core: implement Neo.Crypto.ECDsaVerify interop
This commit is contained in:
parent
1611ede58c
commit
5a30af2c75
3 changed files with 96 additions and 0 deletions
31
pkg/core/interop/crypto/ecdsa.go
Normal file
31
pkg/core/interop/crypto/ecdsa.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ECDSAVerify checks ECDSA signature.
|
||||||
|
func ECDSAVerify(ic *interop.Context, v *vm.VM) error {
|
||||||
|
msg := getMessage(ic, v.Estack().Pop().Item())
|
||||||
|
hashToCheck := hash.Sha256(msg).BytesBE()
|
||||||
|
keyb := v.Estack().Pop().Bytes()
|
||||||
|
signature := v.Estack().Pop().Bytes()
|
||||||
|
pkey, err := keys.NewPublicKeyFromBytes(keyb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res := pkey.Verify(signature, hashToCheck)
|
||||||
|
v.Estack().PushVal(res)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMessage(_ *interop.Context, item vm.StackItem) []byte {
|
||||||
|
msg, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
||||||
"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/core/interop/crypto"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
@ -231,6 +233,67 @@ func TestWitnessGetVerificationScript(t *testing.T) {
|
||||||
require.Equal(t, witness.VerificationScript, value)
|
require.Equal(t, witness.VerificationScript, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestECDSAVerify(t *testing.T) {
|
||||||
|
priv, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
chain := newTestChain(t)
|
||||||
|
defer chain.Close()
|
||||||
|
|
||||||
|
ic := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), nil, nil)
|
||||||
|
runCase := func(t *testing.T, isErr bool, result interface{}, args ...interface{}) {
|
||||||
|
v := vm.New()
|
||||||
|
for i := range args {
|
||||||
|
v.Estack().PushVal(args[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = fmt.Errorf("panic: %v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err = crypto.ECDSAVerify(ic, v)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if isErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, v.Estack().Len())
|
||||||
|
require.Equal(t, result, v.Estack().Pop().Value().(bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []byte("test message")
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
runCase(t, false, true, sign, priv.PublicKey().Bytes(), msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("missing arguments", func(t *testing.T) {
|
||||||
|
runCase(t, true, false)
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
runCase(t, true, false, sign)
|
||||||
|
runCase(t, true, false, sign, priv.PublicKey().Bytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid signature", func(t *testing.T) {
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
sign[0] ^= sign[0]
|
||||||
|
runCase(t, false, false, sign, priv.PublicKey().Bytes(), msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid public key", func(t *testing.T) {
|
||||||
|
sign := priv.Sign(msg)
|
||||||
|
pub := priv.PublicKey().Bytes()
|
||||||
|
pub = pub[10:]
|
||||||
|
runCase(t, true, false, sign, pub, msg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestPopInputFromVM(t *testing.T) {
|
func TestPopInputFromVM(t *testing.T) {
|
||||||
v, tx, _, chain := createVMAndTX(t)
|
v, tx, _, chain := createVMAndTX(t)
|
||||||
defer chain.Close()
|
defer chain.Close()
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"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/core/interop/crypto"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/enumerator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/iterator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -137,6 +138,7 @@ var neoInterops = []interop.Function{
|
||||||
{Name: "Neo.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1},
|
{Name: "Neo.Contract.GetStorageContext", Func: contractGetStorageContext, Price: 1},
|
||||||
{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.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},
|
||||||
|
|
Loading…
Reference in a new issue