diff --git a/pkg/compiler/syscall.go b/pkg/compiler/syscall.go index 910847a94..026cb1b8b 100644 --- a/pkg/compiler/syscall.go +++ b/pkg/compiler/syscall.go @@ -35,6 +35,7 @@ var syscalls = map[string]map[string]Syscall{ "ECDSASecp256k1CheckMultisig": {"Neo.Crypto.CheckMultisigWithECDsaSecp256k1", false}, "ECDsaSecp256r1Verify": {"Neo.Crypto.VerifyWithECDsaSecp256r1", false}, "ECDSASecp256r1CheckMultisig": {"Neo.Crypto.CheckMultisigWithECDsaSecp256r1", false}, + "RIPEMD160": {"Neo.Crypto.RIPEMD160", false}, }, "enumerator": { "Concat": {"System.Enumerator.Concat", false}, diff --git a/pkg/core/interop/crypto/hash.go b/pkg/core/interop/crypto/hash.go index 836d7d693..30936706f 100644 --- a/pkg/core/interop/crypto/hash.go +++ b/pkg/core/interop/crypto/hash.go @@ -13,3 +13,11 @@ func Sha256(ic *interop.Context, v *vm.VM) error { v.Estack().PushVal(h) return nil } + +// RipeMD160 returns RipeMD160 hash of the data. +func RipeMD160(ic *interop.Context, v *vm.VM) error { + msg := getMessage(ic, v.Estack().Pop().Item()) + h := hash.RipeMD160(msg).BytesBE() + v.Estack().PushVal(h) + return nil +} diff --git a/pkg/core/interop/crypto/hash_test.go b/pkg/core/interop/crypto/hash_test.go index 479eb1742..566bcfb6e 100644 --- a/pkg/core/interop/crypto/hash_test.go +++ b/pkg/core/interop/crypto/hash_test.go @@ -28,3 +28,19 @@ func TestSHA256(t *testing.T) { assert.Equal(t, 1, v.Estack().Len()) assert.Equal(t, res, hex.EncodeToString(v.Estack().Pop().Bytes())) } + +func TestRIPEMD160(t *testing.T) { + // 0x0100 hashes to 213492c0c6fc5d61497cf17249dd31cd9964b8a3 + res := "213492c0c6fc5d61497cf17249dd31cd9964b8a3" + buf := io.NewBufBinWriter() + emit.Bytes(buf.BinWriter, []byte{1, 0}) + emit.Syscall(buf.BinWriter, "Neo.Crypto.RIPEMD160") + prog := buf.Bytes() + v := vm.New() + ic := &interop.Context{Trigger: trigger.Verification} + v.RegisterInteropGetter(GetInterop(ic)) + v.Load(prog) + require.NoError(t, v.Run()) + assert.Equal(t, 1, v.Estack().Len()) + assert.Equal(t, res, hex.EncodeToString(v.Estack().Pop().Bytes())) +} diff --git a/pkg/core/interop/crypto/interop.go b/pkg/core/interop/crypto/interop.go index 77dc58479..aff3410d4 100644 --- a/pkg/core/interop/crypto/interop.go +++ b/pkg/core/interop/crypto/interop.go @@ -10,6 +10,7 @@ var ( ecdsaSecp256r1VerifyID = emit.InteropNameToID([]byte("Neo.Crypto.VerifyWithECDsaSecp256r1")) ecdsaSecp256r1CheckMultisigID = emit.InteropNameToID([]byte("Neo.Crypto.CheckMultisigWithECDsaSecp256r1")) sha256ID = emit.InteropNameToID([]byte("Neo.Crypto.SHA256")) + ripemd160ID = emit.InteropNameToID([]byte("Neo.Crypto.RIPEMD160")) ) // GetInterop returns interop getter for crypto-related stuff. @@ -34,6 +35,12 @@ func GetInterop(ic *interop.Context) func(uint32) *vm.InteropFuncPrice { return Sha256(ic, v) }, } + case ripemd160ID: + return &vm.InteropFuncPrice{ + Func: func(v *vm.VM) error { + return RipeMD160(ic, v) + }, + } default: return nil } diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 750713ce5..f7e7f1cb6 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -147,6 +147,7 @@ var neoInterops = []interop.Function{ {Name: "Neo.Crypto.CheckMultisigWithECDsaSecp256r1", Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0}, {Name: "Neo.Crypto.CheckMultisigWithECDsaSecp256k1", Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0}, {Name: "Neo.Crypto.SHA256", Func: crypto.Sha256, Price: 1000000}, + {Name: "Neo.Crypto.RIPEMD160", Func: crypto.RipeMD160, Price: 1000000}, {Name: "Neo.Native.Deploy", Func: native.Deploy, Price: 0, AllowedTriggers: trigger.Application, RequiredFlags: smartcontract.AllowModifyStates}, } diff --git a/pkg/interop/crypto/crypto.go b/pkg/interop/crypto/crypto.go index 6e894465b..4f986f128 100644 --- a/pkg/interop/crypto/crypto.go +++ b/pkg/interop/crypto/crypto.go @@ -8,6 +8,11 @@ func SHA256(b []byte) []byte { return nil } +// RIPEMD160 computes RIPEMD160 hash of b. It uses `Neo.Crypto.RIPEMD160` syscall. +func RIPEMD160(b []byte) []byte { + return nil +} + // ECDsaSecp256r1Verify checks that sig is correct msg's signature for a given pub // (serialized public key). It uses `Neo.Crypto.VerifyWithECDsaSecp256r1` syscall. func ECDsaSecp256r1Verify(msg []byte, pub []byte, sig []byte) bool {