From b77b5ede40785293588552033f94bc8fd302060d Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 3 May 2024 16:18:11 +0300 Subject: [PATCH] Native: extend CryptoLib's verifyWithECDsa with hasher parameter A port of https://github.com/nspcc-dev/neo-go/pull/3425/commits/1e2b438b5580ca9ada7b452130b95a249733d31a. This commit contains minor protocol extension needed for custom Koblitz-based verification scripts (an alternative to https://github.com/neo-project/neo/pull/3205). Replace native CryptoLib's verifyWithECDsa `curve` parameter by `curveHash` parameter which is a enum over supported pairs of named curves and hash functions. NamedCurve enum mark as deprecated and replaced by NamedCurveHash with compatible behaviour. Even though this change is a compatible extension of the protocol, it changes the genesis state due to parameter renaming (CryptoLib's manifest is changed). 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 --- src/Neo/Cryptography/Crypto.cs | 61 ++++++++++++++----- src/Neo/Cryptography/Hasher.cs | 29 +++++++++ src/Neo/Cryptography/Helper.cs | 35 +++++++++++ src/Neo/SmartContract/Native/CryptoLib.cs | 22 +++---- src/Neo/SmartContract/Native/NamedCurve.cs | 8 ++- .../SmartContract/Native/NamedCurveHash.cs | 43 +++++++++++++ .../SmartContract/Native/UT_NativeContract.cs | 2 +- 7 files changed, 170 insertions(+), 30 deletions(-) create mode 100644 src/Neo/Cryptography/Hasher.cs create mode 100644 src/Neo/SmartContract/Native/NamedCurveHash.cs diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index e419d268a2..377edfe6c0 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -28,6 +28,7 @@ public static class Crypto private static readonly bool IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); private static readonly ECCurve secP256k1 = ECCurve.CreateFromFriendlyName("secP256k1"); private static readonly X9ECParameters bouncySecp256k1 = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1"); + private static readonly X9ECParameters bouncySecp256r1 = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256r1"); /// /// Calculates the 160-bit hash value of the specified message. @@ -50,22 +51,30 @@ public static byte[] Hash256(ReadOnlySpan message) } /// - /// Signs the specified message using the ECDSA algorithm. + /// Signs the specified message using the ECDSA algorithm and specified hash algorithm. /// /// The message to be signed. /// The private key to be used. /// The curve of the signature, default is . + /// The hash algorithm to hash the message, default is SHA256. /// The ECDSA signature for the specified message. - public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = null) + public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = null, Hasher hasher = Hasher.SHA256) { - if (IsOSX && ecCurve == ECC.ECCurve.Secp256k1) + if (hasher == Hasher.Keccak256 || (IsOSX && ecCurve == ECC.ECCurve.Secp256k1)) { - var domain = new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H); + var domain = + ecCurve == null || ecCurve == ECC.ECCurve.Secp256r1 ? new ECDomainParameters(bouncySecp256r1.Curve, bouncySecp256r1.G, bouncySecp256r1.N, bouncySecp256r1.H) : + ecCurve == ECC.ECCurve.Secp256k1 ? new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H) : + throw new NotSupportedException(nameof(ecCurve)); var signer = new Org.BouncyCastle.Crypto.Signers.ECDsaSigner(); var privateKey = new BigInteger(1, priKey); var priKeyParameters = new ECPrivateKeyParameters(privateKey, domain); signer.Init(true, priKeyParameters); - var signature = signer.GenerateSignature(message.Sha256()); + var messageHash = + hasher == Hasher.SHA256 ? message.Sha256() : + hasher == Hasher.Keccak256 ? message.Keccak256() : + throw new NotSupportedException(nameof(hasher)); + var signature = signer.GenerateSignature(messageHash); var signatureBytes = new byte[64]; var rBytes = signature[0].ToByteArrayUnsigned(); @@ -87,24 +96,35 @@ public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = n Curve = curve, D = priKey, }); - return ecdsa.SignData(message, HashAlgorithmName.SHA256); + var hashAlg = + hasher == Hasher.SHA256 ? HashAlgorithmName.SHA256 : + throw new NotSupportedException(nameof(hasher)); + return ecdsa.SignData(message, hashAlg); } /// - /// Verifies that a digital signature is appropriate for the provided key and message. + /// Verifies that a digital signature is appropriate for the provided key, message and hash algorithm. /// /// The signed message. /// The signature to be verified. /// The public key to be used. + /// The hash algorithm to be used to hash the message, the default is SHA256. /// if the signature is valid; otherwise, . - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ECC.ECPoint pubkey) + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ECC.ECPoint pubkey, Hasher hasher = Hasher.SHA256) { if (signature.Length != 64) return false; - if (IsOSX && pubkey.Curve == ECC.ECCurve.Secp256k1) + if (hasher == Hasher.Keccak256 || (IsOSX && pubkey.Curve == ECC.ECCurve.Secp256k1)) { - var domain = new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H); - var point = bouncySecp256k1.Curve.CreatePoint( + var domain = + pubkey.Curve == ECC.ECCurve.Secp256r1 ? new ECDomainParameters(bouncySecp256r1.Curve, bouncySecp256r1.G, bouncySecp256r1.N, bouncySecp256r1.H) : + pubkey.Curve == ECC.ECCurve.Secp256k1 ? new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H) : + throw new NotSupportedException(nameof(pubkey.Curve)); + var curve = + pubkey.Curve == ECC.ECCurve.Secp256r1 ? bouncySecp256r1.Curve : + bouncySecp256k1.Curve; + + var point = curve.CreatePoint( new BigInteger(pubkey.X.Value.ToString()), new BigInteger(pubkey.Y.Value.ToString())); var pubKey = new ECPublicKeyParameters("ECDSA", point, domain); @@ -115,11 +135,19 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan @@ -153,16 +181,17 @@ public static ECDsa CreateECDsa(ECC.ECPoint pubkey) } /// - /// Verifies that a digital signature is appropriate for the provided key and message. + /// Verifies that a digital signature is appropriate for the provided key, curve, message and hasher. /// /// The signed message. /// The signature to be verified. /// The public key to be used. /// The curve to be used by the ECDSA algorithm. + /// The hash algorithm to be used hash the message, the default is SHA256. /// if the signature is valid; otherwise, . - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve) + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve, Hasher hasher = Hasher.SHA256) { - return VerifySignature(message, signature, ECC.ECPoint.DecodePoint(pubkey, curve)); + return VerifySignature(message, signature, ECC.ECPoint.DecodePoint(pubkey, curve), hasher); } } } diff --git a/src/Neo/Cryptography/Hasher.cs b/src/Neo/Cryptography/Hasher.cs new file mode 100644 index 0000000000..21c5fef6a8 --- /dev/null +++ b/src/Neo/Cryptography/Hasher.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Hasher.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Cryptography +{ + /// + /// Represents hash function identifiers supported by ECDSA message signature and verification. + /// + public enum Hasher : byte + { + /// + /// The SHA256 hash algorithm. + /// + SHA256 = 0x00, + + /// + /// The Keccak256 hash algorithm. + /// + Keccak256 = 0x01, + } +} diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index a087620034..f13fa08118 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -12,6 +12,7 @@ using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Wallets; +using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; @@ -153,6 +154,40 @@ public static byte[] Sha256(this Span value) return Sha256((ReadOnlySpan)value); } + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// The computed hash code. + public static byte[] Keccak256(this byte[] value) + { + KeccakDigest keccak = new(256); + keccak.BlockUpdate(value, 0, value.Length); + byte[] result = new byte[keccak.GetDigestSize()]; + keccak.DoFinal(result, 0); + return result; + } + + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// The computed hash code. + public static byte[] Keccak256(this ReadOnlySpan value) + { + return Keccak256(value.ToArray()); + } + + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// The computed hash code. + public static byte[] Keccak256(this Span value) + { + return Keccak256(value.ToArray()); + } + public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] nonce, byte[] associatedData = null) { if (nonce.Length != 12) throw new ArgumentOutOfRangeException(nameof(nonce)); diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index a7b822e39c..ad6fc93eec 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -11,7 +11,6 @@ using Neo.Cryptography; using Neo.Cryptography.ECC; -using Org.BouncyCastle.Crypto.Digests; using System; using System.Collections.Generic; @@ -22,10 +21,12 @@ namespace Neo.SmartContract.Native /// public sealed partial class CryptoLib : NativeContract { - private static readonly Dictionary curves = new() + private static readonly Dictionary curves = new() { - [NamedCurve.secp256k1] = ECCurve.Secp256k1, - [NamedCurve.secp256r1] = ECCurve.Secp256r1 + [NamedCurveHash.secp256k1SHA256] = (ECCurve.Secp256k1, Hasher.SHA256), + [NamedCurveHash.secp256r1SHA256] = (ECCurve.Secp256r1, Hasher.SHA256), + [NamedCurveHash.secp256k1Keccak256] = (ECCurve.Secp256k1, Hasher.Keccak256), + [NamedCurveHash.secp256r1Keccak256] = (ECCurve.Secp256r1, Hasher.Keccak256), }; internal CryptoLib() : base() { } @@ -73,11 +74,7 @@ public static byte[] Murmur32(byte[] data, uint seed) [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] public static byte[] Keccak256(byte[] data) { - KeccakDigest keccak = new(256); - keccak.BlockUpdate(data, 0, data.Length); - byte[] result = new byte[keccak.GetDigestSize()]; - keccak.DoFinal(result, 0); - return result; + return data.Keccak256(); } /// @@ -86,14 +83,15 @@ public static byte[] Keccak256(byte[] data) /// The signed message. /// The public key to be used. /// The signature to be verified. - /// The curve to be used by the ECDSA algorithm. + /// A pair of the curve to be used by the ECDSA algorithm and the hasher function to be used to hash message. /// if the signature is valid; otherwise, . [ContractMethod(CpuFee = 1 << 15)] - public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurve curve) + public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurveHash curveHash) { try { - return Crypto.VerifySignature(message, signature, pubkey, curves[curve]); + var ch = curves[curveHash]; + return Crypto.VerifySignature(message, signature, pubkey, ch.Item1, ch.Item2); } catch (ArgumentException) { diff --git a/src/Neo/SmartContract/Native/NamedCurve.cs b/src/Neo/SmartContract/Native/NamedCurve.cs index 9e97472cfc..8c7a9107e9 100644 --- a/src/Neo/SmartContract/Native/NamedCurve.cs +++ b/src/Neo/SmartContract/Native/NamedCurve.cs @@ -9,24 +9,30 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; + namespace Neo.SmartContract.Native { /// - /// Represents the named curve used in ECDSA. + /// Represents the named curve used in ECDSA. This enum is obsolete + /// and will be removed in future versions. Please, use an extended instead. /// /// /// https://tools.ietf.org/html/rfc4492#section-5.1.1 /// + [Obsolete("NamedCurve enum is obsolete and will be removed in future versions. Please, use an extended NamedCurveHash instead.")] public enum NamedCurve : byte { /// /// The secp256k1 curve. /// + [Obsolete("secp256k1 value is obsolete and will be removed in future versions. Please, use NamedCurveHash.secp256k1SHA256 for compatible behaviour.")] secp256k1 = 22, /// /// The secp256r1 curve, which known as prime256v1 or nistP-256. /// + [Obsolete("secp256r1 value is obsolete and will be removed in future versions. Please, use NamedCurveHash.secp256r1SHA256 for compatible behaviour.")] secp256r1 = 23 } } diff --git a/src/Neo/SmartContract/Native/NamedCurveHash.cs b/src/Neo/SmartContract/Native/NamedCurveHash.cs new file mode 100644 index 0000000000..d4dcae6491 --- /dev/null +++ b/src/Neo/SmartContract/Native/NamedCurveHash.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NamedCurveHash.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.SmartContract.Native +{ + /// + /// Represents a pair of the named curve used in ECDSA and a hash algorithm used to hash message. + /// This is a compatible extension of an obsolete enum. + /// + /// + /// https://tools.ietf.org/html/rfc4492#section-5.1.1 + /// + public enum NamedCurveHash : byte + { + /// + /// The secp256k1 curve and SHA256 hash algorithm. + /// + secp256k1SHA256 = 22, + + /// + /// The secp256r1 curve, which known as prime256v1 or nistP-256, and SHA256 hash algorithm. + /// + secp256r1SHA256 = 23, + + /// + /// The secp256k1 curve and Keccak256 hash algorithm. + /// + secp256k1Keccak256 = 24, + + /// + /// The secp256r1 curve, which known as prime256v1 or nistP-256, and Keccak256 hash algorithm. + /// + secp256r1Keccak256 = 25 + } +} diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 181ff139ec..d7be3b4dcd 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -42,7 +42,7 @@ public void TestSetup() { {"ContractManagement", """{"id":-1,"updatecounter":0,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","offset":0,"safe":false},{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","offset":7,"safe":false},{"name":"destroy","parameters":[],"returntype":"Void","offset":14,"safe":false},{"name":"getContract","parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","offset":21,"safe":true},{"name":"getContractById","parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getContractHashes","parameters":[],"returntype":"InteropInterface","offset":35,"safe":true},{"name":"getMinimumDeploymentFee","parameters":[],"returntype":"Integer","offset":42,"safe":true},{"name":"hasMethod","parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","offset":49,"safe":true},{"name":"setMinimumDeploymentFee","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":56,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","offset":63,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","offset":70,"safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}""" }, {"StdLib", """{"id":-2,"updatecounter":0,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"atoi","parameters":[{"name":"value","type":"String"}],"returntype":"Integer","offset":0,"safe":true},{"name":"atoi","parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"base58CheckDecode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":14,"safe":true},{"name":"base58CheckEncode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":21,"safe":true},{"name":"base58Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":28,"safe":true},{"name":"base58Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":35,"safe":true},{"name":"base64Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"base64Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":49,"safe":true},{"name":"deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","offset":56,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"}],"returntype":"String","offset":63,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","offset":70,"safe":true},{"name":"jsonDeserialize","parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","offset":77,"safe":true},{"name":"jsonSerialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":84,"safe":true},{"name":"memoryCompare","parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","offset":91,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","offset":98,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","offset":105,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","offset":112,"safe":true},{"name":"serialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":119,"safe":true},{"name":"strLen","parameters":[{"name":"str","type":"String"}],"returntype":"Integer","offset":126,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","offset":133,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","offset":140,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, - {"CryptoLib", """{"id":-3,"updatecounter":0,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"bls12381Add","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","offset":0,"safe":true},{"name":"bls12381Deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","offset":7,"safe":true},{"name":"bls12381Equal","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","offset":14,"safe":true},{"name":"bls12381Mul","parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"bls12381Pairing","parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","offset":28,"safe":true},{"name":"bls12381Serialize","parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","offset":35,"safe":true},{"name":"keccak256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"murmur32","parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","offset":49,"safe":true},{"name":"ripemd160","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":56,"safe":true},{"name":"sha256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":63,"safe":true},{"name":"verifyWithECDsa","parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","offset":70,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"CryptoLib", """{"id":-3,"updatecounter":0,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"bls12381Add","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","offset":0,"safe":true},{"name":"bls12381Deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","offset":7,"safe":true},{"name":"bls12381Equal","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","offset":14,"safe":true},{"name":"bls12381Mul","parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"bls12381Pairing","parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","offset":28,"safe":true},{"name":"bls12381Serialize","parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","offset":35,"safe":true},{"name":"keccak256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"murmur32","parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","offset":49,"safe":true},{"name":"ripemd160","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":56,"safe":true},{"name":"sha256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":63,"safe":true},{"name":"verifyWithECDsa","parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","offset":70,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"LedgerContract", """{"id":-4,"updatecounter":0,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"currentHash","parameters":[],"returntype":"Hash256","offset":0,"safe":true},{"name":"currentIndex","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlock","parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","offset":14,"safe":true},{"name":"getTransaction","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":21,"safe":true},{"name":"getTransactionFromBlock","parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getTransactionHeight","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":35,"safe":true},{"name":"getTransactionSigners","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":42,"safe":true},{"name":"getTransactionVMState","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":49,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"NeoToken", """{"id":-5,"updatecounter":0,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getAccountState","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","offset":14,"safe":true},{"name":"getAllCandidates","parameters":[],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"getCandidateVote","parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","offset":28,"safe":true},{"name":"getCandidates","parameters":[],"returntype":"Array","offset":35,"safe":true},{"name":"getCommittee","parameters":[],"returntype":"Array","offset":42,"safe":true},{"name":"getCommitteeAddress","parameters":[],"returntype":"Hash160","offset":49,"safe":true},{"name":"getGasPerBlock","parameters":[],"returntype":"Integer","offset":56,"safe":true},{"name":"getNextBlockValidators","parameters":[],"returntype":"Array","offset":63,"safe":true},{"name":"getRegisterPrice","parameters":[],"returntype":"Integer","offset":70,"safe":true},{"name":"registerCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":77,"safe":false},{"name":"setGasPerBlock","parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","offset":84,"safe":false},{"name":"setRegisterPrice","parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","offset":91,"safe":false},{"name":"symbol","parameters":[],"returntype":"String","offset":98,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":105,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":112,"safe":false},{"name":"unclaimedGas","parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","offset":119,"safe":true},{"name":"unregisterCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":126,"safe":false},{"name":"vote","parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","offset":133,"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"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"GasToken", """{"id":-6,"updatecounter":0,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""},