forked from TrueCloudLab/neoneo-go
core: implement Neo.Crypto.ECDsaCheckMultisig interop
This commit is contained in:
parent
5a30af2c75
commit
c23af595c9
5 changed files with 41 additions and 13 deletions
|
@ -1,6 +1,9 @@
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"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/crypto/keys"
|
||||||
|
@ -22,6 +25,29 @@ func ECDSAVerify(ic *interop.Context, v *vm.VM) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ECDSACheckMultisig checks multiple ECDSA signatures at once.
|
||||||
|
func ECDSACheckMultisig(ic *interop.Context, v *vm.VM) error {
|
||||||
|
msg := getMessage(ic, v.Estack().Pop().Item())
|
||||||
|
hashToCheck := hash.Sha256(msg).BytesBE()
|
||||||
|
pkeys, err := v.Estack().PopSigElements()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("wrong parameters: %s", err.Error())
|
||||||
|
}
|
||||||
|
sigs, err := v.Estack().PopSigElements()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("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) {
|
||||||
|
return errors.New("more signatures than there are keys")
|
||||||
|
}
|
||||||
|
v.SetCheckedHash(hashToCheck)
|
||||||
|
sigok := vm.CheckMultisigPar(v, pkeys, sigs)
|
||||||
|
v.Estack().PushVal(sigok)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getMessage(_ *interop.Context, item vm.StackItem) []byte {
|
func getMessage(_ *interop.Context, item vm.StackItem) []byte {
|
||||||
msg, err := item.TryBytes()
|
msg, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -139,6 +139,7 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "Neo.Contract.IsPayable", Func: contractIsPayable, Price: 1},
|
{Name: "Neo.Contract.IsPayable", Func: contractIsPayable, Price: 1},
|
||||||
{Name: "Neo.Contract.Migrate", Func: contractMigrate, Price: 0},
|
{Name: "Neo.Contract.Migrate", Func: contractMigrate, Price: 0},
|
||||||
{Name: "Neo.Crypto.ECDsaVerify", Func: crypto.ECDSAVerify, Price: 1},
|
{Name: "Neo.Crypto.ECDsaVerify", Func: crypto.ECDSAVerify, Price: 1},
|
||||||
|
{Name: "Neo.Crypto.ECDsaCheckMultiSig", Func: crypto.ECDSACheckMultisig, Price: 1},
|
||||||
{Name: "Neo.Enumerator.Concat", Func: enumerator.Concat, Price: 1},
|
{Name: "Neo.Enumerator.Concat", Func: enumerator.Concat, Price: 1},
|
||||||
{Name: "Neo.Enumerator.Create", Func: enumerator.Create, Price: 1},
|
{Name: "Neo.Enumerator.Create", Func: enumerator.Create, Price: 1},
|
||||||
{Name: "Neo.Enumerator.Next", Func: enumerator.Next, Price: 1},
|
{Name: "Neo.Enumerator.Next", Func: enumerator.Next, Price: 1},
|
||||||
|
|
|
@ -424,9 +424,9 @@ func (s *Stack) Roll(n int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// popSigElements pops keys or signatures from the stack as needed for
|
// PopSigElements pops keys or signatures from the stack as needed for
|
||||||
// CHECKMULTISIG.
|
// CHECKMULTISIG.
|
||||||
func (s *Stack) popSigElements() ([][]byte, error) {
|
func (s *Stack) PopSigElements() ([][]byte, error) {
|
||||||
var num int
|
var num int
|
||||||
var elems [][]byte
|
var elems [][]byte
|
||||||
item := s.Pop()
|
item := s.Pop()
|
||||||
|
|
|
@ -317,37 +317,37 @@ func TestRoll(t *testing.T) {
|
||||||
func TestPopSigElements(t *testing.T) {
|
func TestPopSigElements(t *testing.T) {
|
||||||
s := NewStack("test")
|
s := NewStack("test")
|
||||||
|
|
||||||
_, err := s.popSigElements()
|
_, err := s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal([]StackItem{})
|
s.PushVal([]StackItem{})
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal([]StackItem{NewBoolItem(false)})
|
s.PushVal([]StackItem{NewBoolItem(false)})
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
b1 := []byte("smth")
|
b1 := []byte("smth")
|
||||||
b2 := []byte("strange")
|
b2 := []byte("strange")
|
||||||
s.PushVal([]StackItem{NewByteArrayItem(b1), NewByteArrayItem(b2)})
|
s.PushVal([]StackItem{NewByteArrayItem(b1), NewByteArrayItem(b2)})
|
||||||
z, err := s.popSigElements()
|
z, err := s.PopSigElements()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, z, [][]byte{b1, b2})
|
assert.Equal(t, z, [][]byte{b1, b2})
|
||||||
|
|
||||||
s.PushVal(2)
|
s.PushVal(2)
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal(b1)
|
s.PushVal(b1)
|
||||||
s.PushVal(2)
|
s.PushVal(2)
|
||||||
_, err = s.popSigElements()
|
_, err = s.PopSigElements()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
s.PushVal(b2)
|
s.PushVal(b2)
|
||||||
s.PushVal(b1)
|
s.PushVal(b1)
|
||||||
s.PushVal(2)
|
s.PushVal(2)
|
||||||
z, err = s.popSigElements()
|
z, err = s.PopSigElements()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, z, [][]byte{b1, b2})
|
assert.Equal(t, z, [][]byte{b1, b2})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1235,11 +1235,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
v.estack.PushVal(res)
|
v.estack.PushVal(res)
|
||||||
|
|
||||||
case opcode.CHECKMULTISIG:
|
case opcode.CHECKMULTISIG:
|
||||||
pkeys, err := v.estack.popSigElements()
|
pkeys, err := v.estack.PopSigElements()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
||||||
}
|
}
|
||||||
sigs, err := v.estack.popSigElements()
|
sigs, err := v.estack.PopSigElements()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
@ -1252,7 +1252,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
panic("VM is not set up properly for signature checks")
|
panic("VM is not set up properly for signature checks")
|
||||||
}
|
}
|
||||||
|
|
||||||
sigok := checkMultisigPar(v, pkeys, sigs)
|
sigok := CheckMultisigPar(v, pkeys, sigs)
|
||||||
v.estack.PushVal(sigok)
|
v.estack.PushVal(sigok)
|
||||||
|
|
||||||
case opcode.NEWMAP:
|
case opcode.NEWMAP:
|
||||||
|
@ -1446,7 +1446,8 @@ func (v *VM) getJumpOffset(ctx *Context, parameter []byte, mod int) int {
|
||||||
return offset
|
return offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMultisigPar(v *VM, pkeys [][]byte, sigs [][]byte) bool {
|
// CheckMultisigPar checks if sigs contains sufficient valid signatures.
|
||||||
|
func CheckMultisigPar(v *VM, pkeys [][]byte, sigs [][]byte) bool {
|
||||||
if len(sigs) == 1 {
|
if len(sigs) == 1 {
|
||||||
return checkMultisig1(v, pkeys, sigs[0])
|
return checkMultisig1(v, pkeys, sigs[0])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue