From 7995229f6b48c28f5cd877f31fb4ddc95ea4bd92 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Sat, 27 Apr 2024 18:16:02 +0300 Subject: [PATCH 01/11] native: add test for custom Koblitz witness verification script Every single thing is already implemented in the protocol for Koblitz verification scripts. Signed-off-by: Anna Shaleva --- .../cryptolib_verification_test.go | 489 ++++++++++++++++++ 1 file changed, 489 insertions(+) create mode 100644 pkg/core/native/native_test/cryptolib_verification_test.go diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go new file mode 100644 index 000000000..1e42e627a --- /dev/null +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -0,0 +1,489 @@ +package native_test + +import ( + "math/big" + "testing" + + "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/core/native/nativenames" + "github.com/nspcc-dev/neo-go/pkg/core/state" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "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/io" + "github.com/nspcc-dev/neo-go/pkg/neotest" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/emit" + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" + "github.com/stretchr/testify/require" +) + +// TestCryptoLib_KoblitzVerificationScript builds transaction with custom witness that contains +// the Koblitz tx signature bytes and Koblitz signature verification script. +// This test ensures that transaction signed by Koblitz key passes verification and can +// be successfully accepted to the chain. +func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { + check := func( + t *testing.T, + buildVerificationScript func(t *testing.T, pub *keys.PublicKey) []byte, + constructMsg func(t *testing.T, magic uint32, tx hash.Hashable) []byte, + ) { + c := newGasClient(t) + gasInvoker := c.WithSigners(c.Committee) + e := c.Executor + + // Consider the user that is able to sign txs only with Secp256k1 private key. + // Let this user build, sign and push a GAS transfer transaction from its account + // to some other account. + pk, err := keys.NewSecp256k1PrivateKey() + require.NoError(t, err) + + // Firstly, we need to build the N3 user's account address based on the user's public key. + // The address itself is Hash160 from the verification script corresponding to the user's public key. + // Since user's private key belongs to Koblitz curve, we can't use System.Crypto.CheckSig interop + // in the verification script. Likely, we have a 'verifyWithECDsa' method in native CriptoLib contract + // that is able to check Koblitz signature. So let's build custom verification script based on this call. + // The script should call 'verifyWithECDsa' method of native CriptoLib contract with Koblitz curve identifier + // and check the provided message signature against the user's Koblitz public key. + vrfBytes := buildVerificationScript(t, pk.PublicKey()) + + // Construct the user's account script hash. It's effectively a verification script hash. + from := hash.Hash160(vrfBytes) + + // Supply this account with some initial balance so that the user is able to pay for his transactions. + gasInvoker.Invoke(t, true, "transfer", c.Committee.ScriptHash(), from, 10000_0000_0000, nil) + + // Construct transaction that transfers 5 GAS from the user's account to some other account. + to := util.Uint160{1, 2, 3} + amount := 5 + tx := gasInvoker.PrepareInvokeNoSign(t, "transfer", from, to, amount, nil) + tx.Signers = []transaction.Signer{ + { + Account: from, + Scopes: transaction.CalledByEntry, + }, + } + neotest.AddNetworkFee(t, e.Chain, tx) + neotest.AddSystemFee(e.Chain, tx, -1) + + // Add some more network fee to pay for the witness verification. This value may be calculated precisely, + // but let's keep some inaccurate value for the test. + tx.NetworkFee += 540_0000 + + // This transaction (along with the network magic) should be signed by the user's Koblitz private key. + msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) + + // The user has to sign the Sha256 hash of the message by his Koblitz key. + // Please, note that this Sha256 hash may easily be replaced by Keccaak hash via minor adjustment of + // CryptoLib's `verifyWithECDsa` behaviour (if needed). + signature := pk.SignHash(hash.Sha256(msg)) + + // Ensure that signature verification passes. This line here is just for testing purposes, + // it won't be present in the real code. + require.True(t, pk.PublicKey().Verify(signature, hash.Sha256(msg).BytesBE())) + + // Build invocation witness script for the user's account. + invBytes := buildKoblitzInvocationScript(t, signature) + + // Construct witness for signer #0 (the user itself). + tx.Scripts = []transaction.Witness{ + { + InvocationScript: invBytes, + VerificationScript: vrfBytes, + }, + } + + // Add transaction to the chain. No error is expected on new block addition. Note, that this line performs + // all those checks that are executed during transaction acceptance in the real network. + e.AddNewBlock(t, tx) + + // Double-check: ensure funds have been transferred. + e.CheckGASBalance(t, to, big.NewInt(int64(amount))) + } + + // The simplest witness verification script with low length and low execution cost + // (98 bytes, 2092530 GAS including Invocation script execution). + // The user has to sign the sha256([var-bytes-network-magic, txHash-bytes-BE]). + check(t, buildKoblitzVerificationScriptSimpleSingleHash, constructMessageNoHash) + + // Even more simple witness verification script with low length and low execution cost + // (95 bytes, 2092320 GAS including Invocation script execution). + // The user has to sign the sha256([var-bytes-network-magic, txHash-bytes-BE]). + // The difference is that network magic is a static value, thus, both verification script and + // user address are network-specific. + check(t, buildKoblitzVerificationScriptSimpleSingleHashStaticMagic, constructMessageNoHash) + + // More complicated verification script with higher length and higher execution cost + // (136 bytes, 4120620 GAS including Invocation script execution). + // The user has to sign the sha256(sha256([var-bytes-network-magic, txHash-bytes-BE])). + check(t, buildKoblitzVerificationScriptSimple, constructMessageSimple) + + // Witness verification script that follows the existing standard CheckSig account generation rules + // and has larger length and higher execution cost. + // (186 bytes, 5116020 GAS including Invocation script execution). + // The user has to sign the sha256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) + check(t, buildKoblitzVerificationScriptCompat, constructMessageCompat) +} + +// buildKoblitzVerificationScriptSimpleSingleHash builds witness verification script for Koblitz public key. +// This method differs from buildKoblitzVerificationScriptCompat in that it checks +// +// sha256([var-bytes-network-magic, txHash-bytes-BE]) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + // vrf is witness verification script corresponding to the pk. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [network-magic-bytes, tx.Hash()] + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (98 bytes length, always constant length, with variable length of signed data): + // NEO-GO-VM > loadbase64 ABZQDCEDY9ekgSWnbN6m4JjJ8SjoKSDtQo5ftMrx1/gcFsrQwgVBxfug4EEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 98 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 22 (16) << + // 2 SWAP + // 3 PUSHDATA1 0363d7a48125a76cdea6e098c9f128e82920ed428e5fb4caf1d7f81c16cad0c205 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 48 PUSH0 + // 49 PICKITEM + // 50 CAT + // 51 PUSH4 + // 52 PACK + // 53 PUSH15 + // 54 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 71 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 93 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScriptSimpleSingleHashStaticMagic builds witness verification script for Koblitz public key. +// This method differs from buildKoblitzVerificationScriptCompat in that it checks +// +// sha256([var-bytes-network-magic, txHash-bytes-BE]) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +// +// and it uses static magic value (simple PUSHINT* + magic, or PUSHDATA1 + magicBytes is also possible) +// which results in network-specific verification script and, consequently, network-specific user address. +func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + // vrf is witness verification script corresponding to the pk. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [network-magic-bytes, tx.Hash()] + // Firstly, push static network magic (it's 42 for unit test chain). + emit.Int(vrf.BinWriter, 42) + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (95 bytes length, always constant length, with variable length of signed data): + // NEO-GO-VM > loadbase64 ABZQDCECluEwgK3pKiq3IjOMKiSe6Ng6FPZJxoMhZkFl8GvREL0AKkEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 95 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 22 (16) << + // 2 SWAP + // 3 PUSHDATA1 0296e13080ade92a2ab722338c2a249ee8d83a14f649c68321664165f06bd110bd + // 38 PUSHINT8 42 (2a) + // 40 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 45 PUSH0 + // 46 PICKITEM + // 47 CAT + // 48 PUSH4 + // 49 PACK + // 50 PUSH15 + // 51 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 68 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 90 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScriptSimple builds witness verification script for Koblitz public key. +// This method differs from buildKoblitzVerificationScriptCompat in that it checks +// +// sha256(sha256([var-bytes-network-magic, txHash-bytes-BE])) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +// +// It produces constant-length verification script (136 bytes) independently of the network parameters. +// However, the length of signed message is variable and depends on the network magic (since network +// magic Integer stackitem being converted to Buffer has the resulting byte slice length that depends on +// the magic). +func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + // vrf is witness verification script corresponding to the pk. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = Sha256([network-magic-bytes, tx.Hash()]) + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM, // pick 0-th transaction item (the transaction hash). + opcode.CAT, // concatenate network magic and transaction hash; this instruction will convert network magic to bytes using BigInteger rules of conversion. + opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). + opcode.PACK) // pack arguments for 'sha256' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (136 bytes length, always constant length, with variable length of signed data): + // NEO-GO-VM 0 > loadbase64 ABZQDCEDp38Tevu0to16RQqloo/jNfgExYmoCElLS2JuuYcH831Bxfug4EEtUQgwEM6LEcAfDAZzaGEyNTYMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1IUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUg== + // READY: loaded 136 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 22 (16) << + // 2 SWAP + // 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 48 PUSH0 + // 49 PICKITEM + // 50 CAT + // 51 PUSH1 + // 52 PACK + // 53 PUSH15 + // 54 PUSHDATA1 736861323536 ("sha256") + // 62 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 84 SYSCALL System.Contract.Call (627d5b52) + // 89 PUSH4 + // 90 PACK + // 91 PUSH15 + // 92 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 109 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 131 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScript builds custom verification script for the provided Koblitz public key. +// It checks that the following message is signed by the provided public key: +// +// sha256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) +// +// It produces constant-length verification script (186 bytes) independently of the network parameters. +func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = Sha256([4-bytes-network-magic-LE, tx.Hash()]) + // Firstly, convert network magic (uint32) to LE buffer. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. + // First byte: n & 0xFF + emit.Opcodes(vrf.BinWriter, opcode.DUP) + emit.Int(vrf.BinWriter, 0xFF) // TODO: this can be optimize in order not to allocate 0xFF every time, but need to compare execution price. + emit.Opcodes(vrf.BinWriter, opcode.AND, + opcode.SWAP, // Swap with the original network n. + opcode.PUSH8, + opcode.SHR) + // Second byte: n >> 8 & 0xFF + emit.Opcodes(vrf.BinWriter, opcode.DUP) + emit.Int(vrf.BinWriter, 0xFF) + emit.Opcodes(vrf.BinWriter, opcode.AND, + opcode.SWAP, // Swap with the n >> 8. + opcode.PUSH8, + opcode.SHR) + // Third byte: n >> 16 & 0xFF + emit.Opcodes(vrf.BinWriter, opcode.DUP) + emit.Int(vrf.BinWriter, 0xFF) + emit.Opcodes(vrf.BinWriter, opcode.AND, + opcode.SWAP, // Swap with the n >> 16. + opcode.PUSH8, + opcode.SHR) + // Fourth byte: n >> 24 & 0xFF + emit.Int(vrf.BinWriter, 0xFF) // no DUP is needed since it's the last shift. + emit.Opcodes(vrf.BinWriter, opcode.AND) + // Put these 4 bytes into buffer. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.NEWBUFFER) // allocate new 4-bytes-length buffer. + emit.Opcodes(vrf.BinWriter, + // Set fourth byte. + opcode.DUP, opcode.PUSH3, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM, + // Set third byte. + opcode.DUP, opcode.PUSH2, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM, + // Set second byte. + opcode.DUP, opcode.PUSH1, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM, + // Set first byte. + opcode.DUP, opcode.PUSH0, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM) + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM, // pick 0-th transaction item (the transaction hash). + opcode.CAT, // concatenate network magic and transaction hash. + opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). + opcode.PACK) // pack arguments for 'sha256' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (186 bytes length, always constant length, the length of signed data is also always constant): + // NEO-GO-VM 0 > loadbase64 ABZQDCECYn75w2MePMuPvExbbEnjjM7eWnmvseGwcI+7lYp4AtdBxfug4EoB/wCRUBipSgH/AJFQGKlKAf8AkVAYqQH/AJEUiEoTE1LQShITUtBKERNS0EoQE1LQQS1RCDAQzosRwB8MBnNoYTI1NgwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUhTAHwwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtS + // READY: loaded 186 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 22 (16) << + // 2 SWAP + // 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 DUP + // 44 PUSHINT16 255 (ff00) + // 47 AND + // 48 SWAP + // 49 PUSH8 + // 50 SHR + // 51 DUP + // 52 PUSHINT16 255 (ff00) + // 55 AND + // 56 SWAP + // 57 PUSH8 + // 58 SHR + // 59 DUP + // 60 PUSHINT16 255 (ff00) + // 63 AND + // 64 SWAP + // 65 PUSH8 + // 66 SHR + // 67 PUSHINT16 255 (ff00) + // 70 AND + // 71 PUSH4 + // 72 NEWBUFFER + // 73 DUP + // 74 PUSH3 + // 75 PUSH3 + // 76 ROLL + // 77 SETITEM + // 78 DUP + // 79 PUSH2 + // 80 PUSH3 + // 81 ROLL + // 82 SETITEM + // 83 DUP + // 84 PUSH1 + // 85 PUSH3 + // 86 ROLL + // 87 SETITEM + // 88 DUP + // 89 PUSH0 + // 90 PUSH3 + // 91 ROLL + // 92 SETITEM + // 93 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 98 PUSH0 + // 99 PICKITEM + // 100 CAT + // 101 PUSH1 + // 102 PACK + // 103 PUSH15 + // 104 PUSHDATA1 736861323536 ("sha256") + // 112 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 134 SYSCALL System.Contract.Call (627d5b52) + // 139 PUSH4 + // 140 PACK + // 141 PUSH15 + // 142 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 159 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 181 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzInvocationScript builds witness invocation script for the transaction signature. The signature +// itself may be produced by public key over any curve (not required Koblitz, the algorithm is the same). +func buildKoblitzInvocationScript(t *testing.T, signature []byte) []byte { + //Exactly like during standard + // signature verification, the resulting script pushes Koblitz signature bytes onto stack. + inv := io.NewBufBinWriter() + emit.Bytes(inv.BinWriter, signature) // message signatre bytes. + require.NoError(t, inv.Err) + + return inv.Bytes() + // Here's an example of the resulting witness invocation script (66 bytes length, always constant length): + // NEO-GO-VM > loadbase64 DEBMGKU/MdSizlzaVNDUUbd1zMZQJ43eTaZ4vBCpmkJ/wVh1TYrAWEbFyHhkqq+aYxPCUS43NKJdJTXavcjB8sTP + // READY: loaded 66 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHDATA1 4c18a53f31d4a2ce5cda54d0d451b775ccc650278dde4da678bc10a99a427fc158754d8ac05846c5c87864aaaf9a6313c2512e3734a25d2535dabdc8c1f2c4cf << +} + +// constructMessageNoHash constructs message for signing that consists of the +// unhashed magic and transaction hash bytes: +// +// [var-bytes-network-magic, txHash-bytes-BE] +func constructMessageNoHash(t *testing.T, magic uint32, tx hash.Hashable) []byte { + m := big.NewInt(int64(magic)) + return append(m.Bytes(), tx.Hash().BytesBE()...) +} + +// constructMessageCompat constructs message for signing that does not follow N3 rules, +// but entails smaller verification script size and smaller verification price: +// +// sha256([var-bytes-network-magic, txHash-bytes-BE]) +func constructMessageSimple(t *testing.T, magic uint32, tx hash.Hashable) []byte { + m := big.NewInt(int64(magic)) + return hash.Sha256(append(m.Bytes(), tx.Hash().BytesBE()...)).BytesBE() +} + +// constructMessageCompat constructs message for signing following the N3 rules: +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]) +func constructMessageCompat(t *testing.T, magic uint32, tx hash.Hashable) []byte { + return hash.NetSha256(magic, tx).BytesBE() +} From 34eef47a18ff84d92d4e70687eccfef372c7788c Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 1 May 2024 15:44:14 +0300 Subject: [PATCH 02/11] native: extend CryptoLib's verifyWithECDsa with hasher parameter Replace native CryptoLib's verifyWithECDsa `curve` parameter by `curveHash` parameter which is a enum over supported pairs of named curves and hash functions. Even though this change is a compatible extension of the protocol, it changes the genesis state due to parameter renaming. But we're going to resync chain in 3.7 release anyway, so it's not a big deal. Also, we need to check mainnet and testnet compatibility in case if anyone has ever called verifyWithECDsa with 24 or 25 `curve` value. Signed-off-by: Anna Shaleva --- pkg/compiler/native_test.go | 8 ++- pkg/core/native/crypto.go | 63 ++++++++++++------- pkg/core/native/crypto_test.go | 44 ++++++++++--- .../cryptolib_verification_test.go | 57 +++++++++-------- .../native/native_test/management_test.go | 4 +- pkg/interop/native/crypto/crypto.go | 16 ++--- pkg/services/rpcsrv/server_test.go | 2 +- 7 files changed, 119 insertions(+), 75 deletions(-) diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index 47a2a7433..249e6717e 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -74,8 +74,10 @@ func TestRoleManagementRole(t *testing.T) { } func TestCryptoLibNamedCurve(t *testing.T) { - require.EqualValues(t, native.Secp256k1, crypto.Secp256k1) - require.EqualValues(t, native.Secp256r1, crypto.Secp256r1) + require.EqualValues(t, native.Secp256k1Sha256, crypto.Secp256k1Sha256) + require.EqualValues(t, native.Secp256r1Sha256, crypto.Secp256r1Sha256) + require.EqualValues(t, native.Secp256k1Keccak256, crypto.Secp256k1Keccak256) + require.EqualValues(t, native.Secp256r1Keccak256, crypto.Secp256r1Keccak256) } func TestOracleContractValues(t *testing.T) { @@ -233,7 +235,7 @@ func TestNativeHelpersCompile(t *testing.T) { {"sha256", []string{"[]byte{1, 2, 3}"}}, {"ripemd160", []string{"[]byte{1, 2, 3}"}}, {"murmur32", []string{"[]byte{1, 2, 3}", "123"}}, - {"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1"}}, + {"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1Sha256"}}, {"bls12381Serialize", []string{"crypto.Bls12381Point{}"}}, {"bls12381Deserialize", []string{"[]byte{1, 2, 3}"}}, {"bls12381Equal", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}}, diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go index 81979bfbd..bcc6b2f60 100644 --- a/pkg/core/native/crypto.go +++ b/pkg/core/native/crypto.go @@ -18,6 +18,7 @@ import ( "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/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/twmb/murmur3" "golang.org/x/crypto/sha3" @@ -28,13 +29,18 @@ type Crypto struct { interop.ContractMD } -// NamedCurve identifies named elliptic curves. -type NamedCurve byte +// HashFunc is a delegate representing a hasher function with 256 bytes output length. +type HashFunc func([]byte) util.Uint256 -// Various named elliptic curves. +// NamedCurveHash identifies a pair of named elliptic curve and hash function. +type NamedCurveHash byte + +// Various pairs of named elliptic curves and hash functions. const ( - Secp256k1 NamedCurve = 22 - Secp256r1 NamedCurve = 23 + Secp256k1Sha256 NamedCurveHash = 22 + Secp256r1Sha256 NamedCurveHash = 23 + Secp256k1Keccak256 NamedCurveHash = 24 + Secp256r1Keccak256 NamedCurveHash = 25 ) const cryptoContractID = -3 @@ -63,7 +69,7 @@ func newCrypto() *Crypto { manifest.NewParameter("message", smartcontract.ByteArrayType), manifest.NewParameter("pubkey", smartcontract.ByteArrayType), manifest.NewParameter("signature", smartcontract.ByteArrayType), - manifest.NewParameter("curve", smartcontract.IntegerType)) + manifest.NewParameter("curveHash", smartcontract.IntegerType)) md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag) c.AddMethod(md, desc) @@ -142,7 +148,6 @@ func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stac 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)) @@ -151,10 +156,11 @@ func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stac if err != nil { panic(fmt.Errorf("invalid signature stackitem: %w", err)) } - curve, err := curveFromStackitem(args[3]) + curve, hasher, err := curveHasherFromStackitem(args[3]) if err != nil { - panic(fmt.Errorf("invalid curve stackitem: %w", err)) + panic(fmt.Errorf("invalid curveHash stackitem: %w", err)) } + hashToCheck := hasher(msg) pkey, err := keys.NewPublicKeyFromBytes(pubkey, curve) if err != nil { panic(fmt.Errorf("failed to decode pubkey: %w", err)) @@ -163,22 +169,26 @@ func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stac return stackitem.NewBool(res) } -func curveFromStackitem(si stackitem.Item) (elliptic.Curve, error) { +func curveHasherFromStackitem(si stackitem.Item) (elliptic.Curve, HashFunc, error) { curve, err := si.TryInteger() if err != nil { - return nil, err + return nil, nil, err } if !curve.IsInt64() { - return nil, errors.New("not an int64") + return nil, nil, errors.New("not an int64") } c := curve.Int64() switch c { - case int64(Secp256k1): - return secp256k1.S256(), nil - case int64(Secp256r1): - return elliptic.P256(), nil + case int64(Secp256k1Sha256): + return secp256k1.S256(), hash.Sha256, nil + case int64(Secp256r1Sha256): + return elliptic.P256(), hash.Sha256, nil + case int64(Secp256k1Keccak256): + return secp256k1.S256(), Keccak256, nil + case int64(Secp256r1Keccak256): + return elliptic.P256(), Keccak256, nil default: - return nil, errors.New("unsupported curve type") + return nil, nil, errors.New("unsupported curve/hash type") } } @@ -295,13 +305,7 @@ func (c *Crypto) keccak256(_ *interop.Context, args []stackitem.Item) stackitem. if err != nil { panic(err) } - - digest := sha3.NewLegacyKeccak256() - _, err = digest.Write(bs) - if err != nil { - panic(err) - } - return stackitem.NewByteArray(digest.Sum(nil)) + return stackitem.NewByteArray(Keccak256(bs).BytesBE()) } // Metadata implements the Contract interface. @@ -333,3 +337,14 @@ func (c *Crypto) PostPersist(ic *interop.Context) error { func (c *Crypto) ActiveIn() *config.Hardfork { return nil } + +// Keccak256 hashes the incoming byte slice using the +// keccak256 algorithm. +func Keccak256(data []byte) util.Uint256 { + var hash util.Uint256 + hasher := sha3.NewLegacyKeccak256() + _, _ = hasher.Write(data) + + hasher.Sum(hash[:0]) + return hash +} diff --git a/pkg/core/native/crypto_test.go b/pkg/core/native/crypto_test.go index d5d79355e..db8207f73 100644 --- a/pkg/core/native/crypto_test.go +++ b/pkg/core/native/crypto_test.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "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/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" @@ -118,29 +119,44 @@ func TestMurmur32(t *testing.T) { } func TestCryptoLibVerifyWithECDsa(t *testing.T) { - t.Run("R1", func(t *testing.T) { - testECDSAVerify(t, Secp256r1) + t.Run("R1 sha256", func(t *testing.T) { + testECDSAVerify(t, Secp256r1Sha256) }) - t.Run("K1", func(t *testing.T) { - testECDSAVerify(t, Secp256k1) + t.Run("K1 sha256", func(t *testing.T) { + testECDSAVerify(t, Secp256k1Sha256) + }) + t.Run("R1 keccak256", func(t *testing.T) { + testECDSAVerify(t, Secp256r1Keccak256) + }) + t.Run("K1 keccak256", func(t *testing.T) { + testECDSAVerify(t, Secp256k1Keccak256) }) } -func testECDSAVerify(t *testing.T, curve NamedCurve) { +func testECDSAVerify(t *testing.T, curve NamedCurveHash) { var ( priv *keys.PrivateKey err error c = newCrypto() ic = &interop.Context{VM: vm.New()} actual stackitem.Item + hasher HashFunc ) switch curve { - case Secp256k1: + case Secp256k1Sha256: priv, err = keys.NewSecp256k1PrivateKey() - case Secp256r1: + hasher = hash.Sha256 + case Secp256r1Sha256: priv, err = keys.NewPrivateKey() + hasher = hash.Sha256 + case Secp256k1Keccak256: + priv, err = keys.NewSecp256k1PrivateKey() + hasher = Keccak256 + case Secp256r1Keccak256: + priv, err = keys.NewPrivateKey() + hasher = Keccak256 default: - t.Fatal("unknown curve") + t.Fatal("unknown curve/hash") } require.NoError(t, err) @@ -162,7 +178,7 @@ func testECDSAVerify(t *testing.T, curve NamedCurve) { } msg := []byte("test message") - sign := priv.Sign(msg) + sign := priv.SignHash(hasher(msg)) t.Run("bad message item", func(t *testing.T) { runCase(t, true, false, stackitem.NewInterop("cheburek"), priv.PublicKey().Bytes(), sign, int64(curve)) @@ -254,3 +270,13 @@ func TestCryptolib_ScalarFromBytes_Compat(t *testing.T) { }) } } + +func TestKeccak256(t *testing.T) { + input := []byte("hello") + data := Keccak256(input) + + expected := "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8" + actual := hex.EncodeToString(data.BytesBE()) + + require.Equal(t, expected, actual) +} diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 1e42e627a..5cbc7e62d 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -75,14 +75,13 @@ func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { // This transaction (along with the network magic) should be signed by the user's Koblitz private key. msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) - // The user has to sign the Sha256 hash of the message by his Koblitz key. - // Please, note that this Sha256 hash may easily be replaced by Keccaak hash via minor adjustment of - // CryptoLib's `verifyWithECDsa` behaviour (if needed). - signature := pk.SignHash(hash.Sha256(msg)) + // The user has to sign the hash of the message by his Koblitz key. + // Please, note that this Keccak256 hash may easily be replaced by sha256 hash if needed. + signature := pk.SignHash(native.Keccak256(msg)) // Ensure that signature verification passes. This line here is just for testing purposes, // it won't be present in the real code. - require.True(t, pk.PublicKey().Verify(signature, hash.Sha256(msg).BytesBE())) + require.True(t, pk.PublicKey().Verify(signature, native.Keccak256(msg).BytesBE())) // Build invocation witness script for the user's account. invBytes := buildKoblitzInvocationScript(t, signature) @@ -105,32 +104,32 @@ func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { // The simplest witness verification script with low length and low execution cost // (98 bytes, 2092530 GAS including Invocation script execution). - // The user has to sign the sha256([var-bytes-network-magic, txHash-bytes-BE]). + // The user has to sign the keccak256([var-bytes-network-magic, txHash-bytes-BE]). check(t, buildKoblitzVerificationScriptSimpleSingleHash, constructMessageNoHash) // Even more simple witness verification script with low length and low execution cost // (95 bytes, 2092320 GAS including Invocation script execution). - // The user has to sign the sha256([var-bytes-network-magic, txHash-bytes-BE]). + // The user has to sign the keccak256([var-bytes-network-magic, txHash-bytes-BE]). // The difference is that network magic is a static value, thus, both verification script and // user address are network-specific. check(t, buildKoblitzVerificationScriptSimpleSingleHashStaticMagic, constructMessageNoHash) // More complicated verification script with higher length and higher execution cost // (136 bytes, 4120620 GAS including Invocation script execution). - // The user has to sign the sha256(sha256([var-bytes-network-magic, txHash-bytes-BE])). + // The user has to sign the keccak256(sha256([var-bytes-network-magic, txHash-bytes-BE])). check(t, buildKoblitzVerificationScriptSimple, constructMessageSimple) // Witness verification script that follows the existing standard CheckSig account generation rules // and has larger length and higher execution cost. // (186 bytes, 5116020 GAS including Invocation script execution). - // The user has to sign the sha256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) + // The user has to sign the keccak256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) check(t, buildKoblitzVerificationScriptCompat, constructMessageCompat) } // buildKoblitzVerificationScriptSimpleSingleHash builds witness verification script for Koblitz public key. // This method differs from buildKoblitzVerificationScriptCompat in that it checks // -// sha256([var-bytes-network-magic, txHash-bytes-BE]) +// keccak256([var-bytes-network-magic, txHash-bytes-BE]) // // instead of (comparing with N3) // @@ -141,9 +140,9 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ // vrf is witness verification script corresponding to the pub. // vrf is witness verification script corresponding to the pk. vrf := io.NewBufBinWriter() - emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. - emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. - emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, // i.e. msg = [network-magic-bytes, tx.Hash()] // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). @@ -164,7 +163,7 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ // READY: loaded 98 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 22 (16) << + // 0 PUSHINT8 24 (18) << // 2 SWAP // 3 PUSHDATA1 0363d7a48125a76cdea6e098c9f128e82920ed428e5fb4caf1d7f81c16cad0c205 // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) @@ -183,7 +182,7 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ // buildKoblitzVerificationScriptSimpleSingleHashStaticMagic builds witness verification script for Koblitz public key. // This method differs from buildKoblitzVerificationScriptCompat in that it checks // -// sha256([var-bytes-network-magic, txHash-bytes-BE]) +// keccak256([var-bytes-network-magic, txHash-bytes-BE]) // // instead of (comparing with N3) // @@ -197,9 +196,9 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub // vrf is witness verification script corresponding to the pub. // vrf is witness verification script corresponding to the pk. vrf := io.NewBufBinWriter() - emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. - emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. - emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, // i.e. msg = [network-magic-bytes, tx.Hash()] // Firstly, push static network magic (it's 42 for unit test chain). @@ -220,7 +219,7 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub // READY: loaded 95 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 22 (16) << + // 0 PUSHINT8 24 (18) << // 2 SWAP // 3 PUSHDATA1 0296e13080ade92a2ab722338c2a249ee8d83a14f649c68321664165f06bd110bd // 38 PUSHINT8 42 (2a) @@ -239,7 +238,7 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub // buildKoblitzVerificationScriptSimple builds witness verification script for Koblitz public key. // This method differs from buildKoblitzVerificationScriptCompat in that it checks // -// sha256(sha256([var-bytes-network-magic, txHash-bytes-BE])) +// keccak256(sha256([var-bytes-network-magic, txHash-bytes-BE])) // // instead of (comparing with N3) // @@ -255,9 +254,9 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b // vrf is witness verification script corresponding to the pub. // vrf is witness verification script corresponding to the pk. vrf := io.NewBufBinWriter() - emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. - emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. - emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, // i.e. msg = Sha256([network-magic-bytes, tx.Hash()]) // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). @@ -280,7 +279,7 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b // READY: loaded 136 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 22 (16) << + // 0 PUSHINT8 24 (18) << // 2 SWAP // 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) @@ -305,7 +304,7 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b // buildKoblitzVerificationScript builds custom verification script for the provided Koblitz public key. // It checks that the following message is signed by the provided public key: // -// sha256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) +// keccak256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) // // It produces constant-length verification script (186 bytes) independently of the network parameters. func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []byte { @@ -313,9 +312,9 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b // vrf is witness verification script corresponding to the pub. vrf := io.NewBufBinWriter() - emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. - emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. - emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, // i.e. msg = Sha256([4-bytes-network-magic-LE, tx.Hash()]) // Firstly, convert network magic (uint32) to LE buffer. @@ -381,7 +380,7 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b // READY: loaded 186 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 22 (16) << + // 0 PUSHINT8 24 (18) << // 2 SWAP // 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7 // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) diff --git a/pkg/core/native/native_test/management_test.go b/pkg/core/native/native_test/management_test.go index 6bba730fb..1818076f1 100644 --- a/pkg/core/native/native_test/management_test.go +++ b/pkg/core/native/native_test/management_test.go @@ -40,7 +40,7 @@ var ( defaultCSS = map[string]string{ nativenames.Management: `{"id":-1,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","abi":{"methods":[{"name":"deploy","offset":0,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","safe":false},{"name":"deploy","offset":7,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","safe":false},{"name":"destroy","offset":14,"parameters":[],"returntype":"Void","safe":false},{"name":"getContract","offset":21,"parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getContractById","offset":28,"parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getContractHashes","offset":35,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getMinimumDeploymentFee","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"hasMethod","offset":49,"parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","safe":true},{"name":"setMinimumDeploymentFee","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"update","offset":63,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"update","offset":70,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.StdLib: `{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","abi":{"methods":[{"name":"atoi","offset":0,"parameters":[{"name":"value","type":"String"}],"returntype":"Integer","safe":true},{"name":"atoi","offset":7,"parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"base58CheckDecode","offset":14,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58CheckEncode","offset":21,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base58Decode","offset":28,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58Encode","offset":35,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base64Decode","offset":42,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base64Encode","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"deserialize","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"itoa","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":70,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":77,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":84,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":91,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":98,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":105,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":112,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":119,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":126,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":133,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":140,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, - nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2135988409},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":42,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":63,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, + nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2135988409},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":42,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":63,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Ledger: `{"id":-4,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","abi":{"methods":[{"name":"currentHash","offset":0,"parameters":[],"returntype":"Hash256","safe":true},{"name":"currentIndex","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getBlock","offset":14,"parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getTransaction","offset":21,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionFromBlock","offset":28,"parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getTransactionHeight","offset":35,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true},{"name":"getTransactionSigners","offset":42,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionVMState","offset":49,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":65467259},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getGasPerBlock","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":56,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":63,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":70,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":77,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":84,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":91,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":98,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":105,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":112,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":119,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":126,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Gas: `{"id":-6,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"symbol","offset":14,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`, @@ -52,7 +52,7 @@ var ( // cockatriceCSS holds serialized native contract states built for genesis block (with UpdateCounter 0) // under assumption that hardforks from Aspidochelone to Cockatrice (included) are enabled. cockatriceCSS = map[string]string{ - nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, + nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":77,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":84,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":91,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":98,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":105,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":112,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":119,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":126,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":133,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`, } ) diff --git a/pkg/interop/native/crypto/crypto.go b/pkg/interop/native/crypto/crypto.go index db0c3d750..40fd1a0e3 100644 --- a/pkg/interop/native/crypto/crypto.go +++ b/pkg/interop/native/crypto/crypto.go @@ -13,13 +13,15 @@ import ( // 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 a named elliptic curve. -type NamedCurve byte +// NamedCurveHash represents a pair of named elliptic curve and hash function. +type NamedCurveHash byte -// Various named elliptic curves. +// Various pairs of named elliptic curves and hash functions. const ( - Secp256k1 NamedCurve = 22 - Secp256r1 NamedCurve = 23 + Secp256k1Sha256 NamedCurveHash = 22 + Secp256r1Sha256 NamedCurveHash = 23 + Secp256k1Keccak256 NamedCurveHash = 24 + Secp256r1Keccak256 NamedCurveHash = 25 ) // Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b. @@ -40,8 +42,8 @@ func Murmur32(b []byte, seed int) []byte { // VerifyWithECDsa calls `verifyWithECDsa` method of native CryptoLib contract and checks that sig is // a correct msg's signature for the given pub (serialized public key on the given curve). -func VerifyWithECDsa(msg []byte, pub interop.PublicKey, sig interop.Signature, curve NamedCurve) bool { - return neogointernal.CallWithToken(Hash, "verifyWithECDsa", int(contract.NoneFlag), msg, pub, sig, curve).(bool) +func VerifyWithECDsa(msg []byte, pub interop.PublicKey, sig interop.Signature, curveHash NamedCurveHash) bool { + return neogointernal.CallWithToken(Hash, "verifyWithECDsa", int(contract.NoneFlag), msg, pub, sig, curveHash).(bool) } // Bls12381Point represents BLS12-381 curve point (G1 or G2 in the Affine or diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go index 57e5ed4ef..cd96f8dd1 100644 --- a/pkg/services/rpcsrv/server_test.go +++ b/pkg/services/rpcsrv/server_test.go @@ -89,7 +89,7 @@ const ( faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60" faultedTxBlock uint32 = 23 invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA" - block20StateRootLE = "397c69adbc0201d59623fa913bfff4a2da25c792c484d1d278c061709f2c21cf" + block20StateRootLE = "2d95b1149230d40c3043a84d42249b7b344f8755ea9fd0b2d95c5d011af85fc7" ) var ( From bd2f9c75e1cd06e5d650a274dfb04a8f17ba42b9 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 2 May 2024 14:06:37 +0300 Subject: [PATCH 03/11] crypto: export GetSignedData function It's needed for tests and further custom verification script build. Signed-off-by: Anna Shaleva --- pkg/crypto/hash/hash.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/crypto/hash/hash.go b/pkg/crypto/hash/hash.go index a997a3514..999b291da 100644 --- a/pkg/crypto/hash/hash.go +++ b/pkg/crypto/hash/hash.go @@ -16,7 +16,10 @@ type Hashable interface { Hash() util.Uint256 } -func getSignedData(net uint32, hh Hashable) []byte { +// GetSignedData returns the concatenated byte slice containing of the network +// magic in constant-length 4-bytes LE representation and hashable item hash in BE +// representation. +func GetSignedData(net uint32, hh Hashable) []byte { var b = make([]byte, 4+util.Uint256Size) binary.LittleEndian.PutUint32(b, net) h := hh.Hash() @@ -27,7 +30,7 @@ func getSignedData(net uint32, hh Hashable) []byte { // NetSha256 calculates a network-specific hash of the Hashable item that can then // be signed/verified. func NetSha256(net uint32, hh Hashable) util.Uint256 { - return Sha256(getSignedData(net, hh)) + return Sha256(GetSignedData(net, hh)) } // Sha256 hashes the incoming byte slice From 3acb132e9a65a67f2d18025950e9ed91144718e0 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 2 May 2024 14:08:54 +0300 Subject: [PATCH 04/11] native: add preferable method to TestCryptoLib_KoblitzVerificationScript It's based on the constant-length network magic, ref. https://github.com/nspcc-dev/neo-go/pull/3425#discussion_r1582068061. Signed-off-by: Anna Shaleva --- .../cryptolib_verification_test.go | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 5cbc7e62d..580c2d80d 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -102,6 +102,14 @@ func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { e.CheckGASBalance(t, to, big.NewInt(int64(amount))) } + // The proposed preferable witness verification script + // (110 bytes, 2154270 GAS including Invocation script execution). + // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). + check(t, buildKoblitzVerificationScript, constructMessage) + + // Below presented some variations of verification scripts that were also considered, but + // they are not as good as the first one. + // The simplest witness verification script with low length and low execution cost // (98 bytes, 2092530 GAS including Invocation script execution). // The user has to sign the keccak256([var-bytes-network-magic, txHash-bytes-BE]). @@ -126,6 +134,66 @@ func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { check(t, buildKoblitzVerificationScriptCompat, constructMessageCompat) } +// buildKoblitzVerificationScript builds witness verification script for Koblitz public key. +// This method checks +// +// keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [4-network-magic-bytes-LE, tx-hash-BE] + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic (Integer stackitem), can have 0-5 bytes length serialized. + // Convert network magic to 4-bytes-length LE byte array representation. + emit.Int(vrf.BinWriter, 0x100000000) + emit.Opcodes(vrf.BinWriter, opcode.ADD, // some new number that is 5 bytes at least when serialized, but first 4 bytes are intact network value (LE). + opcode.PUSH4, opcode.LEFT) // cut the first 4 bytes out of a number that is at least 5 bytes long, the result is 4-bytes-length LE network representation. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (110 bytes length, always constant length, with constant length of signed data): + // NEO-GO-VM > loadbase64 ABhQDCECoIi/qx5LS+3n1GJFcoYbQByyDDsU6QaHvYhiJypOYWZBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 110 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 24 (18) << + // 2 SWAP + // 3 PUSHDATA1 02a088bfab1e4b4bede7d4624572861b401cb20c3b14e90687bd8862272a4e6166 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 PUSHINT64 4294967296 (0000000001000000) + // 52 ADD + // 53 PUSH4 + // 54 LEFT + // 55 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 60 PUSH0 + // 61 PICKITEM + // 62 CAT + // 63 PUSH4 + // 64 PACK + // 65 PUSH15 + // 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 105 SYSCALL System.Contract.Call (627d5b52) +} + // buildKoblitzVerificationScriptSimpleSingleHash builds witness verification script for Koblitz public key. // This method differs from buildKoblitzVerificationScriptCompat in that it checks // @@ -462,6 +530,14 @@ func buildKoblitzInvocationScript(t *testing.T, signature []byte) []byte { // 0 PUSHDATA1 4c18a53f31d4a2ce5cda54d0d451b775ccc650278dde4da678bc10a99a427fc158754d8ac05846c5c87864aaaf9a6313c2512e3734a25d2535dabdc8c1f2c4cf << } +// constructMessage constructs message for signing that consists of the +// unhashed constant 4-bytes length LE magic and transaction hash bytes: +// +// [4-bytes-network-magic-LE, txHash-bytes-BE] +func constructMessage(t *testing.T, magic uint32, tx hash.Hashable) []byte { + return hash.GetSignedData(magic, tx) +} + // constructMessageNoHash constructs message for signing that consists of the // unhashed magic and transaction hash bytes: // From 71aa32406dfe3dacb6ad1a80dbd5b5a586b109ee Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 2 May 2024 19:17:02 +0300 Subject: [PATCH 05/11] native: add test for multisignature Koblitz witness verification Signed-off-by: Anna Shaleva --- .../cryptolib_verification_test.go | 325 +++++++++++++++++- pkg/vm/emit/emit.go | 5 + 2 files changed, 325 insertions(+), 5 deletions(-) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 580c2d80d..181a035bf 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -2,6 +2,7 @@ package native_test import ( "math/big" + "sort" "testing" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" @@ -84,7 +85,7 @@ func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { require.True(t, pk.PublicKey().Verify(signature, native.Keccak256(msg).BytesBE())) // Build invocation witness script for the user's account. - invBytes := buildKoblitzInvocationScript(t, signature) + invBytes := buildKoblitzInvocationScript(t, [][]byte{signature}) // Construct witness for signer #0 (the user itself). tx.Scripts = []transaction.Witness{ @@ -512,22 +513,34 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b // 181 SYSCALL System.Contract.Call (627d5b52) } -// buildKoblitzInvocationScript builds witness invocation script for the transaction signature. The signature +// buildKoblitzInvocationScript builds witness invocation script for the transaction signatures. The signature // itself may be produced by public key over any curve (not required Koblitz, the algorithm is the same). -func buildKoblitzInvocationScript(t *testing.T, signature []byte) []byte { +// The signatures expected to be sorted by public key (if multiple signatures are provided). +func buildKoblitzInvocationScript(t *testing.T, signatures [][]byte) []byte { //Exactly like during standard // signature verification, the resulting script pushes Koblitz signature bytes onto stack. inv := io.NewBufBinWriter() - emit.Bytes(inv.BinWriter, signature) // message signatre bytes. + for _, sig := range signatures { + emit.Bytes(inv.BinWriter, sig) // message signature bytes. + } require.NoError(t, inv.Err) return inv.Bytes() - // Here's an example of the resulting witness invocation script (66 bytes length, always constant length): + // Here's an example of the resulting single witness invocation script (66 bytes length, always constant length): // NEO-GO-VM > loadbase64 DEBMGKU/MdSizlzaVNDUUbd1zMZQJ43eTaZ4vBCpmkJ/wVh1TYrAWEbFyHhkqq+aYxPCUS43NKJdJTXavcjB8sTP // READY: loaded 66 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER // 0 PUSHDATA1 4c18a53f31d4a2ce5cda54d0d451b775ccc650278dde4da678bc10a99a427fc158754d8ac05846c5c87864aaaf9a6313c2512e3734a25d2535dabdc8c1f2c4cf << + // + // Here's an example of the 3 out of 4 multisignature invocation script (66 * m bytes length, always constant length): + // NEO-GO-VM > loadbase64 DEBsPMY3+7sWyZf0gCVcqPzwZ79p+KpeylgtbYIrXp4Tdi6E/8q3DIrEgK7DdVe3YdbfE+VPrpwym/ufBb8MRTB6DED5B9OZDGWdJApRfuy9LeUTa2mLsXP7mBRa181g0Jo7beylWzVgDqHHF2PilECMcLmRbFRknmQm4KgiGkDE+O6ZDEAYt61O2dMfasJHiQD95M5b4mR6NBnDsMTo2e59H3y4YguroVLiUxnQSc4qu9LWvEIKr4/ytjCCuANXOkJmSw8C + // READY: loaded 198 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHDATA1 6c3cc637fbbb16c997f480255ca8fcf067bf69f8aa5eca582d6d822b5e9e13762e84ffcab70c8ac480aec37557b761d6df13e54fae9c329bfb9f05bf0c45307a << + // 66 PUSHDATA1 f907d3990c659d240a517eecbd2de5136b698bb173fb98145ad7cd60d09a3b6deca55b35600ea1c71763e294408c70b9916c54649e6426e0a8221a40c4f8ee99 + // 132 PUSHDATA1 18b7ad4ed9d31f6ac2478900fde4ce5be2647a3419c3b0c4e8d9ee7d1f7cb8620baba152e25319d049ce2abbd2d6bc420aaf8ff2b63082b803573a42664b0f02 } // constructMessage constructs message for signing that consists of the @@ -562,3 +575,305 @@ func constructMessageSimple(t *testing.T, magic uint32, tx hash.Hashable) []byte func constructMessageCompat(t *testing.T, magic uint32, tx hash.Hashable) []byte { return hash.NetSha256(magic, tx).BytesBE() } + +// TestCryptoLib_KoblitzMultisigVerificationScript builds transaction with custom witness that contains +// the Koblitz tx multisignature bytes and Koblitz multisignature verification script. +// This test ensures that transaction signed by m out of n Koblitz keys passes verification and can +// be successfully accepted to the chain. +func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) { + check := func( + t *testing.T, + buildVerificationScript func(t *testing.T, m int, pub keys.PublicKeys) []byte, + constructMsg func(t *testing.T, magic uint32, tx hash.Hashable) []byte, + ) { + c := newGasClient(t) + gasInvoker := c.WithSigners(c.Committee) + e := c.Executor + + // Consider 4 users willing to sign 3/4 multisignature transaction Secp256k1 private keys. + const ( + n = 4 + m = 3 + ) + pks := make([]*keys.PrivateKey, n) + for i := range pks { + var err error + pks[i], err = keys.NewSecp256k1PrivateKey() + require.NoError(t, err) + } + // Sort private keys by their public keys. + sort.Slice(pks, func(i, j int) bool { + return pks[i].PublicKey().Cmp(pks[j].PublicKey()) < 0 + }) + + // Firstly, we need to build the N3 multisig account address based on the users' public keys. + // Pubs must be sorted, exactly like for the standard CheckMultisig. + pubs := make(keys.PublicKeys, n) + for i := range pks { + pubs[i] = pks[i].PublicKey() + } + vrfBytes := buildVerificationScript(t, m, pubs) + + // Construct the user's account script hash. It's effectively a verification script hash. + from := hash.Hash160(vrfBytes) + + // Supply this account with some initial balance so that the user is able to pay for his transactions. + gasInvoker.Invoke(t, true, "transfer", c.Committee.ScriptHash(), from, 10000_0000_0000, nil) + + // Construct transaction that transfers 5 GAS from the user's account to some other account. + to := util.Uint160{1, 2, 3} + amount := 5 + tx := gasInvoker.PrepareInvokeNoSign(t, "transfer", from, to, amount, nil) + tx.Signers = []transaction.Signer{ + { + Account: from, + Scopes: transaction.CalledByEntry, + }, + } + neotest.AddNetworkFee(t, e.Chain, tx) + neotest.AddSystemFee(e.Chain, tx, -1) + + // Add some more network fee to pay for the witness verification. This value may be calculated precisely, + // but let's keep some inaccurate value for the test. + tx.NetworkFee += 900_0000 + + // This transaction (along with the network magic) should be signed by the user's Koblitz private key. + msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) + + // The users have to sign the hash of the message by their Koblitz key. Collect m signatures from first m keys. + // Signatures must be sorted by public key. + sigs := make([][]byte, m) + for i := range sigs { + j := i + if i > 0 { + j++ // Add some shift to ensure that verification script works correctly. + } + if i > 3 { + j++ // Add more shift for large number of public keys for the same purpose. + } + sigs[i] = pks[j].SignHash(native.Keccak256(msg)) + } + + // Build invocation witness script for the signatures. + invBytes := buildKoblitzInvocationScript(t, sigs) + + // Construct witness for signer #0 (the multisig account itself). + tx.Scripts = []transaction.Witness{ + { + InvocationScript: invBytes, + VerificationScript: vrfBytes, + }, + } + + // Add transaction to the chain. No error is expected on new block addition. Note, that this line performs + // all those checks that are executed during transaction acceptance in the real network. + e.AddNewBlock(t, tx) + + // Double-check: ensure funds have been transferred. + e.CheckGASBalance(t, to, big.NewInt(int64(amount))) + } + + // The proposed multisig verification script. + // (261 bytes, 8389470 GAS including Invocation script execution for 3/4 multisig). + // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). + check(t, buildKoblitzMultisigVerificationScript, constructMessage) +} + +// buildKoblitzMultisigVerificationScript builds witness verification script for m signatures out of n Koblitz public keys. +// Public keys must be sorted. Signatures (pushed by witness Invocation script) must be sorted by public keys. +// It checks m out of n multisignature of the following message: +// +// keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]) +func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.PublicKeys) []byte { + if len(pubs) == 0 { + t.Fatalf("empty pubs list") + } + if m > len(pubs) { + t.Fatalf("m must be not greater than the number of public keys") + } + + n := len(pubs) // public keys must be sorted. + cryptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // In fact, the following algorithm is implemented via NeoVM instructions: + // + // func Check(sigs []interop.Signature) bool { + // if m != len(sigs) { + // return false + // } + // var pubs []interop.PublicKey = []interop.PublicKey{...} + // msg := append(convert.ToBytes(runtime.GetNetwork()), runtime.GetScriptContainer().Hash...) + // var sigCnt = 0 + // var pubCnt = 0 + // for ; sigCnt < m && pubCnt < n; { // sigs must be sorted by pub + // sigCnt += crypto.VerifyWithECDsa(msg, pubs[pubCnt], sigs[sigCnt], crypto.Secp256k1Keccak256) + // pubCnt++ + // } + // return sigCnt == m + // } + vrf := io.NewBufBinWriter() + + // Initialize slots for local variables. Locals slot scheme: + // LOC0 -> sigs + // LOC1 -> pubs + // LOC2 -> msg (ByteString) + // LOC3 -> sigCnt (Integer) + // LOC4 -> pubCnt (Integer) + emit.InitSlot(vrf.BinWriter, 5, 0) + + // Check the number of signatures is m. Return false if not. + emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // Push the number of signatures onto stack. + emit.Int(vrf.BinWriter, int64(m)) + emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient. + sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check. + emit.Opcodes(vrf.BinWriter, opcode.CLEAR, opcode.PUSHF, opcode.RET) // return if length of the signatures not equal to m. + + // Start the check. + checkStartOffset := vrf.Len() + + // Pack signatures and store at LOC0. + emit.Int(vrf.BinWriter, int64(m)) + emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC0) + + // Pack public keys and store at LOC1. + for _, pub := range pubs { + emit.Bytes(vrf.BinWriter, pub.Bytes()) + } + emit.Int(vrf.BinWriter, int64(n)) + emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC1) + + // Get message and store it at LOC2. + // msg = [4-network-magic-bytes-LE, tx-hash-BE] + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic (Integer stackitem), can have 0-5 bytes length serialized. + // Convert network magic to 4-bytes-length LE byte array representation. + emit.Int(vrf.BinWriter, 0x100000000) + emit.Opcodes(vrf.BinWriter, opcode.ADD, // some new number that is 5 bytes at least when serialized, but first 4 bytes are intact network value (LE). + opcode.PUSH4, opcode.LEFT) // cut the first 4 bytes out of a number that is at least 5 bytes long, the result is 4-bytes-length LE network representation. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + emit.Opcodes(vrf.BinWriter, opcode.STLOC2) // store msg as a local variable #2. + + // Initialize local variables: sigCnt, pubCnt. + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.STLOC3, // initialize sigCnt. + opcode.PUSH0, opcode.STLOC4) // initialize pubCnt. + + // Loop condition check. + loopStartOffset := vrf.Len() + emit.Opcodes(vrf.BinWriter, opcode.LDLOC3) // load sigCnt. + emit.Int(vrf.BinWriter, int64(m)) // push m. + emit.Opcodes(vrf.BinWriter, opcode.GE, // sigCnt >= m + opcode.LDLOC4) // load pubCnt + emit.Int(vrf.BinWriter, int64(n)) // push n. + emit.Opcodes(vrf.BinWriter, opcode.GE, // pubCnt >= n + opcode.OR) // sigCnt >= m || pubCnt >= n + emit.Instruction(vrf.BinWriter, opcode.JMPIF, []byte{0}) // jump to the end of the script if (sigCnt >= m || pubCnt >= n). + loopConditionOffset := vrf.Len() + + // Loop start. Prepare arguments and call CryptoLib's verifyWithECDsa. + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC0, // load signatures. + opcode.LDLOC3, // load sigCnt. + opcode.PICKITEM, // pick signature at index sigCnt. + opcode.LDLOC1, // load pubs. + opcode.LDLOC4, // load pubCnt. + opcode.PICKITEM, // pick pub at index pubCnt. + opcode.LDLOC2, // load msg. + opcode.PUSH4, opcode.PACK) // pack 4 arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, cryptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + + // Update loop variables. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC3, opcode.ADD, opcode.STLOC3, // increment sigCnt if signature is valid. + opcode.LDLOC4, opcode.INC, opcode.STLOC4) // increment pubCnt. + + // End of the loop. + emit.Instruction(vrf.BinWriter, opcode.JMP, []byte{0}) // jump to the start of cycle. + loopEndOffset := vrf.Len() + + // Return condition: the number of valid signatures should be equal to m. + progRetOffset := vrf.Len() + emit.Opcodes(vrf.BinWriter, opcode.LDLOC3) // load sigCnt. + emit.Int(vrf.BinWriter, int64(m)) // push m. + emit.Opcodes(vrf.BinWriter, opcode.NUMEQUAL) // push m == sigCnt. + + require.NoError(t, vrf.Err) + script := vrf.Bytes() + + // Set JMP* instructions offsets. "-1" is for short JMP parameter offset. JMP parameters + // are relative offsets. + script[sigsLenCheckEndOffset-1] = byte(checkStartOffset - sigsLenCheckEndOffset + 2) + script[loopEndOffset-1] = byte(loopStartOffset - loopEndOffset + 2) + script[loopConditionOffset-1] = byte(progRetOffset - loopConditionOffset + 2) + + return script + // Here's an example of the resulting single witness invocation script (261 bytes length, the length may vary depending on m/n): + // NEO-GO-VM > loadbase64 VwUAQxMoBUkJQBPAcAwhAnDdr99Ja4K3I81KURO2xs8b+dYYVIaMhbDFTYO4FCnKDCECuBwcms5bdqbWeBZ1cnMAJ8z/uUMcxnIK0CxTyxNdYqAMIQLQHl4aPx8PZOgu4EQUh0qCPaCfaZZPLNNS9ZVPcmuXpwwhA+YKTuJo6wB/u/CQdzJczfQQaMk6LHfMlSZMdBD2qCV1FMBxQcX7oOADAAAAAAEAAACeFI1BLVEIMBDOi3IQcxB0axO4bBS4kiRCABhoa85pbM5qFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1JrnnNsnHQiuWsTsw== + // READY: loaded 262 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 INITSLOT 5 local, 0 arg << + // 3 DEPTH + // 4 PUSH3 + // 5 JMPEQ 10 (5/05) + // 7 CLEAR + // 8 PUSHF + // 9 RET + // 10 PUSH3 + // 11 PACK + // 12 STLOC0 + // 13 PUSHDATA1 0270ddafdf496b82b723cd4a5113b6c6cf1bf9d61854868c85b0c54d83b81429ca + // 48 PUSHDATA1 02b81c1c9ace5b76a6d678167572730027ccffb9431cc6720ad02c53cb135d62a0 + // 83 PUSHDATA1 02d01e5e1a3f1f0f64e82ee04414874a823da09f69964f2cd352f5954f726b97a7 + // 118 PUSHDATA1 03e60a4ee268eb007fbbf09077325ccdf41068c93a2c77cc95264c7410f6a82575 + // 153 PUSH4 + // 154 PACK + // 155 STLOC1 + // 156 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 161 PUSHINT64 4294967296 (0000000001000000) + // 170 ADD + // 171 PUSH4 + // 172 LEFT + // 173 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 178 PUSH0 + // 179 PICKITEM + // 180 CAT + // 181 STLOC2 + // 182 PUSH0 + // 183 STLOC3 + // 184 PUSH0 + // 185 STLOC4 + // 186 LDLOC3 + // 187 PUSH3 + // 188 GE + // 189 LDLOC4 + // 190 PUSH4 + // 191 GE + // 192 OR + // 193 JMPIF 259 (66/42) + // 195 PUSHINT8 24 (18) + // 197 LDLOC0 + // 198 LDLOC3 + // 199 PICKITEM + // 200 LDLOC1 + // 201 LDLOC4 + // 202 PICKITEM + // 203 LDLOC2 + // 204 PUSH4 + // 205 PACK + // 206 PUSH15 + // 207 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 224 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 246 SYSCALL System.Contract.Call (627d5b52) + // 251 LDLOC3 + // 252 ADD + // 253 STLOC3 + // 254 LDLOC4 + // 255 INC + // 256 STLOC4 + // 257 JMP 186 (-71/b9) + // 259 LDLOC3 + // 260 PUSH3 + // 261 NUMEQUAL +} diff --git a/pkg/vm/emit/emit.go b/pkg/vm/emit/emit.go index a51e3f781..7a2b1033c 100644 --- a/pkg/vm/emit/emit.go +++ b/pkg/vm/emit/emit.go @@ -29,6 +29,11 @@ func Opcodes(w *io.BinWriter, ops ...opcode.Opcode) { } } +// InitSlot emits INITSLOT instruction with the specified size of locals/args slots. +func InitSlot(w *io.BinWriter, locals, args uint8) { + Instruction(w, opcode.INITSLOT, []byte{locals, args}) +} + // Bool emits a bool type to the given buffer. func Bool(w *io.BinWriter, ok bool) { var opVal = opcode.PUSHT From 5053a073f93d28cf5e9682bfa975f6c366112b15 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 3 May 2024 12:36:03 +0300 Subject: [PATCH 06/11] rpcsrv: test calculatenetworkfee with custom Koblitz-based witness Value calculated by calculatenetworkfee is enough to pass the real tx verification. However, network fee may be decreased, so calculations are not quite accurate. Need to investigate, why. Signed-off-by: Anna Shaleva --- .../native_test/cryptolib_verification_test.go | 2 +- pkg/services/rpcsrv/server_test.go | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 181a035bf..9b6dbaa22 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -635,7 +635,7 @@ func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) { // Add some more network fee to pay for the witness verification. This value may be calculated precisely, // but let's keep some inaccurate value for the test. - tx.NetworkFee += 900_0000 + tx.NetworkFee = 8995470 // This transaction (along with the network magic) should be signed by the user's Koblitz private key. msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go index cd96f8dd1..439b27dd4 100644 --- a/pkg/services/rpcsrv/server_test.go +++ b/pkg/services/rpcsrv/server_test.go @@ -3152,10 +3152,13 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] body := doRPCCall(`{"jsonrpc": "2.0", "id": 1, "method": "calculatenetworkfee", "params": ["bm90IGEgdHJhbnNhY3Rpb24K"]}"`, httpSrv.URL, t) _ = checkErrGetResult(t, body, true, neorpc.InvalidParamsCode, "Invalid params") }) - calcReq := func(t *testing.T, tx *transaction.Transaction) []byte { - rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "calculatenetworkfee", "params": ["%s"]}"`, base64.StdEncoding.EncodeToString(tx.Bytes())) + calcReqExactly := func(t *testing.T, tx string) []byte { + rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "calculatenetworkfee", "params": ["%s"]}"`, tx) return doRPCCall(rpc, httpSrv.URL, t) } + calcReq := func(t *testing.T, tx *transaction.Transaction) []byte { + return calcReqExactly(t, base64.StdEncoding.EncodeToString(tx.Bytes())) + } t.Run("non-contract with zero verification", func(t *testing.T) { tx := &transaction.Transaction{ Script: []byte{byte(opcode.RET)}, @@ -3235,6 +3238,13 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] } checkCalc(t, tx, 2315100) // Perfectly matches FeeIsMultiSigContract() C# test. }) + t.Run("Koblitz custom multisignature witness", func(t *testing.T) { + tx := "AAIAAACWP5gAAAAAAIBniwAAAAAAAgAAAAFSPSnnAijsThGazYipphHw5ljbTgEAVgsVDBQBAgMAAAAAAAAAAAAAAAAAAAAAAAwUUj0p5wIo7E4Rms2IqaYR8OZY204UwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSAcwMQgxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxCDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEIMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9BgFXBQBDEygFSQlAE8BwDCEDL5dNUWO0ZANmSz16KYRBbhmdzE7u8DguVYmWcRLdiF4MIQNFg/P7jBdGcTXcxgjfua/nv6taGb4rLqQXYGQ3LtfuLQwhA0hxJZ8CzRWOQpvE/60SPZ7bVYGr6Kl1MiZBLnvtDpsdDCECkTKVLY6bY2bFkIbD+dViOp7w2eZ2ZWr+1kH4qFNKkP8UwHFBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrE7hsFLiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5axOz" + resp := checkErrGetResult(t, calcReqExactly(t, tx), false, 0) + res := new(result.NetworkFee) + require.NoError(t, json.Unmarshal(resp, res)) + require.Equal(t, int64(8995470), res.Value) + }) checkContract := func(t *testing.T, verAcc util.Uint160, invoc []byte, fee int64) { txScript, err := smartcontract.CreateCallWithAssertScript(chain.UtilityTokenHash(), "transfer", verAcc, verAcc, 1, nil) From 3d1e33a50216fc2b6dce45b1188bf1e769faaf23 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 3 May 2024 15:29:03 +0300 Subject: [PATCH 07/11] native: make multisig koblitz easier to parse 1. Make prologue be exactly the same as regular CheckMultisig. 2. But instead of "SYSCALL System.Crypto.CheckMultisig" do INITSLOT and K check. 3. This makes all of the code from INITSLOT below be independent of N/M, so one can parse the script beginning in the same way CheckMultisig is parsed and then just compare the rest of it with some known-good blob. 4. The script becomes a tiny bit larger now, but properties above are too good. Signed-off-by: Roman Khimov Signed-off-by: Anna Shaleva --- .../cryptolib_verification_test.go | 178 ++++++++++-------- 1 file changed, 97 insertions(+), 81 deletions(-) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 9b6dbaa22..7e00dfc8c 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -674,7 +674,7 @@ func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) { } // The proposed multisig verification script. - // (261 bytes, 8389470 GAS including Invocation script execution for 3/4 multisig). + // (266 bytes, 8390070 GAS including Invocation script execution for 3/4 multisig). // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). check(t, buildKoblitzMultisigVerificationScript, constructMessage) } @@ -713,17 +713,36 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // } vrf := io.NewBufBinWriter() + // Start the same way as regular multisig script. + emit.Int(vrf.BinWriter, int64(m)) // push m. + for _, pub := range pubs { + emit.Bytes(vrf.BinWriter, pub.Bytes()) // push public keys in compressed form. + } + emit.Int(vrf.BinWriter, int64(n)) // push n. + // Initialize slots for local variables. Locals slot scheme: // LOC0 -> sigs // LOC1 -> pubs // LOC2 -> msg (ByteString) // LOC3 -> sigCnt (Integer) // LOC4 -> pubCnt (Integer) - emit.InitSlot(vrf.BinWriter, 5, 0) + // LOC5 -> n + // LOC6 -> m + emit.InitSlot(vrf.BinWriter, 7, 0) + + // Store n. + emit.Opcodes(vrf.BinWriter, opcode.STLOC5) + + // Pack public keys and store at LOC1. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC5) + emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC1) + + // Store m. + emit.Opcodes(vrf.BinWriter, opcode.STLOC6) // Check the number of signatures is m. Return false if not. - emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // Push the number of signatures onto stack. - emit.Int(vrf.BinWriter, int64(m)) + emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // push the number of signatures onto stack. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient. sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check. emit.Opcodes(vrf.BinWriter, opcode.CLEAR, opcode.PUSHF, opcode.RET) // return if length of the signatures not equal to m. @@ -732,16 +751,9 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi checkStartOffset := vrf.Len() // Pack signatures and store at LOC0. - emit.Int(vrf.BinWriter, int64(m)) + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC0) - // Pack public keys and store at LOC1. - for _, pub := range pubs { - emit.Bytes(vrf.BinWriter, pub.Bytes()) - } - emit.Int(vrf.BinWriter, int64(n)) - emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC1) - // Get message and store it at LOC2. // msg = [4-network-magic-bytes-LE, tx-hash-BE] emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic (Integer stackitem), can have 0-5 bytes length serialized. @@ -763,11 +775,11 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // Loop condition check. loopStartOffset := vrf.Len() emit.Opcodes(vrf.BinWriter, opcode.LDLOC3) // load sigCnt. - emit.Int(vrf.BinWriter, int64(m)) // push m. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // push m. emit.Opcodes(vrf.BinWriter, opcode.GE, // sigCnt >= m opcode.LDLOC4) // load pubCnt - emit.Int(vrf.BinWriter, int64(n)) // push n. - emit.Opcodes(vrf.BinWriter, opcode.GE, // pubCnt >= n + emit.Opcodes(vrf.BinWriter, opcode.LDLOC5) // push n. + emit.Opcodes(vrf.BinWriter, opcode.GE, // pubCnt >= n opcode.OR) // sigCnt >= m || pubCnt >= n emit.Instruction(vrf.BinWriter, opcode.JMPIF, []byte{0}) // jump to the end of the script if (sigCnt >= m || pubCnt >= n). loopConditionOffset := vrf.Len() @@ -795,7 +807,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // Return condition: the number of valid signatures should be equal to m. progRetOffset := vrf.Len() emit.Opcodes(vrf.BinWriter, opcode.LDLOC3) // load sigCnt. - emit.Int(vrf.BinWriter, int64(m)) // push m. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // push m. emit.Opcodes(vrf.BinWriter, opcode.NUMEQUAL) // push m == sigCnt. require.NoError(t, vrf.Err) @@ -808,72 +820,76 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi script[loopConditionOffset-1] = byte(progRetOffset - loopConditionOffset + 2) return script - // Here's an example of the resulting single witness invocation script (261 bytes length, the length may vary depending on m/n): - // NEO-GO-VM > loadbase64 VwUAQxMoBUkJQBPAcAwhAnDdr99Ja4K3I81KURO2xs8b+dYYVIaMhbDFTYO4FCnKDCECuBwcms5bdqbWeBZ1cnMAJ8z/uUMcxnIK0CxTyxNdYqAMIQLQHl4aPx8PZOgu4EQUh0qCPaCfaZZPLNNS9ZVPcmuXpwwhA+YKTuJo6wB/u/CQdzJczfQQaMk6LHfMlSZMdBD2qCV1FMBxQcX7oOADAAAAAAEAAACeFI1BLVEIMBDOi3IQcxB0axO4bBS4kiRCABhoa85pbM5qFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1JrnnNsnHQiuWsTsw== - // READY: loaded 262 instructions + // Here's an example of the resulting single witness invocation script (266 bytes length, the length may vary depending on m/n): + // NEO-GO-VM > loadbase64 EwwhAyGrdKSa2M6xnP2HMGzk4Gu/XffuBthZSuRatmtc0xd6DCECN5etf+pJm7AeaQNlFK0dgheMB4kMEG6v20PHe8JpoYQMIQNCHZPDdLgJyE+cbsj9KPpg/8ZsVtZNtziKDdKnOIV3ggwhAoXJ9JwG0qdjg1ZC/PQCV7PqNq0i9g2nOT+sKg1rqMhzFFcHAHVtwHF2Q24oBUkJQG7AcEHF+6DgAwAAAAABAAAAnhSNQS1RCDAQzotyEHMQdGtuuGxtuJIkQgAYaGvOaWzOahTAHwwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtSa55zbJx0IrlrbrM= + // READY: loaded 266 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 INITSLOT 5 local, 0 arg << - // 3 DEPTH - // 4 PUSH3 - // 5 JMPEQ 10 (5/05) - // 7 CLEAR - // 8 PUSHF - // 9 RET - // 10 PUSH3 - // 11 PACK - // 12 STLOC0 - // 13 PUSHDATA1 0270ddafdf496b82b723cd4a5113b6c6cf1bf9d61854868c85b0c54d83b81429ca - // 48 PUSHDATA1 02b81c1c9ace5b76a6d678167572730027ccffb9431cc6720ad02c53cb135d62a0 - // 83 PUSHDATA1 02d01e5e1a3f1f0f64e82ee04414874a823da09f69964f2cd352f5954f726b97a7 - // 118 PUSHDATA1 03e60a4ee268eb007fbbf09077325ccdf41068c93a2c77cc95264c7410f6a82575 - // 153 PUSH4 - // 154 PACK - // 155 STLOC1 - // 156 SYSCALL System.Runtime.GetNetwork (c5fba0e0) - // 161 PUSHINT64 4294967296 (0000000001000000) - // 170 ADD - // 171 PUSH4 - // 172 LEFT - // 173 SYSCALL System.Runtime.GetScriptContainer (2d510830) - // 178 PUSH0 - // 179 PICKITEM - // 180 CAT - // 181 STLOC2 + // 0 PUSH3 << + // 1 PUSHDATA1 0321ab74a49ad8ceb19cfd87306ce4e06bbf5df7ee06d8594ae45ab66b5cd3177a + // 36 PUSHDATA1 023797ad7fea499bb01e69036514ad1d82178c07890c106eafdb43c77bc269a184 + // 71 PUSHDATA1 03421d93c374b809c84f9c6ec8fd28fa60ffc66c56d64db7388a0dd2a738857782 + // 106 PUSHDATA1 0285c9f49c06d2a763835642fcf40257b3ea36ad22f60da7393fac2a0d6ba8c873 + // 141 PUSH4 + // 142 INITSLOT 7 local, 0 arg + // 145 STLOC5 + // 146 LDLOC5 + // 147 PACK + // 148 STLOC1 + // 149 STLOC6 + // 150 DEPTH + // 151 LDLOC6 + // 152 JMPEQ 157 (5/05) + // 154 CLEAR + // 155 PUSHF + // 156 RET + // 157 LDLOC6 + // 158 PACK + // 159 STLOC0 + // 160 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 165 PUSHINT64 4294967296 (0000000001000000) + // 174 ADD + // 175 PUSH4 + // 176 LEFT + // 177 SYSCALL System.Runtime.GetScriptContainer (2d510830) // 182 PUSH0 - // 183 STLOC3 - // 184 PUSH0 - // 185 STLOC4 - // 186 LDLOC3 - // 187 PUSH3 - // 188 GE - // 189 LDLOC4 - // 190 PUSH4 - // 191 GE - // 192 OR - // 193 JMPIF 259 (66/42) - // 195 PUSHINT8 24 (18) - // 197 LDLOC0 - // 198 LDLOC3 - // 199 PICKITEM - // 200 LDLOC1 - // 201 LDLOC4 - // 202 PICKITEM - // 203 LDLOC2 - // 204 PUSH4 - // 205 PACK - // 206 PUSH15 - // 207 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") - // 224 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") - // 246 SYSCALL System.Contract.Call (627d5b52) - // 251 LDLOC3 - // 252 ADD - // 253 STLOC3 - // 254 LDLOC4 - // 255 INC - // 256 STLOC4 - // 257 JMP 186 (-71/b9) - // 259 LDLOC3 - // 260 PUSH3 - // 261 NUMEQUAL + // 183 PICKITEM + // 184 CAT + // 185 STLOC2 + // 186 PUSH0 + // 187 STLOC3 + // 188 PUSH0 + // 189 STLOC4 + // 190 LDLOC3 + // 191 LDLOC6 + // 192 GE + // 193 LDLOC4 + // 194 LDLOC5 + // 195 GE + // 196 OR + // 197 JMPIF 263 (66/42) + // 199 PUSHINT8 24 (18) + // 201 LDLOC0 + // 202 LDLOC3 + // 203 PICKITEM + // 204 LDLOC1 + // 205 LDLOC4 + // 206 PICKITEM + // 207 LDLOC2 + // 208 PUSH4 + // 209 PACK + // 210 PUSH15 + // 211 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 228 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 250 SYSCALL System.Contract.Call (627d5b52) + // 255 LDLOC3 + // 256 ADD + // 257 STLOC3 + // 258 LDLOC4 + // 259 INC + // 260 STLOC4 + // 261 JMP 190 (-71/b9) + // 263 LDLOC3 + // 264 LDLOC6 + // 265 NUMEQUAL } From 701ea8d5f30601d29ecf816b029c8ca177056a90 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 3 May 2024 15:35:10 +0300 Subject: [PATCH 08/11] native: use ABORT in Koblitz multisig Make the script a bit shorter. ABORTMSG would cost a bit more. Signed-off-by: Roman Khimov Signed-off-by: Anna Shaleva --- .../cryptolib_verification_test.go | 130 +++++++++--------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 7e00dfc8c..5dbec0fc8 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -674,7 +674,7 @@ func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) { } // The proposed multisig verification script. - // (266 bytes, 8390070 GAS including Invocation script execution for 3/4 multisig). + // (264 bytes, 8390070 GAS including Invocation script execution for 3/4 multisig). // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). check(t, buildKoblitzMultisigVerificationScript, constructMessage) } @@ -740,12 +740,12 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // Store m. emit.Opcodes(vrf.BinWriter, opcode.STLOC6) - // Check the number of signatures is m. Return false if not. - emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // push the number of signatures onto stack. - emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. - emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient. - sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check. - emit.Opcodes(vrf.BinWriter, opcode.CLEAR, opcode.PUSHF, opcode.RET) // return if length of the signatures not equal to m. + // Check the number of signatures is m. Abort the execution if not. + emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // push the number of signatures onto stack. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. + emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient. + sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check. + emit.Opcodes(vrf.BinWriter, opcode.ABORT) // abort execution if length of the signatures not equal to m. // Start the check. checkStartOffset := vrf.Len() @@ -820,16 +820,16 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi script[loopConditionOffset-1] = byte(progRetOffset - loopConditionOffset + 2) return script - // Here's an example of the resulting single witness invocation script (266 bytes length, the length may vary depending on m/n): - // NEO-GO-VM > loadbase64 EwwhAyGrdKSa2M6xnP2HMGzk4Gu/XffuBthZSuRatmtc0xd6DCECN5etf+pJm7AeaQNlFK0dgheMB4kMEG6v20PHe8JpoYQMIQNCHZPDdLgJyE+cbsj9KPpg/8ZsVtZNtziKDdKnOIV3ggwhAoXJ9JwG0qdjg1ZC/PQCV7PqNq0i9g2nOT+sKg1rqMhzFFcHAHVtwHF2Q24oBUkJQG7AcEHF+6DgAwAAAAABAAAAnhSNQS1RCDAQzotyEHMQdGtuuGxtuJIkQgAYaGvOaWzOahTAHwwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtSa55zbJx0IrlrbrM= - // READY: loaded 266 instructions + // Here's an example of the resulting single witness invocation script (264 bytes length, the length may vary depending on m/n): + // NEO-GO-VM > loadbase64 EwwhAg1khs9yqTuG8R7dEj8/GhCqKwkL+6shSOczeaHENFo8DCECibz2wVNY1zRkRCbn+Qr87lQFjStnrQrwv1CSoea/91sMIQPiiV+wNGl5g5SVULR+BM/G2n6WO0WrGIsq+GBRqQHYwAwhAuwZz40NwnerrmSusUUgNqsZiv0WFj3KQE1BYd7lU7mDFFcHAHVtwHF2Q24oAzhuwHBBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrbrhsbbiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5a26z + // READY: loaded 264 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER // 0 PUSH3 << - // 1 PUSHDATA1 0321ab74a49ad8ceb19cfd87306ce4e06bbf5df7ee06d8594ae45ab66b5cd3177a - // 36 PUSHDATA1 023797ad7fea499bb01e69036514ad1d82178c07890c106eafdb43c77bc269a184 - // 71 PUSHDATA1 03421d93c374b809c84f9c6ec8fd28fa60ffc66c56d64db7388a0dd2a738857782 - // 106 PUSHDATA1 0285c9f49c06d2a763835642fcf40257b3ea36ad22f60da7393fac2a0d6ba8c873 + // 1 PUSHDATA1 020d6486cf72a93b86f11edd123f3f1a10aa2b090bfbab2148e73379a1c4345a3c + // 36 PUSHDATA1 0289bcf6c15358d734644426e7f90afcee54058d2b67ad0af0bf5092a1e6bff75b + // 71 PUSHDATA1 03e2895fb034697983949550b47e04cfc6da7e963b45ab188b2af86051a901d8c0 + // 106 PUSHDATA1 02ec19cf8d0dc277abae64aeb1452036ab198afd16163dca404d4161dee553b983 // 141 PUSH4 // 142 INITSLOT 7 local, 0 arg // 145 STLOC5 @@ -839,57 +839,55 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // 149 STLOC6 // 150 DEPTH // 151 LDLOC6 - // 152 JMPEQ 157 (5/05) - // 154 CLEAR - // 155 PUSHF - // 156 RET - // 157 LDLOC6 - // 158 PACK - // 159 STLOC0 - // 160 SYSCALL System.Runtime.GetNetwork (c5fba0e0) - // 165 PUSHINT64 4294967296 (0000000001000000) - // 174 ADD - // 175 PUSH4 - // 176 LEFT - // 177 SYSCALL System.Runtime.GetScriptContainer (2d510830) - // 182 PUSH0 - // 183 PICKITEM - // 184 CAT - // 185 STLOC2 + // 152 JMPEQ 155 (3/03) + // 154 ABORT + // 155 LDLOC6 + // 156 PACK + // 157 STLOC0 + // 158 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 163 PUSHINT64 4294967296 (0000000001000000) + // 172 ADD + // 173 PUSH4 + // 174 LEFT + // 175 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 180 PUSH0 + // 181 PICKITEM + // 182 CAT + // 183 STLOC2 + // 184 PUSH0 + // 185 STLOC3 // 186 PUSH0 - // 187 STLOC3 - // 188 PUSH0 - // 189 STLOC4 - // 190 LDLOC3 - // 191 LDLOC6 - // 192 GE - // 193 LDLOC4 - // 194 LDLOC5 - // 195 GE - // 196 OR - // 197 JMPIF 263 (66/42) - // 199 PUSHINT8 24 (18) - // 201 LDLOC0 - // 202 LDLOC3 - // 203 PICKITEM - // 204 LDLOC1 - // 205 LDLOC4 - // 206 PICKITEM - // 207 LDLOC2 - // 208 PUSH4 - // 209 PACK - // 210 PUSH15 - // 211 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") - // 228 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") - // 250 SYSCALL System.Contract.Call (627d5b52) - // 255 LDLOC3 - // 256 ADD - // 257 STLOC3 - // 258 LDLOC4 - // 259 INC - // 260 STLOC4 - // 261 JMP 190 (-71/b9) - // 263 LDLOC3 - // 264 LDLOC6 - // 265 NUMEQUAL + // 187 STLOC4 + // 188 LDLOC3 + // 189 LDLOC6 + // 190 GE + // 191 LDLOC4 + // 192 LDLOC5 + // 193 GE + // 194 OR + // 195 JMPIF 261 (66/42) + // 197 PUSHINT8 24 (18) + // 199 LDLOC0 + // 200 LDLOC3 + // 201 PICKITEM + // 202 LDLOC1 + // 203 LDLOC4 + // 204 PICKITEM + // 205 LDLOC2 + // 206 PUSH4 + // 207 PACK + // 208 PUSH15 + // 209 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 226 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 248 SYSCALL System.Contract.Call (627d5b52) + // 253 LDLOC3 + // 254 ADD + // 255 STLOC3 + // 256 LDLOC4 + // 257 INC + // 258 STLOC4 + // 259 JMP 188 (-71/b9) + // 261 LDLOC3 + // 262 LDLOC6 + // 263 NUMEQUAL } From 988440949bef9609d3b0024a4377782d835ab72c Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Sat, 4 May 2024 13:40:57 +0300 Subject: [PATCH 09/11] native: reduce callflag scope for Koblitz verification scripts callflag.All is too wide. Signed-off-by: Anna Shaleva --- .../cryptolib_verification_test.go | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index 5dbec0fc8..f119a8556 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -165,8 +165,8 @@ func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte { // Concatenate network magic and transaction hash. emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. // Continue construction of 'verifyWithECDsa' call. - emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. require.NoError(t, vrf.Err) return vrf.Bytes() @@ -189,7 +189,7 @@ func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte { // 62 CAT // 63 PUSH4 // 64 PACK - // 65 PUSH15 + // 65 PUSH0 // 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 105 SYSCALL System.Contract.Call (627d5b52) @@ -222,8 +222,8 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ // Concatenate network magic and transaction hash. emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. // Continue construction of 'verifyWithECDsa' call. - emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. require.NoError(t, vrf.Err) return vrf.Bytes() @@ -242,7 +242,7 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ // 50 CAT // 51 PUSH4 // 52 PACK - // 53 PUSH15 + // 53 PUSH0 // 54 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 71 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 93 SYSCALL System.Contract.Call (627d5b52) @@ -278,8 +278,8 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub // Concatenate network magic and transaction hash. emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. // Continue construction of 'verifyWithECDsa' call. - emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. require.NoError(t, vrf.Err) return vrf.Bytes() @@ -298,7 +298,7 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub // 47 CAT // 48 PUSH4 // 49 PACK - // 50 PUSH15 + // 50 PUSH0 // 51 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 68 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 90 SYSCALL System.Contract.Call (627d5b52) @@ -336,10 +336,10 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b opcode.CAT, // concatenate network magic and transaction hash; this instruction will convert network magic to bytes using BigInteger rules of conversion. opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). opcode.PACK) // pack arguments for 'sha256' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.NoneFlag) // emit the call to 'sha256' itself. // Continue construction of 'verifyWithECDsa' call. - emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. require.NoError(t, vrf.Err) return vrf.Bytes() @@ -358,13 +358,13 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b // 50 CAT // 51 PUSH1 // 52 PACK - // 53 PUSH15 + // 53 PUSH0 // 54 PUSHDATA1 736861323536 ("sha256") // 62 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 84 SYSCALL System.Contract.Call (627d5b52) // 89 PUSH4 // 90 PACK - // 91 PUSH15 + // 91 PUSH0 // 92 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 109 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 131 SYSCALL System.Contract.Call (627d5b52) @@ -437,10 +437,10 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b opcode.CAT, // concatenate network magic and transaction hash. opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). opcode.PACK) // pack arguments for 'sha256' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.NoneFlag) // emit the call to 'sha256' itself. // Continue construction of 'verifyWithECDsa' call. - emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. - emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. require.NoError(t, vrf.Err) return vrf.Bytes() @@ -501,13 +501,13 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b // 100 CAT // 101 PUSH1 // 102 PACK - // 103 PUSH15 + // 103 PUSH0 // 104 PUSHDATA1 736861323536 ("sha256") // 112 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 134 SYSCALL System.Contract.Call (627d5b52) // 139 PUSH4 // 140 PACK - // 141 PUSH15 + // 141 PUSH0 // 142 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 159 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 181 SYSCALL System.Contract.Call (627d5b52) @@ -794,7 +794,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi opcode.PICKITEM, // pick pub at index pubCnt. opcode.LDLOC2, // load msg. opcode.PUSH4, opcode.PACK) // pack 4 arguments for 'verifyWithECDsa' call. - emit.AppCallNoArgs(vrf.BinWriter, cryptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. + emit.AppCallNoArgs(vrf.BinWriter, cryptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. // Update loop variables. emit.Opcodes(vrf.BinWriter, opcode.LDLOC3, opcode.ADD, opcode.STLOC3, // increment sigCnt if signature is valid. @@ -876,7 +876,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // 205 LDLOC2 // 206 PUSH4 // 207 PACK - // 208 PUSH15 + // 208 PUSH0 // 209 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 226 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 248 SYSCALL System.Contract.Call (627d5b52) From 6e0926e59ffbd824ba76dc7935e3cb4ab3581e08 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 6 May 2024 16:57:38 +0300 Subject: [PATCH 10/11] native: adjust NamedCurveHash values Use 122 and 123 respectively for Secp256k1Keccak256 and Secp256r1Keccak256, ref. https://github.com/neo-project/neo/pull/3209#issuecomment-2095798056. Signed-off-by: Anna Shaleva --- pkg/core/native/crypto.go | 4 ++-- pkg/core/native/crypto_test.go | 2 +- .../native_test/cryptolib_verification_test.go | 12 ++++++------ pkg/interop/native/crypto/crypto.go | 4 ++-- pkg/services/rpcsrv/server_test.go | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go index bcc6b2f60..d63a20c70 100644 --- a/pkg/core/native/crypto.go +++ b/pkg/core/native/crypto.go @@ -39,8 +39,8 @@ type NamedCurveHash byte const ( Secp256k1Sha256 NamedCurveHash = 22 Secp256r1Sha256 NamedCurveHash = 23 - Secp256k1Keccak256 NamedCurveHash = 24 - Secp256r1Keccak256 NamedCurveHash = 25 + Secp256k1Keccak256 NamedCurveHash = 122 + Secp256r1Keccak256 NamedCurveHash = 123 ) const cryptoContractID = -3 diff --git a/pkg/core/native/crypto_test.go b/pkg/core/native/crypto_test.go index db8207f73..0227a9da8 100644 --- a/pkg/core/native/crypto_test.go +++ b/pkg/core/native/crypto_test.go @@ -199,7 +199,7 @@ func testECDSAVerify(t *testing.T, curve NamedCurveHash) { runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1))) }) t.Run("unknown curve", func(t *testing.T) { - runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(123)) + runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(124)) }) t.Run("invalid signature", func(t *testing.T) { s := priv.Sign(msg) diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go index f119a8556..2143a1217 100644 --- a/pkg/core/native/native_test/cryptolib_verification_test.go +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -175,7 +175,7 @@ func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte { // READY: loaded 110 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 24 (18) << + // 0 PUSHINT8 122 (7a) << // 2 SWAP // 3 PUSHDATA1 02a088bfab1e4b4bede7d4624572861b401cb20c3b14e90687bd8862272a4e6166 // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) @@ -232,7 +232,7 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ // READY: loaded 98 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 24 (18) << + // 0 PUSHINT8 122 (7a) << // 2 SWAP // 3 PUSHDATA1 0363d7a48125a76cdea6e098c9f128e82920ed428e5fb4caf1d7f81c16cad0c205 // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) @@ -288,7 +288,7 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub // READY: loaded 95 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 24 (18) << + // 0 PUSHINT8 122 (7a) << // 2 SWAP // 3 PUSHDATA1 0296e13080ade92a2ab722338c2a249ee8d83a14f649c68321664165f06bd110bd // 38 PUSHINT8 42 (2a) @@ -348,7 +348,7 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b // READY: loaded 136 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 24 (18) << + // 0 PUSHINT8 122 (7a) << // 2 SWAP // 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) @@ -449,7 +449,7 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b // READY: loaded 186 instructions // NEO-GO-VM 0 > ops // INDEX OPCODE PARAMETER - // 0 PUSHINT8 24 (18) << + // 0 PUSHINT8 122 (7a) << // 2 SWAP // 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7 // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) @@ -866,7 +866,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi // 193 GE // 194 OR // 195 JMPIF 261 (66/42) - // 197 PUSHINT8 24 (18) + // 197 PUSHINT8 122 (7a) // 199 LDLOC0 // 200 LDLOC3 // 201 PICKITEM diff --git a/pkg/interop/native/crypto/crypto.go b/pkg/interop/native/crypto/crypto.go index 40fd1a0e3..b3574fcde 100644 --- a/pkg/interop/native/crypto/crypto.go +++ b/pkg/interop/native/crypto/crypto.go @@ -20,8 +20,8 @@ type NamedCurveHash byte const ( Secp256k1Sha256 NamedCurveHash = 22 Secp256r1Sha256 NamedCurveHash = 23 - Secp256k1Keccak256 NamedCurveHash = 24 - Secp256r1Keccak256 NamedCurveHash = 25 + Secp256k1Keccak256 NamedCurveHash = 122 + Secp256r1Keccak256 NamedCurveHash = 123 ) // Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b. diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go index 439b27dd4..f6c89d7fd 100644 --- a/pkg/services/rpcsrv/server_test.go +++ b/pkg/services/rpcsrv/server_test.go @@ -3239,11 +3239,11 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] checkCalc(t, tx, 2315100) // Perfectly matches FeeIsMultiSigContract() C# test. }) t.Run("Koblitz custom multisignature witness", func(t *testing.T) { - tx := "AAIAAACWP5gAAAAAAIBniwAAAAAAAgAAAAFSPSnnAijsThGazYipphHw5ljbTgEAVgsVDBQBAgMAAAAAAAAAAAAAAAAAAAAAAAwUUj0p5wIo7E4Rms2IqaYR8OZY204UwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSAcwMQgxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxCDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEIMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9BgFXBQBDEygFSQlAE8BwDCEDL5dNUWO0ZANmSz16KYRBbhmdzE7u8DguVYmWcRLdiF4MIQNFg/P7jBdGcTXcxgjfua/nv6taGb4rLqQXYGQ3LtfuLQwhA0hxJZ8CzRWOQpvE/60SPZ7bVYGr6Kl1MiZBLnvtDpsdDCECkTKVLY6bY2bFkIbD+dViOp7w2eZ2ZWr+1kH4qFNKkP8UwHFBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrE7hsFLiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5axOz" + tx := "AAIAAACWP5gAAAAAAAAAAAAAAAAAAgAAAAEGyZgQyJQyWjzvqUZochi8rGE9RQEAVgsVDBQBAgMAAAAAAAAAAAAAAAAAAAAAAAwUBsmYEMiUMlo876lGaHIYvKxhPUUUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSAcYMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9CAETDCECbSVpJ0BN2xiveIGNU0LzEz4V7FUAp1NV8s7YI4kq9eQMIQOaHY3bh+3OmXuU9t72Pj62loLM7gZDgXJwnBV2zO4u1wwhAsvP18ohoYHcHBPt4wwPqAOstOhazEegr4klYmDlWpzeDCED9EsK7L0qFMP1QpBBfKMMVXPLa894ONINLRtjtBLBM6oUVwcAdW3AcXZDbigDOG7AcEHF+6DgAwAAAAABAAAAnhSNQS1RCDAQzotyEHMQdGtuuGxtuJIkQgB6aGvOaWzOahTAEAwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtSa55zbJx0IrlrbrM=" resp := checkErrGetResult(t, calcReqExactly(t, tx), false, 0) res := new(result.NetworkFee) require.NoError(t, json.Unmarshal(resp, res)) - require.Equal(t, int64(8995470), res.Value) + require.Equal(t, int64(8992070), res.Value) }) checkContract := func(t *testing.T, verAcc util.Uint160, invoc []byte, fee int64) { txScript, err := smartcontract.CreateCallWithAssertScript(chain.UtilityTokenHash(), "transfer", From e2754958508b8448acaf1f5b9e7a38fc56951110 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 13 May 2024 10:16:04 +0300 Subject: [PATCH 11/11] *: update interop deps Signed-off-by: Anna Shaleva --- examples/engine/go.mod | 2 +- examples/engine/go.sum | 4 ++-- examples/events/go.mod | 2 +- examples/events/go.sum | 4 ++-- examples/iterator/go.mod | 2 +- examples/iterator/go.sum | 4 ++-- examples/nft-d/go.mod | 2 +- examples/nft-d/go.sum | 4 ++-- examples/nft-nd-nns/go.mod | 2 +- examples/nft-nd-nns/go.sum | 4 ++-- examples/nft-nd/go.mod | 2 +- examples/nft-nd/go.sum | 4 ++-- examples/oracle/go.mod | 2 +- examples/oracle/go.sum | 4 ++-- examples/runtime/go.mod | 2 +- examples/runtime/go.sum | 4 ++-- examples/storage/go.mod | 2 +- examples/storage/go.sum | 4 ++-- examples/timer/go.mod | 2 +- examples/timer/go.sum | 4 ++-- examples/token/go.mod | 2 +- examples/token/go.sum | 4 ++-- examples/zkp/cubic_circuit/go.mod | 2 +- examples/zkp/cubic_circuit/go.sum | 4 ++-- examples/zkp/xor_compat/go.mod | 2 +- examples/zkp/xor_compat/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/contracts/oracle_contract/go.mod | 2 +- internal/contracts/oracle_contract/go.sum | 4 ++-- 30 files changed, 45 insertions(+), 45 deletions(-) diff --git a/examples/engine/go.mod b/examples/engine/go.mod index b8c1f57b6..a3e1af0dc 100644 --- a/examples/engine/go.mod +++ b/examples/engine/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/engine/go.sum b/examples/engine/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/engine/go.sum +++ b/examples/engine/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/events/go.mod b/examples/events/go.mod index b0bda4b37..8c9910e5a 100644 --- a/examples/events/go.mod +++ b/examples/events/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/events/go.sum b/examples/events/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/events/go.sum +++ b/examples/events/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/iterator/go.mod b/examples/iterator/go.mod index 2b3d13d3e..57de4a87e 100644 --- a/examples/iterator/go.mod +++ b/examples/iterator/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/iterator/go.sum b/examples/iterator/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/iterator/go.sum +++ b/examples/iterator/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/nft-d/go.mod b/examples/nft-d/go.mod index 42df68efc..87060a972 100644 --- a/examples/nft-d/go.mod +++ b/examples/nft-d/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/nft-d/go.sum b/examples/nft-d/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/nft-d/go.sum +++ b/examples/nft-d/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/nft-nd-nns/go.mod b/examples/nft-nd-nns/go.mod index 78522923e..249993a39 100644 --- a/examples/nft-nd-nns/go.mod +++ b/examples/nft-nd-nns/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb github.com/stretchr/testify v1.8.4 ) diff --git a/examples/nft-nd-nns/go.sum b/examples/nft-nd-nns/go.sum index bb122c9db..2e6044811 100644 --- a/examples/nft-nd-nns/go.sum +++ b/examples/nft-nd-nns/go.sum @@ -200,8 +200,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= diff --git a/examples/nft-nd/go.mod b/examples/nft-nd/go.mod index e9f47c373..b84c32fb7 100644 --- a/examples/nft-nd/go.mod +++ b/examples/nft-nd/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/nft-nd/go.sum b/examples/nft-nd/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/nft-nd/go.sum +++ b/examples/nft-nd/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/oracle/go.mod b/examples/oracle/go.mod index cf5e26961..031ffbf68 100644 --- a/examples/oracle/go.mod +++ b/examples/oracle/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/oracle/go.sum b/examples/oracle/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/oracle/go.sum +++ b/examples/oracle/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/runtime/go.mod b/examples/runtime/go.mod index d49e669e2..a243086af 100644 --- a/examples/runtime/go.mod +++ b/examples/runtime/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/runtime/go.sum b/examples/runtime/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/runtime/go.sum +++ b/examples/runtime/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/storage/go.mod b/examples/storage/go.mod index 786d4d324..f4eca85b6 100644 --- a/examples/storage/go.mod +++ b/examples/storage/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/storage/go.sum b/examples/storage/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/storage/go.sum +++ b/examples/storage/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/timer/go.mod b/examples/timer/go.mod index e00b24175..95043975b 100644 --- a/examples/timer/go.mod +++ b/examples/timer/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/timer/go.sum b/examples/timer/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/timer/go.sum +++ b/examples/timer/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/token/go.mod b/examples/token/go.mod index 64494aad8..077dd8891 100644 --- a/examples/token/go.mod +++ b/examples/token/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/token/go.sum b/examples/token/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/token/go.sum +++ b/examples/token/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/zkp/cubic_circuit/go.mod b/examples/zkp/cubic_circuit/go.mod index 54702a26a..bab4104c3 100644 --- a/examples/zkp/cubic_circuit/go.mod +++ b/examples/zkp/cubic_circuit/go.mod @@ -33,7 +33,7 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c // indirect - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 // indirect + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb // indirect github.com/nspcc-dev/rfc6979 v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/examples/zkp/cubic_circuit/go.sum b/examples/zkp/cubic_circuit/go.sum index 59d49427b..809bda2cb 100644 --- a/examples/zkp/cubic_circuit/go.sum +++ b/examples/zkp/cubic_circuit/go.sum @@ -216,8 +216,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c/go.mod h github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/neo-go v0.103.1 h1:BfRBceHUu8jSc1KQy7CzmQ/pa+xzAmgcyteGf0/IGgM= github.com/nspcc-dev/neo-go v0.103.1/go.mod h1:MD7MPiyshUwrE5n1/LzxeandbItaa/iLW/bJb6gNs/U= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= diff --git a/examples/zkp/xor_compat/go.mod b/examples/zkp/xor_compat/go.mod index a605846d1..8882b7ca2 100644 --- a/examples/zkp/xor_compat/go.mod +++ b/examples/zkp/xor_compat/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/zkp/xor_compat/go.sum b/examples/zkp/xor_compat/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/zkp/xor_compat/go.sum +++ b/examples/zkp/xor_compat/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/go.mod b/go.mod index 75cee142c..0b7590384 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/dbft v0.2.0 github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 github.com/nspcc-dev/rfc6979 v0.2.1 github.com/pierrec/lz4 v2.6.1+incompatible diff --git a/go.sum b/go.sum index b0e22e3b6..0b6fe0e15 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= diff --git a/internal/contracts/oracle_contract/go.mod b/internal/contracts/oracle_contract/go.mod index 2fe0af1fd..f6959e04b 100644 --- a/internal/contracts/oracle_contract/go.mod +++ b/internal/contracts/oracle_contract/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/internal/contracts/oracle_contract/go.sum b/internal/contracts/oracle_contract/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/internal/contracts/oracle_contract/go.sum +++ b/internal/contracts/oracle_contract/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=