mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-27 03:58:06 +00:00
vm: remove CHECKSIG/VERIFY/CHECKMULTISIG opcodes
This commit is contained in:
parent
4740d937aa
commit
cde4ccf01c
4 changed files with 110 additions and 350 deletions
|
@ -29,29 +29,6 @@ func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) util.Fixed8 {
|
||||||
return toFixed8(10)
|
return toFixed8(10)
|
||||||
case opcode.HASH160, opcode.HASH256:
|
case opcode.HASH160, opcode.HASH256:
|
||||||
return toFixed8(20)
|
return toFixed8(20)
|
||||||
case opcode.CHECKSIG, opcode.VERIFY:
|
|
||||||
return toFixed8(100)
|
|
||||||
case opcode.CHECKMULTISIG:
|
|
||||||
estack := v.Estack()
|
|
||||||
if estack.Len() == 0 {
|
|
||||||
return toFixed8(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var cost int
|
|
||||||
|
|
||||||
item := estack.Peek(0)
|
|
||||||
switch item.Item().(type) {
|
|
||||||
case *vm.ArrayItem, *vm.StructItem:
|
|
||||||
cost = len(item.Array())
|
|
||||||
default:
|
|
||||||
cost = int(item.BigInt().Int64())
|
|
||||||
}
|
|
||||||
|
|
||||||
if cost < 1 {
|
|
||||||
return toFixed8(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return toFixed8(int64(100 * cost))
|
|
||||||
default:
|
default:
|
||||||
return toFixed8(1)
|
return toFixed8(1)
|
||||||
}
|
}
|
||||||
|
|
110
pkg/core/interop/crypto/ecdsa_test.go
Normal file
110
pkg/core/interop/crypto/ecdsa_test.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initCHECKMULTISIG(msg []byte, n int) ([]vm.StackItem, []vm.StackItem, map[string]*keys.PublicKey, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
keyMap := make(map[string]*keys.PublicKey)
|
||||||
|
pkeys := make([]*keys.PrivateKey, n)
|
||||||
|
pubs := make([]vm.StackItem, n)
|
||||||
|
for i := range pubs {
|
||||||
|
pkeys[i], err = keys.NewPrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pk := pkeys[i].PublicKey()
|
||||||
|
data := pk.Bytes()
|
||||||
|
pubs[i] = vm.NewByteArrayItem(data)
|
||||||
|
keyMap[string(data)] = pk
|
||||||
|
}
|
||||||
|
|
||||||
|
sigs := make([]vm.StackItem, n)
|
||||||
|
for i := range sigs {
|
||||||
|
sig := pkeys[i].Sign(msg)
|
||||||
|
sigs[i] = vm.NewByteArrayItem(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pubs, sigs, keyMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func subSlice(arr []vm.StackItem, indices []int) []vm.StackItem {
|
||||||
|
if indices == nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]vm.StackItem, len(indices))
|
||||||
|
for i, j := range indices {
|
||||||
|
result[i] = arr[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func initCHECKMULTISIGVM(t *testing.T, n int, ik, is []int) *vm.VM {
|
||||||
|
buf := make([]byte, 5)
|
||||||
|
buf[0] = byte(opcode.SYSCALL)
|
||||||
|
binary.LittleEndian.PutUint32(buf[1:], ecdsaCheckMultisigID)
|
||||||
|
|
||||||
|
v := vm.New()
|
||||||
|
ic := &interop.Context{Trigger: trigger.Verification}
|
||||||
|
v.RegisterInteropGetter(GetInterop(ic))
|
||||||
|
v.LoadScript(buf)
|
||||||
|
msg := []byte("NEO - An Open Network For Smart Economy")
|
||||||
|
|
||||||
|
pubs, sigs, _, err := initCHECKMULTISIG(msg, n)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
pubs = subSlice(pubs, ik)
|
||||||
|
sigs = subSlice(sigs, is)
|
||||||
|
|
||||||
|
v.Estack().PushVal(sigs)
|
||||||
|
v.Estack().PushVal(pubs)
|
||||||
|
v.Estack().PushVal(msg)
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCHECKMULTISIGGood(t *testing.T, n int, is []int) {
|
||||||
|
v := initCHECKMULTISIGVM(t, n, nil, is)
|
||||||
|
|
||||||
|
require.NoError(t, v.Run())
|
||||||
|
assert.Equal(t, 1, v.Estack().Len())
|
||||||
|
assert.True(t, v.Estack().Pop().Bool())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCHECKMULTISIGGood(t *testing.T) {
|
||||||
|
t.Run("3_1", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{1}) })
|
||||||
|
t.Run("2_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 2, []int{0, 1}) })
|
||||||
|
t.Run("3_3", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{0, 1, 2}) })
|
||||||
|
t.Run("3_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{0, 2}) })
|
||||||
|
t.Run("4_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 4, []int{0, 2}) })
|
||||||
|
t.Run("10_7", func(t *testing.T) { testCHECKMULTISIGGood(t, 10, []int{2, 3, 4, 5, 6, 8, 9}) })
|
||||||
|
t.Run("12_9", func(t *testing.T) { testCHECKMULTISIGGood(t, 12, []int{0, 1, 4, 5, 6, 7, 8, 9}) })
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCHECKMULTISIGBad(t *testing.T, n int, ik, is []int) {
|
||||||
|
v := initCHECKMULTISIGVM(t, n, ik, is)
|
||||||
|
|
||||||
|
require.NoError(t, v.Run())
|
||||||
|
assert.Equal(t, 1, v.Estack().Len())
|
||||||
|
assert.False(t, v.Estack().Pop().Bool())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCHECKMULTISIGBad(t *testing.T) {
|
||||||
|
t.Run("1_1 wrong signature", func(t *testing.T) { testCHECKMULTISIGBad(t, 2, []int{0}, []int{1}) })
|
||||||
|
t.Run("3_2 wrong order", func(t *testing.T) { testCHECKMULTISIGBad(t, 3, []int{0, 2}, []int{2, 0}) })
|
||||||
|
t.Run("3_2 duplicate sig", func(t *testing.T) { testCHECKMULTISIGBad(t, 3, nil, []int{0, 0}) })
|
||||||
|
}
|
39
pkg/vm/vm.go
39
pkg/vm/vm.go
|
@ -1196,45 +1196,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
v.astack = v.Context().astack
|
v.astack = v.Context().astack
|
||||||
}
|
}
|
||||||
|
|
||||||
case opcode.CHECKSIG, opcode.VERIFY:
|
|
||||||
var hashToCheck []byte
|
|
||||||
|
|
||||||
keyb := v.estack.Pop().Bytes()
|
|
||||||
signature := v.estack.Pop().Bytes()
|
|
||||||
if op == opcode.CHECKSIG {
|
|
||||||
if v.checkhash == nil {
|
|
||||||
panic("VM is not set up properly for signature checks")
|
|
||||||
}
|
|
||||||
hashToCheck = v.checkhash
|
|
||||||
} else { // VERIFY
|
|
||||||
msg := v.estack.Pop().Bytes()
|
|
||||||
hashToCheck = hash.Sha256(msg).BytesBE()
|
|
||||||
}
|
|
||||||
pkey := v.bytesToPublicKey(keyb)
|
|
||||||
res := pkey.Verify(signature, hashToCheck)
|
|
||||||
v.estack.PushVal(res)
|
|
||||||
|
|
||||||
case opcode.CHECKMULTISIG:
|
|
||||||
pkeys, err := v.estack.PopSigElements()
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
|
||||||
}
|
|
||||||
sigs, err := v.estack.PopSigElements()
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
|
||||||
}
|
|
||||||
// It's ok to have more keys than there are signatures (it would
|
|
||||||
// just mean that some keys didn't sign), but not the other way around.
|
|
||||||
if len(pkeys) < len(sigs) {
|
|
||||||
panic("more signatures than there are keys")
|
|
||||||
}
|
|
||||||
if v.checkhash == nil {
|
|
||||||
panic("VM is not set up properly for signature checks")
|
|
||||||
}
|
|
||||||
|
|
||||||
sigok := CheckMultisigPar(v, v.checkhash, pkeys, sigs)
|
|
||||||
v.estack.PushVal(sigok)
|
|
||||||
|
|
||||||
case opcode.NEWMAP:
|
case opcode.NEWMAP:
|
||||||
v.estack.Push(&Element{value: NewMapItem()})
|
v.estack.Push(&Element{value: NewMapItem()})
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
|
@ -2603,292 +2601,6 @@ func TestREMOVEMap(t *testing.T) {
|
||||||
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCHECKSIGNoArgs(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKSIG)
|
|
||||||
vm := load(prog)
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKSIGOneArg(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKSIG)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKSIGNoSigLoaded(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKSIG)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := "NEO - An Open Network For Smart Economy"
|
|
||||||
sig := pk.Sign([]byte(msg))
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.estack.PushVal(sig)
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKSIGBadKey(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKSIG)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig := pk.Sign(msg)
|
|
||||||
pbytes := pk.PublicKey().Bytes()[:4]
|
|
||||||
vm := load(prog)
|
|
||||||
vm.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
vm.estack.PushVal(sig)
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKSIGWrongSig(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKSIG)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig := pk.Sign(msg)
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
vm.estack.PushVal(util.ArrayReverse(sig))
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, false, vm.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKSIGGood(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKSIG)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig := pk.Sign(msg)
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
vm.estack.PushVal(sig)
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, true, vm.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVERIFYGood(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.VERIFY)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig := pk.Sign(msg)
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.estack.PushVal(msg)
|
|
||||||
vm.estack.PushVal(sig)
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, true, vm.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVERIFYBad(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.VERIFY)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig := pk.Sign(msg)
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.estack.PushVal(util.ArrayReverse(msg))
|
|
||||||
vm.estack.PushVal(sig)
|
|
||||||
vm.estack.PushVal(pbytes)
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, false, vm.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGNoArgs(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
vm := load(prog)
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGOneArg(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
pk, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
vm := load(prog)
|
|
||||||
pbytes := pk.PublicKey().Bytes()
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(pbytes)})
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGNotEnoughKeys(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
pk1, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
pk2, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig1 := pk1.Sign(msg)
|
|
||||||
sig2 := pk2.Sign(msg)
|
|
||||||
pbytes1 := pk1.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(sig1), NewByteArrayItem(sig2)})
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(pbytes1)})
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGNoHash(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
pk1, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
pk2, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig1 := pk1.Sign(msg)
|
|
||||||
sig2 := pk2.Sign(msg)
|
|
||||||
pbytes1 := pk1.PublicKey().Bytes()
|
|
||||||
pbytes2 := pk2.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(sig1), NewByteArrayItem(sig2)})
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(pbytes1), NewByteArrayItem(pbytes2)})
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGBadKey(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
pk1, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
pk2, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig1 := pk1.Sign(msg)
|
|
||||||
sig2 := pk2.Sign(msg)
|
|
||||||
pbytes1 := pk1.PublicKey().Bytes()
|
|
||||||
pbytes2 := pk2.PublicKey().Bytes()[:4]
|
|
||||||
vm := load(prog)
|
|
||||||
vm.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(sig1), NewByteArrayItem(sig2)})
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(pbytes1), NewByteArrayItem(pbytes2)})
|
|
||||||
checkVMFailed(t, vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGBadSig(t *testing.T) {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
pk1, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
pk2, err := keys.NewPrivateKey()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
sig1 := pk1.Sign(msg)
|
|
||||||
sig2 := pk2.Sign(msg)
|
|
||||||
pbytes1 := pk1.PublicKey().Bytes()
|
|
||||||
pbytes2 := pk2.PublicKey().Bytes()
|
|
||||||
vm := load(prog)
|
|
||||||
vm.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(util.ArrayReverse(sig1)), NewByteArrayItem(sig2)})
|
|
||||||
vm.estack.PushVal([]StackItem{NewByteArrayItem(pbytes1), NewByteArrayItem(pbytes2)})
|
|
||||||
runVM(t, vm)
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
assert.Equal(t, false, vm.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func initCHECKMULTISIG(msg []byte, n int) ([]StackItem, []StackItem, map[string]*keys.PublicKey, error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
keyMap := make(map[string]*keys.PublicKey)
|
|
||||||
pkeys := make([]*keys.PrivateKey, n)
|
|
||||||
pubs := make([]StackItem, n)
|
|
||||||
for i := range pubs {
|
|
||||||
pkeys[i], err = keys.NewPrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pk := pkeys[i].PublicKey()
|
|
||||||
data := pk.Bytes()
|
|
||||||
pubs[i] = NewByteArrayItem(data)
|
|
||||||
keyMap[string(data)] = pk
|
|
||||||
}
|
|
||||||
|
|
||||||
sigs := make([]StackItem, n)
|
|
||||||
for i := range sigs {
|
|
||||||
sig := pkeys[i].Sign(msg)
|
|
||||||
sigs[i] = NewByteArrayItem(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pubs, sigs, keyMap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func subSlice(arr []StackItem, indices []int) []StackItem {
|
|
||||||
if indices == nil {
|
|
||||||
return arr
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]StackItem, len(indices))
|
|
||||||
for i, j := range indices {
|
|
||||||
result[i] = arr[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func initCHECKMULTISIGVM(t *testing.T, n int, ik, is []int) *VM {
|
|
||||||
prog := makeProgram(opcode.CHECKMULTISIG)
|
|
||||||
v := load(prog)
|
|
||||||
msg := []byte("NEO - An Open Network For Smart Economy")
|
|
||||||
|
|
||||||
v.SetCheckedHash(hash.Sha256(msg).BytesBE())
|
|
||||||
|
|
||||||
pubs, sigs, _, err := initCHECKMULTISIG(msg, n)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
pubs = subSlice(pubs, ik)
|
|
||||||
sigs = subSlice(sigs, is)
|
|
||||||
|
|
||||||
v.estack.PushVal(sigs)
|
|
||||||
v.estack.PushVal(pubs)
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCHECKMULTISIGGood(t *testing.T, n int, is []int) {
|
|
||||||
v := initCHECKMULTISIGVM(t, n, nil, is)
|
|
||||||
|
|
||||||
runVM(t, v)
|
|
||||||
assert.Equal(t, 1, v.estack.Len())
|
|
||||||
assert.True(t, v.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGGood(t *testing.T) {
|
|
||||||
t.Run("3_1", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{1}) })
|
|
||||||
t.Run("2_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 2, []int{0, 1}) })
|
|
||||||
t.Run("3_3", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{0, 1, 2}) })
|
|
||||||
t.Run("3_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 3, []int{0, 2}) })
|
|
||||||
t.Run("4_2", func(t *testing.T) { testCHECKMULTISIGGood(t, 4, []int{0, 2}) })
|
|
||||||
t.Run("10_7", func(t *testing.T) { testCHECKMULTISIGGood(t, 10, []int{2, 3, 4, 5, 6, 8, 9}) })
|
|
||||||
t.Run("12_9", func(t *testing.T) { testCHECKMULTISIGGood(t, 12, []int{0, 1, 4, 5, 6, 7, 8, 9}) })
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCHECKMULTISIGBad(t *testing.T, n int, ik, is []int) {
|
|
||||||
v := initCHECKMULTISIGVM(t, n, ik, is)
|
|
||||||
|
|
||||||
runVM(t, v)
|
|
||||||
assert.Equal(t, 1, v.estack.Len())
|
|
||||||
assert.False(t, v.estack.Pop().Bool())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCHECKMULTISIGBad(t *testing.T) {
|
|
||||||
t.Run("1_1 wrong signature", func(t *testing.T) { testCHECKMULTISIGBad(t, 2, []int{0}, []int{1}) })
|
|
||||||
t.Run("3_2 wrong order", func(t *testing.T) { testCHECKMULTISIGBad(t, 3, []int{0, 2}, []int{2, 0}) })
|
|
||||||
t.Run("3_2 duplicate sig", func(t *testing.T) { testCHECKMULTISIGBad(t, 3, nil, []int{0, 0}) })
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSWAPGood(t *testing.T) {
|
func TestSWAPGood(t *testing.T) {
|
||||||
prog := makeProgram(opcode.SWAP)
|
prog := makeProgram(opcode.SWAP)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
|
Loading…
Reference in a new issue