From 519b31a70410f45025b2468e05607a248fb0354a Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 28 Apr 2020 16:37:42 +0300 Subject: [PATCH] vm: remove crypto-related opcodes All cryptography has moved to interops in NEO3. There is no SHA256 interop RN, but it is to appear later. Closes #777. --- pkg/compiler/analysis.go | 1 - pkg/compiler/codegen.go | 4 +- pkg/compiler/util_test.go | 27 ++++++------ pkg/core/gas_price.go | 4 -- pkg/core/interop/crypto/hash.go | 15 +++++++ pkg/core/interop/crypto/hash_test.go | 30 ++++++++++++++ pkg/core/interop/crypto/interop.go | 7 ++++ pkg/core/interops.go | 1 + pkg/interop/crypto/crypto.go | 5 --- pkg/vm/opcode/opcode.go | 9 ---- pkg/vm/opcode/opcode_string.go | 62 +++++++++++----------------- pkg/vm/vm.go | 13 ------ pkg/vm/vm_test.go | 22 ---------- 13 files changed, 90 insertions(+), 110 deletions(-) create mode 100644 pkg/core/interop/crypto/hash.go create mode 100644 pkg/core/interop/crypto/hash_test.go diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index 45105b2c3..b075d7032 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -13,7 +13,6 @@ var ( // Go language builtin functions and custom builtin utility functions. builtinFuncs = []string{ "len", "append", "SHA256", - "SHA1", "Hash256", "Hash160", "AppCall", "FromAddress", "Equals", "panic", diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index f2a150daa..3ddcb1ecc 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -1065,9 +1065,7 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { } emit.Instruction(c.prog.BinWriter, opcode.CONVERT, []byte{byte(typ)}) case "SHA256": - emit.Opcode(c.prog.BinWriter, opcode.SHA256) - case "SHA1": - emit.Opcode(c.prog.BinWriter, opcode.SHA1) + emit.Syscall(c.prog.BinWriter, "Neo.Crypto.SHA256") case "AppCall": numArgs := len(expr.Args) - 1 c.emitReverse(numArgs) diff --git a/pkg/compiler/util_test.go b/pkg/compiler/util_test.go index 1f82c73f4..59a628642 100644 --- a/pkg/compiler/util_test.go +++ b/pkg/compiler/util_test.go @@ -2,6 +2,11 @@ package compiler_test import ( "testing" + + "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/smartcontract/trigger" + "github.com/stretchr/testify/require" ) func TestSHA256(t *testing.T) { @@ -16,20 +21,12 @@ func TestSHA256(t *testing.T) { return hash } ` - eval(t, src, []byte{0x2a, 0xa, 0xb7, 0x32, 0xb4, 0xe9, 0xd8, 0x5e, 0xf7, 0xdc, 0x25, 0x30, 0x3b, 0x64, 0xab, 0x52, 0x7c, 0x25, 0xa4, 0xd7, 0x78, 0x15, 0xeb, 0xb5, 0x79, 0xf3, 0x96, 0xec, 0x6c, 0xac, 0xca, 0xd3}) -} + v := vmAndCompile(t, src) + ic := &interop.Context{Trigger: trigger.Verification} + v.RegisterInteropGetter(crypto.GetInterop(ic)) + require.NoError(t, v.Run()) + require.True(t, v.Estack().Len() >= 1) -func TestSHA1(t *testing.T) { - src := ` - package foo - import ( - "github.com/nspcc-dev/neo-go/pkg/interop/crypto" - ) - func Main() []byte { - src := []byte{0x97} - hash := crypto.SHA1(src) - return hash - } - ` - eval(t, src, []byte{0xfa, 0x13, 0x8a, 0xe3, 0x56, 0xd3, 0x5c, 0x8d, 0x77, 0x8, 0x3c, 0x40, 0x6a, 0x5b, 0xe7, 0x37, 0x45, 0x64, 0x3a, 0xae}) + h := []byte{0x2a, 0xa, 0xb7, 0x32, 0xb4, 0xe9, 0xd8, 0x5e, 0xf7, 0xdc, 0x25, 0x30, 0x3b, 0x64, 0xab, 0x52, 0x7c, 0x25, 0xa4, 0xd7, 0x78, 0x15, 0xeb, 0xb5, 0x79, 0xf3, 0x96, 0xec, 0x6c, 0xac, 0xca, 0xd3} + require.Equal(t, h, v.PopResult()) } diff --git a/pkg/core/gas_price.go b/pkg/core/gas_price.go index c3ec08cc9..a4d281b5d 100644 --- a/pkg/core/gas_price.go +++ b/pkg/core/gas_price.go @@ -25,10 +25,6 @@ func getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) util.Fixed8 { case opcode.SYSCALL: interopID := vm.GetInteropID(parameter) return getSyscallPrice(v, interopID) - case opcode.SHA1, opcode.SHA256: - return toFixed8(10) - case opcode.HASH160, opcode.HASH256: - return toFixed8(20) default: return toFixed8(1) } diff --git a/pkg/core/interop/crypto/hash.go b/pkg/core/interop/crypto/hash.go new file mode 100644 index 000000000..836d7d693 --- /dev/null +++ b/pkg/core/interop/crypto/hash.go @@ -0,0 +1,15 @@ +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/vm" +) + +// Sha256 returns sha256 hash of the data. +func Sha256(ic *interop.Context, v *vm.VM) error { + msg := getMessage(ic, v.Estack().Pop().Item()) + h := hash.Sha256(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 new file mode 100644 index 000000000..479eb1742 --- /dev/null +++ b/pkg/core/interop/crypto/hash_test.go @@ -0,0 +1,30 @@ +package crypto + +import ( + "encoding/hex" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/io" + "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/emit" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSHA256(t *testing.T) { + // 0x0100 hashes to 47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254 + res := "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254" + buf := io.NewBufBinWriter() + emit.Bytes(buf.BinWriter, []byte{1, 0}) + emit.Syscall(buf.BinWriter, "Neo.Crypto.SHA256") + 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 e565b51f5..bf651058a 100644 --- a/pkg/core/interop/crypto/interop.go +++ b/pkg/core/interop/crypto/interop.go @@ -9,6 +9,7 @@ import ( var ( ecdsaVerifyID = emit.InteropNameToID([]byte("Neo.Crypto.ECDsaVerify")) ecdsaCheckMultisigID = emit.InteropNameToID([]byte("Neo.Crypto.ECDsaCheckMultiSig")) + sha256ID = emit.InteropNameToID([]byte("Neo.Crypto.SHA256")) ) // GetInterop returns interop getter for crypto-related stuff. @@ -27,6 +28,12 @@ func GetInterop(ic *interop.Context) func(uint32) *vm.InteropFuncPrice { return ECDSACheckMultisig(ic, v) }, } + case sha256ID: + return &vm.InteropFuncPrice{ + Func: func(v *vm.VM) error { + return Sha256(ic, v) + }, + } default: return nil } diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 93b03d778..03728282a 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -147,6 +147,7 @@ var neoInterops = []interop.Function{ {Name: "Neo.Contract.Migrate", Func: contractMigrate, Price: 0}, {Name: "Neo.Crypto.ECDsaVerify", Func: crypto.ECDSAVerify, Price: 1}, {Name: "Neo.Crypto.ECDsaCheckMultiSig", Func: crypto.ECDSACheckMultisig, Price: 1}, + {Name: "Neo.Crypto.SHA256", Func: crypto.Sha256, Price: 1}, {Name: "Neo.Enumerator.Concat", Func: enumerator.Concat, Price: 1}, {Name: "Neo.Enumerator.Create", Func: enumerator.Create, Price: 1}, {Name: "Neo.Enumerator.Next", Func: enumerator.Next, Price: 1}, diff --git a/pkg/interop/crypto/crypto.go b/pkg/interop/crypto/crypto.go index cce23b916..dfcab6a5d 100644 --- a/pkg/interop/crypto/crypto.go +++ b/pkg/interop/crypto/crypto.go @@ -3,11 +3,6 @@ package crypto // Package crypto provides function signatures that can be used inside // smart contracts that are written in the neo-go framework. -// SHA1 computes the sha1 hash of b. -func SHA1(b []byte) []byte { - return nil -} - // SHA256 computes the sha256 hash of b. func SHA256(b []byte) []byte { return nil diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go index d918e8d87..39fd7b1f5 100644 --- a/pkg/vm/opcode/opcode.go +++ b/pkg/vm/opcode/opcode.go @@ -131,15 +131,6 @@ const ( MAX Opcode = 0xA4 WITHIN Opcode = 0xA5 - // Crypto - SHA1 Opcode = 0xA7 - SHA256 Opcode = 0xA8 - HASH160 Opcode = 0xA9 - HASH256 Opcode = 0xAA - CHECKSIG Opcode = 0xAC - VERIFY Opcode = 0xAD - CHECKMULTISIG Opcode = 0xAE - // Advanced data structures (arrays, structures, maps) PACK Opcode = 0xC0 UNPACK Opcode = 0xC1 diff --git a/pkg/vm/opcode/opcode_string.go b/pkg/vm/opcode/opcode_string.go index 2447a7dca..8a8a66f9c 100644 --- a/pkg/vm/opcode/opcode_string.go +++ b/pkg/vm/opcode/opcode_string.go @@ -114,13 +114,6 @@ func _() { _ = x[MIN-163] _ = x[MAX-164] _ = x[WITHIN-165] - _ = x[SHA1-167] - _ = x[SHA256-168] - _ = x[HASH160-169] - _ = x[HASH256-170] - _ = x[CHECKSIG-172] - _ = x[VERIFY-173] - _ = x[CHECKMULTISIG-174] _ = x[PACK-192] _ = x[UNPACK-193] _ = x[NEWARRAY0-194] @@ -146,7 +139,7 @@ func _() { _ = x[THROWIFNOT-241] } -const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT" +const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLOLDPUSH1RETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERTTHROWTHROWIFNOT" var _Opcode_map = map[Opcode]string{ 0: _Opcode_name[0:8], @@ -253,36 +246,29 @@ var _Opcode_map = map[Opcode]string{ 163: _Opcode_name[548:551], 164: _Opcode_name[551:554], 165: _Opcode_name[554:560], - 167: _Opcode_name[560:564], - 168: _Opcode_name[564:570], - 169: _Opcode_name[570:577], - 170: _Opcode_name[577:584], - 172: _Opcode_name[584:592], - 173: _Opcode_name[592:598], - 174: _Opcode_name[598:611], - 192: _Opcode_name[611:615], - 193: _Opcode_name[615:621], - 194: _Opcode_name[621:630], - 195: _Opcode_name[630:638], - 196: _Opcode_name[638:647], - 197: _Opcode_name[647:657], - 198: _Opcode_name[657:666], - 200: _Opcode_name[666:672], - 202: _Opcode_name[672:676], - 203: _Opcode_name[676:682], - 204: _Opcode_name[682:686], - 205: _Opcode_name[686:692], - 206: _Opcode_name[692:700], - 207: _Opcode_name[700:706], - 208: _Opcode_name[706:713], - 209: _Opcode_name[713:725], - 210: _Opcode_name[725:731], - 211: _Opcode_name[731:741], - 216: _Opcode_name[741:747], - 217: _Opcode_name[747:753], - 219: _Opcode_name[753:760], - 240: _Opcode_name[760:765], - 241: _Opcode_name[765:775], + 192: _Opcode_name[560:564], + 193: _Opcode_name[564:570], + 194: _Opcode_name[570:579], + 195: _Opcode_name[579:587], + 196: _Opcode_name[587:596], + 197: _Opcode_name[596:606], + 198: _Opcode_name[606:615], + 200: _Opcode_name[615:621], + 202: _Opcode_name[621:625], + 203: _Opcode_name[625:631], + 204: _Opcode_name[631:635], + 205: _Opcode_name[635:641], + 206: _Opcode_name[641:649], + 207: _Opcode_name[649:655], + 208: _Opcode_name[655:662], + 209: _Opcode_name[662:674], + 210: _Opcode_name[674:680], + 211: _Opcode_name[680:690], + 216: _Opcode_name[690:696], + 217: _Opcode_name[696:702], + 219: _Opcode_name[702:709], + 240: _Opcode_name[709:714], + 241: _Opcode_name[714:724], } func (i Opcode) String() string { diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index a645ee48c..4793a3dfd 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -1,7 +1,6 @@ package vm import ( - "crypto/sha1" "encoding/binary" "encoding/json" "fmt" @@ -11,7 +10,6 @@ import ( "text/tabwriter" "unicode/utf8" - "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/util" "github.com/nspcc-dev/neo-go/pkg/vm/emit" @@ -1314,17 +1312,6 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro panic("wrong collection type") } - // Cryptographic operations. - case opcode.SHA1: - b := v.estack.Pop().Bytes() - sha := sha1.New() - sha.Write(b) - v.estack.PushVal(sha.Sum(nil)) - - case opcode.SHA256: - b := v.estack.Pop().Bytes() - v.estack.PushVal(hash.Sha256(b).BytesBE()) - case opcode.NOP: // unlucky ^^ diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index 6bba08c69..2774ad9d8 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -3037,28 +3037,6 @@ func TestDupBool(t *testing.T) { assert.Equal(t, true, vm.estack.Pop().Bool()) } -func TestSHA1(t *testing.T) { - // 0x0100 hashes to 0e356ba505631fbf715758bed27d503f8b260e3a - res := "0e356ba505631fbf715758bed27d503f8b260e3a" - prog := makeProgram(opcode.PUSHDATA1, 2, 1, 0, - opcode.SHA1) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, res, hex.EncodeToString(vm.estack.Pop().Bytes())) -} - -func TestSHA256(t *testing.T) { - // 0x0100 hashes to 47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254 - res := "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254" - prog := makeProgram(opcode.PUSHDATA1, 2, 1, 0, - opcode.SHA256) - vm := load(prog) - runVM(t, vm) - assert.Equal(t, 1, vm.estack.Len()) - assert.Equal(t, res, hex.EncodeToString(vm.estack.Pop().Bytes())) -} - var opcodesTestCases = map[opcode.Opcode][]struct { name string args []interface{}