core: add murmur32 to CryptoLib native contract

Close #2415.
This commit is contained in:
Anna Shaleva 2022-04-04 16:43:15 +03:00
parent 0e8bf83dda
commit 16f952270c
3 changed files with 47 additions and 0 deletions

View file

@ -2,6 +2,7 @@ package native
import (
"crypto/elliptic"
"encoding/binary"
"errors"
"fmt"
@ -14,6 +15,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/twmb/murmur3"
)
// Crypto represents CryptoLib contract.
@ -46,6 +48,12 @@ func newCrypto() *Crypto {
md = newMethodAndPrice(c.ripemd160, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc)
desc = newDescriptor("murmur32", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType),
manifest.NewParameter("seed", smartcontract.IntegerType))
md = newMethodAndPrice(c.murmur32, 1<<13, callflag.NoneFlag)
c.AddMethod(md, desc)
desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType,
manifest.NewParameter("message", smartcontract.ByteArrayType),
manifest.NewParameter("pubkey", smartcontract.ByteArrayType),
@ -72,6 +80,18 @@ func (c *Crypto) ripemd160(_ *interop.Context, args []stackitem.Item) stackitem.
return stackitem.NewByteArray(hash.RipeMD160(bs).BytesBE())
}
func (c *Crypto) murmur32(_ *interop.Context, args []stackitem.Item) stackitem.Item {
bs, err := args[0].TryBytes()
if err != nil {
panic(err)
}
seed := toUint32(args[1])
h := murmur3.SeedSum32(seed, bs)
result := make([]byte, 4)
binary.LittleEndian.PutUint32(result, h)
return stackitem.NewByteArray(result)
}
func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stackitem.Item {
msg, err := args[0].TryBytes()
if err != nil {

View file

@ -1,6 +1,7 @@
package native
import (
"encoding/binary"
"encoding/hex"
"math"
"math/big"
@ -43,6 +44,26 @@ func TestRIPEMD160(t *testing.T) {
})
}
func TestMurmur32(t *testing.T) {
c := newCrypto()
ic := &interop.Context{VM: vm.New()}
t.Run("bad arg type", func(t *testing.T) {
require.Panics(t, func() {
c.murmur32(ic, []stackitem.Item{stackitem.NewInterop(nil), stackitem.Make(5)})
})
})
t.Run("good", func(t *testing.T) {
// Example from the C# node:
// https://github.com/neo-project/neo/blob/2a64c1cc809d1ff4b3a573c7c22bffbbf69a738b/tests/neo.UnitTests/Cryptography/UT_Murmur32.cs#L18
data := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1}
seed := 10
expected := make([]byte, 4)
binary.LittleEndian.PutUint32(expected, 378574820)
require.Equal(t, expected, c.murmur32(ic, []stackitem.Item{stackitem.NewByteArray(data), stackitem.Make(seed)}).Value().([]byte))
})
}
func TestCryptoLibVerifyWithECDsa(t *testing.T) {
t.Run("R1", func(t *testing.T) {
testECDSAVerify(t, Secp256r1)

View file

@ -32,6 +32,12 @@ func Ripemd160(b []byte) interop.Hash160 {
return neogointernal.CallWithToken(Hash, "ripemd160", int(contract.NoneFlag), b).(interop.Hash160)
}
// Murmur32 calls `murmur32` method of native CryptoLib contract and computes Murmur32 hash of b
// using the given seed.
func Murmur32(b []byte, seed int) []byte {
return neogointernal.CallWithToken(Hash, "murmur32", int(contract.NoneFlag), b, seed).([]byte)
}
// VerifyWithECDsa calls `verifyWithECDsa` method of native CryptoLib contract and checks that sig is
// correct msg's signature for a given pub (serialized public key on a given curve).
func VerifyWithECDsa(msg []byte, pub interop.PublicKey, sig interop.Signature, curve NamedCurve) bool {