From 100f2db3fb6df23f23f9f3659cb8e74aef1acd6c Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Mon, 15 Feb 2021 18:43:10 +0300 Subject: [PATCH] native: implement CryptoLib contract --- pkg/compiler/native_test.go | 13 +++ pkg/compiler/syscall_test.go | 2 - pkg/compiler/util_test.go | 34 ------ pkg/core/interop/crypto/hash.go | 39 ------- pkg/core/interop/crypto/hash_test.go | 69 ------------- pkg/core/interop/crypto/interop.go | 4 - pkg/core/interop/interopnames/names.go | 4 - pkg/core/interops.go | 2 - pkg/core/native/contract.go | 5 + pkg/core/native/crypto.go | 138 +++++++++++++++++++++++++ pkg/core/native/crypto_test.go | 41 ++++++++ pkg/core/native/designate.go | 2 +- pkg/core/native/ledger.go | 2 +- pkg/core/native/name_service.go | 2 +- pkg/core/native/native_gas.go | 2 +- pkg/core/native/native_neo.go | 2 +- pkg/core/native/nativenames/names.go | 1 + pkg/core/native/oracle.go | 2 +- pkg/core/native/policy.go | 2 +- pkg/interop/crypto/crypto.go | 10 -- pkg/interop/native/crypto/crypto.go | 34 ++++++ pkg/rpc/server/server_test.go | 2 +- 22 files changed, 240 insertions(+), 172 deletions(-) delete mode 100644 pkg/compiler/util_test.go delete mode 100644 pkg/core/interop/crypto/hash.go delete mode 100644 pkg/core/interop/crypto/hash_test.go create mode 100644 pkg/core/native/crypto.go create mode 100644 pkg/core/native/crypto_test.go create mode 100644 pkg/interop/native/crypto/crypto.go diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index 7c194f9b5..9a52c5a97 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/interop/native/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/native/gas" "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" @@ -37,6 +38,7 @@ func TestContractHashes(t *testing.T) { require.Equal(t, []byte(ledger.Hash), cs.Ledger.Hash.BytesBE()) require.Equal(t, []byte(management.Hash), cs.Management.Hash.BytesBE()) require.Equal(t, []byte(notary.Hash), cs.Notary.Hash.BytesBE()) + require.Equal(t, []byte(crypto.Hash), cs.Crypto.Hash.BytesBE()) } // testPrintHash is a helper for updating contract hashes. @@ -77,6 +79,11 @@ func TestNameServiceRecordType(t *testing.T) { require.EqualValues(t, native.RecordTypeAAAA, nameservice.TypeAAAA) } +func TestCryptoLibNamedCurve(t *testing.T) { + require.EqualValues(t, native.Secp256k1, crypto.Secp256k1) + require.EqualValues(t, native.Secp256r1, crypto.Secp256r1) +} + type nativeTestCase struct { method string params []string @@ -88,6 +95,7 @@ func TestNativeHelpersCompile(t *testing.T) { u160 := `interop.Hash160("aaaaaaaaaaaaaaaaaaaa")` u256 := `interop.Hash256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")` pub := `interop.PublicKey("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")` + sig := `interop.Signature("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")` nep17TestCases := []nativeTestCase{ {"balanceOf", []string{u160}}, {"decimals", nil}, @@ -176,6 +184,11 @@ func TestNativeHelpersCompile(t *testing.T) { {"update", []string{"nil", "nil"}}, {"updateWithData", []string{"nil", "nil", "123"}}, }) + runNativeTestCases(t, cs.Crypto.ContractMD, "crypto", []nativeTestCase{ + {"sha256", []string{"[]byte{1, 2, 3}"}}, + {"ripemd160", []string{"[]byte{1, 2, 3}"}}, + {"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1"}}, + }) } func runNativeTestCases(t *testing.T, ctr interop.ContractMD, name string, testCases []nativeTestCase) { diff --git a/pkg/compiler/syscall_test.go b/pkg/compiler/syscall_test.go index ace3adb1b..325b73abd 100644 --- a/pkg/compiler/syscall_test.go +++ b/pkg/compiler/syscall_test.go @@ -103,8 +103,6 @@ func TestSyscallExecution(t *testing.T) { "crypto.ECDsaSecp256k1Verify": {interopnames.NeoCryptoVerifyWithECDsaSecp256k1, []string{b, pub, sig}, false}, "crypto.ECDSASecp256r1CheckMultisig": {interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, []string{b, pubs, sigs}, false}, "crypto.ECDSASecp256k1CheckMultisig": {interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, []string{b, pubs, sigs}, false}, - "crypto.SHA256": {interopnames.NeoCryptoSHA256, []string{b}, false}, - "crypto.RIPEMD160": {interopnames.NeoCryptoRIPEMD160, []string{b}, false}, } ic := &interop.Context{} core.SpawnVM(ic) // set Functions field diff --git a/pkg/compiler/util_test.go b/pkg/compiler/util_test.go deleted file mode 100644 index 67eeb8118..000000000 --- a/pkg/compiler/util_test.go +++ /dev/null @@ -1,34 +0,0 @@ -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) { - src := ` - package foo - import ( - "github.com/nspcc-dev/neo-go/pkg/interop/crypto" - ) - func Main() []byte { - src := []byte{0x97} - hash := crypto.SHA256(src) - return hash - } - ` - v := vmAndCompile(t, src) - ic := &interop.Context{Trigger: trigger.Verification} - ic.VM = v - crypto.Register(ic) - v.SyscallHandler = ic.SyscallHandler - require.NoError(t, v.Run()) - require.True(t, v.Estack().Len() >= 1) - - 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/interop/crypto/hash.go b/pkg/core/interop/crypto/hash.go deleted file mode 100644 index f00efb3a3..000000000 --- a/pkg/core/interop/crypto/hash.go +++ /dev/null @@ -1,39 +0,0 @@ -package crypto - -import ( - "github.com/nspcc-dev/neo-go/pkg/core/interop" - "github.com/nspcc-dev/neo-go/pkg/crypto" - "github.com/nspcc-dev/neo-go/pkg/crypto/hash" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" -) - -// Sha256 returns sha256 hash of the data. -func Sha256(ic *interop.Context) error { - h, err := getMessageHash(ic, ic.VM.Estack().Pop().Item()) - if err != nil { - return err - } - ic.VM.Estack().PushVal(h.BytesBE()) - return nil -} - -// RipeMD160 returns RipeMD160 hash of the data. -func RipeMD160(ic *interop.Context) error { - var msg []byte - - item := ic.VM.Estack().Pop().Item() - switch val := item.(type) { - case *stackitem.Interop: - msg = val.Value().(crypto.Verifiable).GetSignedPart() - case stackitem.Null: - msg = ic.Container.GetSignedPart() - default: - var err error - if msg, err = val.TryBytes(); err != nil { - return err - } - } - h := hash.RipeMD160(msg).BytesBE() - ic.VM.Estack().PushVal(h) - return nil -} diff --git a/pkg/core/interop/crypto/hash_test.go b/pkg/core/interop/crypto/hash_test.go deleted file mode 100644 index 313074d4a..000000000 --- a/pkg/core/interop/crypto/hash_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package crypto - -import ( - "encoding/hex" - "testing" - - "github.com/nspcc-dev/neo-go/pkg/core/interop" - "github.com/nspcc-dev/neo-go/pkg/crypto" - "github.com/nspcc-dev/neo-go/pkg/crypto/hash" - "github.com/nspcc-dev/neo-go/pkg/util" - "github.com/nspcc-dev/neo-go/pkg/vm" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" - "github.com/stretchr/testify/require" -) - -type testVerifiable []byte - -var _ crypto.Verifiable = testVerifiable{} - -func (v testVerifiable) GetSignedPart() []byte { - return v -} -func (v testVerifiable) GetSignedHash() util.Uint256 { - return hash.Sha256(v) -} - -func testHash0100(t *testing.T, result string, interopFunc func(*interop.Context) error) { - t.Run("good", func(t *testing.T) { - bs := []byte{1, 0} - - checkGood := func(t *testing.T, ic *interop.Context) { - require.NoError(t, interopFunc(ic)) - require.Equal(t, 1, ic.VM.Estack().Len()) - require.Equal(t, result, hex.EncodeToString(ic.VM.Estack().Pop().Bytes())) - } - t.Run("raw bytes", func(t *testing.T) { - ic := &interop.Context{VM: vm.New()} - ic.VM.Estack().PushVal(bs) - checkGood(t, ic) - }) - t.Run("interop", func(t *testing.T) { - ic := &interop.Context{VM: vm.New()} - ic.VM.Estack().PushVal(stackitem.NewInterop(testVerifiable(bs))) - checkGood(t, ic) - }) - t.Run("container", func(t *testing.T) { - ic := &interop.Context{VM: vm.New(), Container: testVerifiable(bs)} - ic.VM.Estack().PushVal(stackitem.Null{}) - checkGood(t, ic) - }) - }) - t.Run("bad message", func(t *testing.T) { - ic := &interop.Context{VM: vm.New()} - ic.VM.Estack().PushVal(stackitem.NewArray(nil)) - require.Error(t, interopFunc(ic)) - }) -} - -func TestSHA256(t *testing.T) { - // 0x0100 hashes to 47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254 - res := "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254" - testHash0100(t, res, Sha256) -} - -func TestRIPEMD160(t *testing.T) { - // 0x0100 hashes to 213492c0c6fc5d61497cf17249dd31cd9964b8a3 - res := "213492c0c6fc5d61497cf17249dd31cd9964b8a3" - testHash0100(t, res, RipeMD160) -} diff --git a/pkg/core/interop/crypto/interop.go b/pkg/core/interop/crypto/interop.go index 74e7815df..6d8172f99 100644 --- a/pkg/core/interop/crypto/interop.go +++ b/pkg/core/interop/crypto/interop.go @@ -10,8 +10,6 @@ var ( ecdsaSecp256k1VerifyID = interopnames.ToID([]byte(interopnames.NeoCryptoVerifyWithECDsaSecp256k1)) ecdsaSecp256r1CheckMultisigID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1)) ecdsaSecp256k1CheckMultisigID = interopnames.ToID([]byte(interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1)) - sha256ID = interopnames.ToID([]byte(interopnames.NeoCryptoSHA256)) - ripemd160ID = interopnames.ToID([]byte(interopnames.NeoCryptoRIPEMD160)) ) var cryptoInterops = []interop.Function{ @@ -19,8 +17,6 @@ var cryptoInterops = []interop.Function{ {ID: ecdsaSecp256k1VerifyID, Func: ECDSASecp256k1Verify}, {ID: ecdsaSecp256r1CheckMultisigID, Func: ECDSASecp256r1CheckMultisig}, {ID: ecdsaSecp256k1CheckMultisigID, Func: ECDSASecp256k1CheckMultisig}, - {ID: sha256ID, Func: Sha256}, - {ID: ripemd160ID, Func: RipeMD160}, } func init() { diff --git a/pkg/core/interop/interopnames/names.go b/pkg/core/interop/interopnames/names.go index d342284f1..9b58c2796 100644 --- a/pkg/core/interop/interopnames/names.go +++ b/pkg/core/interop/interopnames/names.go @@ -51,8 +51,6 @@ const ( NeoCryptoVerifyWithECDsaSecp256k1 = "Neo.Crypto.VerifyWithECDsaSecp256k1" NeoCryptoCheckMultisigWithECDsaSecp256r1 = "Neo.Crypto.CheckMultisigWithECDsaSecp256r1" NeoCryptoCheckMultisigWithECDsaSecp256k1 = "Neo.Crypto.CheckMultisigWithECDsaSecp256k1" - NeoCryptoSHA256 = "Neo.Crypto.SHA256" - NeoCryptoRIPEMD160 = "Neo.Crypto.RIPEMD160" ) var names = []string{ @@ -105,6 +103,4 @@ var names = []string{ NeoCryptoVerifyWithECDsaSecp256k1, NeoCryptoCheckMultisigWithECDsaSecp256r1, NeoCryptoCheckMultisigWithECDsaSecp256k1, - NeoCryptoSHA256, - NeoCryptoRIPEMD160, } diff --git a/pkg/core/interops.go b/pkg/core/interops.go index 9b961ccff..db4844216 100644 --- a/pkg/core/interops.go +++ b/pkg/core/interops.go @@ -93,8 +93,6 @@ var neoInterops = []interop.Function{ Price: fee.ECDSAVerifyPrice, ParamCount: 3}, {Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 3}, {Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0, ParamCount: 3}, - {Name: interopnames.NeoCryptoSHA256, Func: crypto.Sha256, Price: 1 << 15, ParamCount: 1}, - {Name: interopnames.NeoCryptoRIPEMD160, Func: crypto.RipeMD160, Price: 1 << 15, ParamCount: 1}, } // initIDinInteropsSlice initializes IDs from names in one given diff --git a/pkg/core/native/contract.go b/pkg/core/native/contract.go index 7a0479144..64b8c73a9 100644 --- a/pkg/core/native/contract.go +++ b/pkg/core/native/contract.go @@ -24,6 +24,7 @@ type Contracts struct { Designate *Designate NameService *NameService Notary *Notary + Crypto *Crypto Contracts []interop.Contract // persistScript is vm script which executes "onPersist" method of every native contract. persistScript []byte @@ -61,6 +62,10 @@ func NewContracts(p2pSigExtensionsEnabled bool) *Contracts { cs.Management = mgmt cs.Contracts = append(cs.Contracts, mgmt) + c := newCrypto() + cs.Crypto = c + cs.Contracts = append(cs.Contracts, c) + ledger := newLedger() cs.Ledger = ledger cs.Contracts = append(cs.Contracts, ledger) diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go new file mode 100644 index 000000000..b377dd82e --- /dev/null +++ b/pkg/core/native/crypto.go @@ -0,0 +1,138 @@ +package native + +import ( + "crypto/elliptic" + "errors" + "fmt" + + "github.com/btcsuite/btcd/btcec" + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "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/smartcontract" + "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" +) + +// Crypto represents CryptoLib contract. +type Crypto struct { + interop.ContractMD +} + +// NamedCurve identifies named elliptic curves. +type NamedCurve byte + +// Various named elliptic curves. +const ( + Secp256k1 NamedCurve = 22 + Secp256r1 NamedCurve = 23 +) + +const cryptoContractID = -3 + +func newCrypto() *Crypto { + c := &Crypto{ContractMD: *interop.NewContractMD(nativenames.CryptoLib, cryptoContractID)} + defer c.UpdateHash() + + desc := newDescriptor("sha256", smartcontract.ByteArrayType, + manifest.NewParameter("data", smartcontract.ByteArrayType)) + md := newMethodAndPrice(c.sha256, 1<<15, callflag.NoneFlag) + c.AddMethod(md, desc) + + desc = newDescriptor("ripemd160", smartcontract.ByteArrayType, + manifest.NewParameter("data", smartcontract.ByteArrayType)) + md = newMethodAndPrice(c.ripemd160, 1<<15, callflag.NoneFlag) + c.AddMethod(md, desc) + + desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType, + manifest.NewParameter("message", smartcontract.ByteArrayType), + manifest.NewParameter("pubkey", smartcontract.ByteArrayType), + manifest.NewParameter("signature", smartcontract.ByteArrayType), + manifest.NewParameter("curve", smartcontract.IntegerType)) + md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag) + c.AddMethod(md, desc) + return c +} + +func (c *Crypto) sha256(_ *interop.Context, args []stackitem.Item) stackitem.Item { + bs, err := args[0].TryBytes() + if err != nil { + panic(err) + } + return stackitem.NewByteArray(hash.Sha256(bs).BytesBE()) +} + +func (c *Crypto) ripemd160(_ *interop.Context, args []stackitem.Item) stackitem.Item { + bs, err := args[0].TryBytes() + if err != nil { + panic(err) + } + return stackitem.NewByteArray(hash.RipeMD160(bs).BytesBE()) +} + +func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stackitem.Item { + msg, err := args[0].TryBytes() + if err != nil { + panic(fmt.Errorf("invalid message stackitem: %w", err)) + } + hashToCheck := hash.Sha256(msg) + pubkey, err := args[1].TryBytes() + if err != nil { + panic(fmt.Errorf("invalid pubkey stackitem: %w", err)) + } + signature, err := args[2].TryBytes() + if err != nil { + panic(fmt.Errorf("invalid signature stackitem: %w", err)) + } + curve, err := curveFromStackitem(args[3]) + if err != nil { + panic(fmt.Errorf("invalid curve stackitem: %w", err)) + } + pkey, err := keys.NewPublicKeyFromBytes(pubkey, curve) + if err != nil { + panic(fmt.Errorf("failed to decode pubkey: %w", err)) + } + res := pkey.Verify(signature, hashToCheck.BytesBE()) + return stackitem.NewBool(res) +} + +func curveFromStackitem(si stackitem.Item) (elliptic.Curve, error) { + curve, err := si.TryInteger() + if err != nil { + return nil, err + } + if !curve.IsInt64() { + return nil, errors.New("not an int64") + } + c := curve.Int64() + switch c { + case int64(Secp256k1): + return btcec.S256(), nil + case int64(Secp256r1): + return elliptic.P256(), nil + default: + return nil, errors.New("unsupported curve type") + } +} + +// Metadata implements Contract interface. +func (c *Crypto) Metadata() *interop.ContractMD { + return &c.ContractMD +} + +// Initialize implements Contract interface. +func (c *Crypto) Initialize(ic *interop.Context) error { + return nil +} + +// OnPersist implements Contract interface. +func (c *Crypto) OnPersist(ic *interop.Context) error { + return nil +} + +// PostPersist implements Contract interface. +func (c *Crypto) PostPersist(ic *interop.Context) error { + return nil +} diff --git a/pkg/core/native/crypto_test.go b/pkg/core/native/crypto_test.go new file mode 100644 index 000000000..37f61ef60 --- /dev/null +++ b/pkg/core/native/crypto_test.go @@ -0,0 +1,41 @@ +package native + +import ( + "encoding/hex" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/vm" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" + "github.com/stretchr/testify/require" +) + +func TestSha256(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.sha256(ic, []stackitem.Item{stackitem.NewInterop(nil)}) + }) + }) + t.Run("good", func(t *testing.T) { + // 0x0100 hashes to 47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254 + require.Equal(t, "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254", hex.EncodeToString(c.sha256(ic, []stackitem.Item{stackitem.NewByteArray([]byte{1, 0})}).Value().([]byte))) + }) +} + +func TestRIPEMD160(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.ripemd160(ic, []stackitem.Item{stackitem.NewInterop(nil)}) + }) + }) + t.Run("good", func(t *testing.T) { + // 0x0100 hashes to 213492c0c6fc5d61497cf17249dd31cd9964b8a3 + require.Equal(t, "213492c0c6fc5d61497cf17249dd31cd9964b8a3", hex.EncodeToString(c.ripemd160(ic, []stackitem.Item{stackitem.NewByteArray([]byte{1, 0})}).Value().([]byte))) + }) +} diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index 44e40978d..1186d6d7a 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -52,7 +52,7 @@ type roleData struct { } const ( - designateContractID = -6 + designateContractID = -8 // maxNodeCount is the maximum number of nodes to set the role for. maxNodeCount = 32 diff --git a/pkg/core/native/ledger.go b/pkg/core/native/ledger.go index 60ea77594..4c76da1d5 100644 --- a/pkg/core/native/ledger.go +++ b/pkg/core/native/ledger.go @@ -26,7 +26,7 @@ type Ledger struct { } const ( - ledgerContractID = -2 + ledgerContractID = -4 prefixBlockHash = 9 prefixCurrentBlock = 12 diff --git a/pkg/core/native/name_service.go b/pkg/core/native/name_service.go index 23d263156..dbaefde72 100644 --- a/pkg/core/native/name_service.go +++ b/pkg/core/native/name_service.go @@ -54,7 +54,7 @@ const ( ) const ( - nameServiceID = -8 + nameServiceID = -10 prefixRoots = 10 prefixDomainPrice = 22 diff --git a/pkg/core/native/native_gas.go b/pkg/core/native/native_gas.go index 8f18c9789..61e3b79bb 100644 --- a/pkg/core/native/native_gas.go +++ b/pkg/core/native/native_gas.go @@ -18,7 +18,7 @@ type GAS struct { NEO *NEO } -const gasContractID = -4 +const gasContractID = -6 // GASFactor is a divisor for finding GAS integral value. const GASFactor = NEOTotalSupply diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 17b35acdc..543b09842 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -50,7 +50,7 @@ type NEO struct { } const ( - neoContractID = -3 + neoContractID = -5 // NEOTotalSupply is the total amount of NEO in the system. NEOTotalSupply = 100000000 // prefixCandidate is a prefix used to store validator's data. diff --git a/pkg/core/native/nativenames/names.go b/pkg/core/native/nativenames/names.go index 0f37e5ba8..440057744 100644 --- a/pkg/core/native/nativenames/names.go +++ b/pkg/core/native/nativenames/names.go @@ -11,4 +11,5 @@ const ( Designation = "RoleManagement" Notary = "Notary" NameService = "NameService" + CryptoLib = "CryptoLib" ) diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index e6029cc62..bc2859fc8 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -47,7 +47,7 @@ type Oracle struct { } const ( - oracleContractID = -7 + oracleContractID = -9 maxURLLength = 256 maxFilterLength = 128 maxCallbackLength = 32 diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index 368d4926c..882ccc935 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -19,7 +19,7 @@ import ( ) const ( - policyContractID = -5 + policyContractID = -7 defaultExecFeeFactor = interop.DefaultBaseExecFee defaultFeePerByte = 1000 diff --git a/pkg/interop/crypto/crypto.go b/pkg/interop/crypto/crypto.go index 28702d7e9..f988632d0 100644 --- a/pkg/interop/crypto/crypto.go +++ b/pkg/interop/crypto/crypto.go @@ -8,16 +8,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal" ) -// SHA256 computes SHA256 hash of b. It uses `Neo.Crypto.SHA256` syscall. -func SHA256(b []byte) interop.Hash256 { - return neogointernal.Syscall1("Neo.Crypto.SHA256", b).(interop.Hash256) -} - -// RIPEMD160 computes RIPEMD160 hash of b. It uses `Neo.Crypto.RIPEMD160` syscall. -func RIPEMD160(b []byte) interop.Hash160 { - return neogointernal.Syscall1("Neo.Crypto.RIPEMD160", b).(interop.Hash160) -} - // 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 interop.PublicKey, sig interop.Signature) bool { diff --git a/pkg/interop/native/crypto/crypto.go b/pkg/interop/native/crypto/crypto.go new file mode 100644 index 000000000..32684d551 --- /dev/null +++ b/pkg/interop/native/crypto/crypto.go @@ -0,0 +1,34 @@ +package crypto + +import ( + "github.com/nspcc-dev/neo-go/pkg/interop" + "github.com/nspcc-dev/neo-go/pkg/interop/contract" +) + +// Hash represents CryptoLib contract hash. +const Hash = "\x1b\xf5\x75\xab\x11\x89\x68\x84\x13\x61\x0a\x35\xa1\x28\x86\xcd\xe0\xb6\x6c\x72" + +// NamedCurve represents named elliptic curve. +type NamedCurve byte + +// Various named elliptic curves. +const ( + Secp256k1 NamedCurve = 22 + Secp256r1 NamedCurve = 23 +) + +// Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b. +func Sha256(b []byte) interop.Hash256 { + return contract.Call(interop.Hash160(Hash), "sha256", contract.NoneFlag, b).(interop.Hash256) +} + +// Ripemd160 calls `ripemd160` method of native CryptoLib contract and computes RIPEMD160 hash of b. +func Ripemd160(b []byte) interop.Hash160 { + return contract.Call(interop.Hash160(Hash), "ripemd160", contract.NoneFlag, b).(interop.Hash160) +} + +// 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 { + return contract.Call(interop.Hash160(Hash), "verifyWithECDsa", contract.NoneFlag, msg, pub, sig, curve).(bool) +} diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 84a9a0269..166d856bd 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -183,7 +183,7 @@ var rpcTestCases = map[string][]rpcTestCase{ check: func(t *testing.T, e *executor, cs interface{}) { res, ok := cs.(*state.Contract) require.True(t, ok) - assert.Equal(t, int32(-5), res.ID) + assert.Equal(t, int32(-7), res.ID) }, }, {