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.
This commit is contained in:
Evgenii Stratonikov 2020-04-28 16:37:42 +03:00
parent c1aa96d614
commit 519b31a704
13 changed files with 90 additions and 110 deletions

View file

@ -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",

View file

@ -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)

View file

@ -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())
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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()))
}

View file

@ -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
}

View file

@ -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},

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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 ^^

View file

@ -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{}