From 1af936929093721ec274167829761ddba825c86c Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 26 Apr 2020 07:51:06 +0200 Subject: [PATCH] Add standard cryptography primitives (#1419) --- src/neo/Consensus/ConsensusService.cs | 5 +- src/neo/Cryptography/Crypto.cs | 78 +++++++++---- src/neo/Cryptography/ECC/ECDsa.cs | 107 ++++++++++++++++++ src/neo/SmartContract/Contract.cs | 4 +- src/neo/SmartContract/Helper.cs | 4 +- .../SmartContract/InteropService.Crypto.cs | 52 +++++++-- .../SmartContract/Manifest/ContractGroup.cs | 2 +- src/neo/Wallets/Wallet.cs | 4 +- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 16 +-- tests/neo.UnitTests/Cryptography/UT_Crypto.cs | 35 +++++- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 6 +- .../SmartContract/UT_Contract.cs | 12 +- .../UT_ContractParameterContext.cs | 12 +- .../SmartContract/UT_InteropService.NEO.cs | 14 +-- .../SmartContract/UT_InteropService.cs | 6 +- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 4 +- 16 files changed, 283 insertions(+), 78 deletions(-) create mode 100644 src/neo/Cryptography/ECC/ECDsa.cs diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 9e59ba7283..788719ae14 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -231,8 +231,7 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) { existingCommitPayload = payload; } - else if (Crypto.VerifySignature(hashData, commit.Signature, - context.Validators[payload.ValidatorIndex].EncodePoint(false))) + else if (Crypto.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex])) { existingCommitPayload = payload; CheckCommits(); @@ -433,7 +432,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m byte[] hashData = context.EnsureHeader().GetHashData(); for (int i = 0; i < context.CommitPayloads.Length; i++) if (context.CommitPayloads[i]?.ConsensusMessage.ViewNumber == context.ViewNumber) - if (!Crypto.VerifySignature(hashData, context.CommitPayloads[i].GetDeserializedMessage().Signature, context.Validators[i].EncodePoint(false))) + if (!Crypto.VerifySignature(hashData, context.CommitPayloads[i].GetDeserializedMessage().Signature, context.Validators[i])) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) diff --git a/src/neo/Cryptography/Crypto.cs b/src/neo/Cryptography/Crypto.cs index ee7b1418c8..ddd010cc63 100644 --- a/src/neo/Cryptography/Crypto.cs +++ b/src/neo/Cryptography/Crypto.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; using System.Security.Cryptography; namespace Neo.Cryptography @@ -32,38 +33,75 @@ public static byte[] Sign(byte[] message, byte[] prikey, byte[] pubkey) } } - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey) + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ECC.ECPoint pubkey) { - if (pubkey.Length == 33 && (pubkey[0] == 0x02 || pubkey[0] == 0x03)) + if (pubkey.Curve == ECC.ECCurve.Secp256r1) { - try + byte[] buffer = pubkey.EncodePoint(false); + using (var ecdsa = ECDsa.Create(new ECParameters { - pubkey = ECC.ECPoint.DecodePoint(pubkey, ECC.ECCurve.Secp256r1).EncodePoint(false).AsSpan(1); - } - catch + Curve = ECCurve.NamedCurves.nistP256, + Q = new ECPoint + { + X = buffer[1..33], + Y = buffer[33..] + } + })) { - return false; + return ecdsa.VerifyData(message, signature, HashAlgorithmName.SHA256); } } - else if (pubkey.Length == 65 && pubkey[0] == 0x04) - { - pubkey = pubkey[1..]; - } - else if (pubkey.Length != 64) + else { - throw new ArgumentException(); + var ecdsa = new ECC.ECDsa(pubkey); + var r = new BigInteger(signature[..32], true, true); + var s = new BigInteger(signature[32..], true, true); + return ecdsa.VerifySignature(message.Sha256(), r, s); } - using (var ecdsa = ECDsa.Create(new ECParameters + } + + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve) + { + if (curve == ECC.ECCurve.Secp256r1) { - Curve = ECCurve.NamedCurves.nistP256, - Q = new ECPoint + if (pubkey.Length == 33 && (pubkey[0] == 0x02 || pubkey[0] == 0x03)) { - X = pubkey[..32].ToArray(), - Y = pubkey[32..].ToArray() + try + { + pubkey = ECC.ECPoint.DecodePoint(pubkey, curve).EncodePoint(false).AsSpan(1); + } + catch + { + return false; + } } - })) + else if (pubkey.Length == 65 && pubkey[0] == 0x04) + { + pubkey = pubkey[1..]; + } + else + { + throw new ArgumentException(); + } + using (var ecdsa = ECDsa.Create(new ECParameters + { + Curve = ECCurve.NamedCurves.nistP256, + Q = new ECPoint + { + X = pubkey[..32].ToArray(), + Y = pubkey[32..].ToArray() + } + })) + { + return ecdsa.VerifyData(message, signature, HashAlgorithmName.SHA256); + } + } + else { - return ecdsa.VerifyData(message, signature, HashAlgorithmName.SHA256); + var ecdsa = new ECC.ECDsa(ECC.ECPoint.DecodePoint(pubkey, curve)); + var r = new BigInteger(signature[..32], true, true); + var s = new BigInteger(signature[32..], true, true); + return ecdsa.VerifySignature(message.Sha256(), r, s); } } } diff --git a/src/neo/Cryptography/ECC/ECDsa.cs b/src/neo/Cryptography/ECC/ECDsa.cs new file mode 100644 index 0000000000..08f48b1dc3 --- /dev/null +++ b/src/neo/Cryptography/ECC/ECDsa.cs @@ -0,0 +1,107 @@ +using System; +using System.Numerics; +using System.Security.Cryptography; + +namespace Neo.Cryptography.ECC +{ + public class ECDsa + { + private readonly byte[] privateKey; + private readonly ECPoint publicKey; + private readonly ECCurve curve; + + public ECDsa(byte[] privateKey, ECCurve curve) + : this(curve.G * privateKey) + { + this.privateKey = privateKey; + } + + public ECDsa(ECPoint publicKey) + { + this.publicKey = publicKey; + this.curve = publicKey.Curve; + } + + private BigInteger CalculateE(BigInteger n, ReadOnlySpan message) + { + int messageBitLength = message.Length * 8; + BigInteger trunc = new BigInteger(message, isUnsigned: true, isBigEndian: true); + if (n.GetBitLength() < messageBitLength) + { + trunc >>= messageBitLength - n.GetBitLength(); + } + return trunc; + } + + public BigInteger[] GenerateSignature(ReadOnlySpan message) + { + if (privateKey == null) throw new InvalidOperationException(); + BigInteger e = CalculateE(curve.N, message); + BigInteger d = new BigInteger(privateKey, isUnsigned: true, isBigEndian: true); + BigInteger r, s; + using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + { + do + { + BigInteger k; + do + { + do + { + k = rng.NextBigInteger(curve.N.GetBitLength()); + } + while (k.Sign == 0 || k.CompareTo(curve.N) >= 0); + ECPoint p = ECPoint.Multiply(curve.G, k); + BigInteger x = p.X.Value; + r = x.Mod(curve.N); + } + while (r.Sign == 0); + s = (k.ModInverse(curve.N) * (e + d * r)).Mod(curve.N); + if (s > curve.N / 2) + { + s = curve.N - s; + } + } + while (s.Sign == 0); + } + return new BigInteger[] { r, s }; + } + + private static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) + { + int m = Math.Max(k.GetBitLength(), l.GetBitLength()); + ECPoint Z = P + Q; + ECPoint R = P.Curve.Infinity; + for (int i = m - 1; i >= 0; --i) + { + R = R.Twice(); + if (k.TestBit(i)) + { + if (l.TestBit(i)) + R = R + Z; + else + R = R + P; + } + else + { + if (l.TestBit(i)) + R = R + Q; + } + } + return R; + } + + public bool VerifySignature(ReadOnlySpan message, BigInteger r, BigInteger s) + { + if (r.Sign < 1 || s.Sign < 1 || r.CompareTo(curve.N) >= 0 || s.CompareTo(curve.N) >= 0) + return false; + BigInteger e = CalculateE(curve.N, message); + BigInteger c = s.ModInverse(curve.N); + BigInteger u1 = (e * c).Mod(curve.N); + BigInteger u2 = (r * c).Mod(curve.N); + ECPoint point = SumOfTwoMultiplies(curve.G, u1, publicKey, u2); + BigInteger v = point.X.Value.Mod(curve.N); + return v.Equals(r); + } + } +} diff --git a/src/neo/SmartContract/Contract.cs b/src/neo/SmartContract/Contract.cs index 022e6a4c3f..32f409eab8 100644 --- a/src/neo/SmartContract/Contract.cs +++ b/src/neo/SmartContract/Contract.cs @@ -82,7 +82,7 @@ public static byte[] CreateMultiSigRedeemScript(int m, params ECPoint[] publicKe } sb.EmitPush(publicKeys.Length); sb.Emit(OpCode.PUSHNULL); - sb.EmitSysCall(InteropService.Crypto.ECDsaCheckMultiSig); + sb.EmitSysCall(InteropService.Crypto.CheckMultisigWithECDsaSecp256r1); return sb.ToArray(); } } @@ -102,7 +102,7 @@ public static byte[] CreateSignatureRedeemScript(ECPoint publicKey) { sb.EmitPush(publicKey.EncodePoint(true)); sb.Emit(OpCode.PUSHNULL); - sb.EmitSysCall(InteropService.Crypto.ECDsaVerify); + sb.EmitSysCall(InteropService.Crypto.VerifyWithECDsaSecp256r1); return sb.ToArray(); } } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index f2a506da6a..33c6b260cf 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -92,7 +92,7 @@ private static bool IsMultiSigContract(byte[] script, out int m, out int n, List if (script[i++] != (byte)OpCode.PUSHNULL) return false; if (script[i++] != (byte)OpCode.SYSCALL) return false; if (script.Length != i + 4) return false; - if (BitConverter.ToUInt32(script, i) != InteropService.Crypto.ECDsaCheckMultiSig) + if (BitConverter.ToUInt32(script, i) != InteropService.Crypto.CheckMultisigWithECDsaSecp256r1) return false; return true; } @@ -104,7 +104,7 @@ public static bool IsSignatureContract(this byte[] script) || script[1] != 33 || script[35] != (byte)OpCode.PUSHNULL || script[36] != (byte)OpCode.SYSCALL - || BitConverter.ToUInt32(script, 37) != InteropService.Crypto.ECDsaVerify) + || BitConverter.ToUInt32(script, 37) != InteropService.Crypto.VerifyWithECDsaSecp256r1) return false; return true; } diff --git a/src/neo/SmartContract/InteropService.Crypto.cs b/src/neo/SmartContract/InteropService.Crypto.cs index 9678f321ce..99b585885e 100644 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ b/src/neo/SmartContract/InteropService.Crypto.cs @@ -14,8 +14,12 @@ partial class InteropService { public static class Crypto { - public static readonly InteropDescriptor ECDsaVerify = Register("Neo.Crypto.ECDsaVerify", Crypto_ECDsaVerify, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ECDsaCheckMultiSig = Register("Neo.Crypto.ECDsaCheckMultiSig", Crypto_ECDsaCheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor SHA256 = Register("Neo.Crypto.SHA256", Crypto_SHA256, 0_01000000, TriggerType.All, CallFlags.None); + + public static readonly InteropDescriptor VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.ECDsa.Secp256r1.Verify", Crypto_ECDsaSecp256r1Verify, 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.ECDsa.Secp256k1.Verify", Crypto_ECDsaSecp256k1Verify, 0_01000000, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.ECDsa.Secp256r1.CheckMultiSig", Crypto_ECDsaSecp256r1CheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); + public static readonly InteropDescriptor CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.ECDsa.Secp256k1.CheckMultiSig", Crypto_ECDsaSecp256k1CheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack, StoreView snapshot) { @@ -25,10 +29,34 @@ private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack, StoreView if (item is Array array) n = array.Count; else n = (int)item.GetBigInteger(); if (n < 1) return 0; - return ECDsaVerify.Price * n; + return VerifyWithECDsaSecp256r1.Price * n; + } + + private static bool Crypto_SHA256(ApplicationEngine engine) + { + StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); + ReadOnlySpan value = item0 switch + { + InteropInterface _interface => _interface.GetInterface().GetHashData(), + Null _ => engine.ScriptContainer.GetHashData(), + _ => item0.GetSpan() + }; + + engine.CurrentContext.EvaluationStack.Push(value.ToArray().Sha256()); + return true; } - private static bool Crypto_ECDsaVerify(ApplicationEngine engine) + private static bool Crypto_ECDsaSecp256r1Verify(ApplicationEngine engine) + { + return Crypto_ECDsaVerify(engine, Cryptography.ECC.ECCurve.Secp256r1); + } + + private static bool Crypto_ECDsaSecp256k1Verify(ApplicationEngine engine) + { + return Crypto_ECDsaVerify(engine, Cryptography.ECC.ECCurve.Secp256k1); + } + + private static bool Crypto_ECDsaVerify(ApplicationEngine engine, Cryptography.ECC.ECCurve curve) { StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); ReadOnlySpan message = item0 switch @@ -41,7 +69,7 @@ private static bool Crypto_ECDsaVerify(ApplicationEngine engine) ReadOnlySpan signature = engine.CurrentContext.EvaluationStack.Pop().GetSpan(); try { - engine.CurrentContext.EvaluationStack.Push(Cryptography.Crypto.VerifySignature(message, signature, pubkey)); + engine.CurrentContext.EvaluationStack.Push(Cryptography.Crypto.VerifySignature(message, signature, pubkey, curve)); } catch (ArgumentException) { @@ -50,7 +78,17 @@ private static bool Crypto_ECDsaVerify(ApplicationEngine engine) return true; } - private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine) + private static bool Crypto_ECDsaSecp256r1CheckMultiSig(ApplicationEngine engine) + { + return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Secp256r1); + } + + private static bool Crypto_ECDsaSecp256k1CheckMultiSig(ApplicationEngine engine) + { + return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Secp256k1); + } + + private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine, Cryptography.ECC.ECCurve curve) { StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); ReadOnlySpan message = item0 switch @@ -98,7 +136,7 @@ private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine) { for (int i = 0, j = 0; fSuccess && i < m && j < n;) { - if (Cryptography.Crypto.VerifySignature(message, signatures[i], pubkeys[j])) + if (Cryptography.Crypto.VerifySignature(message, signatures[i], pubkeys[j], curve)) i++; j++; if (m - i > n - j) diff --git a/src/neo/SmartContract/Manifest/ContractGroup.cs b/src/neo/SmartContract/Manifest/ContractGroup.cs index c10bcba283..8cb6ced3b8 100644 --- a/src/neo/SmartContract/Manifest/ContractGroup.cs +++ b/src/neo/SmartContract/Manifest/ContractGroup.cs @@ -52,7 +52,7 @@ public static ContractGroup FromJson(JObject json) /// Return true or false public bool IsValid(UInt160 hash) { - return Crypto.VerifySignature(hash.ToArray(), Signature, PubKey.EncodePoint(false)); + return Crypto.VerifySignature(hash.ToArray(), Signature, PubKey); } public virtual JObject ToJson() diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 4831a82c96..56d0076140 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -346,7 +346,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) if (witness_script.IsSignatureContract()) { size += 67 + witness_script.GetVarSize(); - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.VerifyWithECDsaSecp256r1, null, null); } else if (witness_script.IsMultiSigContract(out int m, out int n)) { @@ -358,7 +358,7 @@ public static long CalculateNetworkFee(byte[] witness_script, ref int size) networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n; using (ScriptBuilder sb = new ScriptBuilder()) networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null) * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.VerifyWithECDsaSecp256r1, null, null) * n; } else { diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 4bdb0da2c5..1baf64acb8 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -10,6 +10,7 @@ using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.UnitTests.Cryptography; using Neo.Wallets; using System; @@ -18,7 +19,6 @@ using System.Reflection; using System.Security.Cryptography; using ECPoint = Neo.Cryptography.ECC.ECPoint; -using Neo.SmartContract.Native; namespace Neo.UnitTests.Consensus { @@ -153,8 +153,8 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Contract originalContract = Contract.CreateMultiSigContract(mockContext.Object.M, mockContext.Object.Validators); Console.WriteLine($"\nORIGINAL Contract is: {originalContract.ScriptHash}"); Console.WriteLine($"ORIGINAL NextConsensus: {mockContext.Object.Block.NextConsensus}\nENSURING values..."); - originalContract.ScriptHash.Should().Be(UInt160.Parse("0x9412c3107a59fa732ccd94866976f7bbb3d9c372")); - mockContext.Object.Block.NextConsensus.Should().Be(UInt160.Parse("0x9412c3107a59fa732ccd94866976f7bbb3d9c372")); + originalContract.ScriptHash.Should().Be(UInt160.Parse("0x7ab841144dcdbf228ff57f7068f795e2afd1a3c1")); + mockContext.Object.Block.NextConsensus.Should().Be(UInt160.Parse("0x7ab841144dcdbf228ff57f7068f795e2afd1a3c1")); Console.WriteLine("\n=========================="); Console.WriteLine("will trigger OnPersistCompleted again with OnStart flag!"); @@ -175,7 +175,7 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("will create template MakePrepareRequest..."); mockContext.Object.PrevHeader.Timestamp = defaultTimestamp; - mockContext.Object.PrevHeader.NextConsensus.Should().Be(UInt160.Parse("0x9412c3107a59fa732ccd94866976f7bbb3d9c372")); + mockContext.Object.PrevHeader.NextConsensus.Should().Be(UInt160.Parse("0x7ab841144dcdbf228ff57f7068f795e2afd1a3c1")); var prepReq = mockContext.Object.MakePrepareRequest(); var ppToSend = (PrepareRequest)prepReq.ConsensusMessage; // Forcing hashes to 0 because mempool is currently shared @@ -292,10 +292,10 @@ public void ConsensusService_SingleNodeActors_OnStart_PrepReq_PrepResponses_Comm Console.WriteLine("\nBasic commits Signatures verification"); // Basic tests for understanding signatures and ensuring signatures of commits are correct on tests var cmPayloadTemp = GetCommitPayloadModifiedAndSignedCopy(commitPayload, 6, kp_array[6], updatedBlockHashData); - Crypto.VerifySignature(originalBlockHashData, cm.Signature, mockContext.Object.Validators[0].EncodePoint(false)).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0].EncodePoint(false)).Should().BeFalse(); - Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6].EncodePoint(false)).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6].EncodePoint(false)).Should().BeTrue(); + Crypto.VerifySignature(originalBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0]).Should().BeFalse(); + Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6]).Should().BeTrue(); Console.WriteLine("\n=========================="); Console.WriteLine("\n=========================="); diff --git a/tests/neo.UnitTests/Cryptography/UT_Crypto.cs b/tests/neo.UnitTests/Cryptography/UT_Crypto.cs index 38f2006a7f..0154fea65a 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Crypto.cs @@ -44,21 +44,44 @@ public void TestVerifySignature() { byte[] message = System.Text.Encoding.Default.GetBytes("HelloWorld"); byte[] signature = Crypto.Sign(message, key.PrivateKey, key.PublicKey.EncodePoint(false).Skip(1).ToArray()); - Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false)).Should().BeTrue(); - Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false).Skip(1).ToArray()).Should().BeTrue(); - Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false).Skip(1).ToArray()).Should().BeTrue(); + Crypto.VerifySignature(message, signature, key.PublicKey).Should().BeTrue(); byte[] wrongKey = new byte[33]; wrongKey[0] = 0x02; - Crypto.VerifySignature(message, signature, wrongKey).Should().BeFalse(); + Crypto.VerifySignature(message, signature, wrongKey, Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); wrongKey[0] = 0x03; for (int i = 1; i < 33; i++) wrongKey[i] = byte.MaxValue; - Crypto.VerifySignature(message, signature, wrongKey).Should().BeFalse(); + Crypto.VerifySignature(message, signature, wrongKey, Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); wrongKey = new byte[36]; - Action action = () => Crypto.VerifySignature(message, signature, wrongKey).Should().BeFalse(); + Action action = () => Crypto.VerifySignature(message, signature, wrongKey, Neo.Cryptography.ECC.ECCurve.Secp256r1); action.Should().Throw(); } + + [TestMethod] + public void TestSecp256k1() + { + byte[] message = System.Text.Encoding.Default.GetBytes("hello"); + byte[] signature = "5331be791532d157df5b5620620d938bcb622ad02c81cfc184c460efdad18e695480d77440c511e9ad02ea30d773cb54e88f8cbb069644aefa283957085f38b5".HexToBytes(); + byte[] pubKey = "03ea01cb94bdaf0cd1c01b159d474f9604f4af35a3e2196f6bdfdb33b2aa4961fa".HexToBytes(); + + Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Secp256k1) + .Should().BeTrue(); + + message = System.Text.Encoding.Default.GetBytes("world"); + signature = "b1e6ff4f40536fb7ed706b0f7567903cc227a5241a079fb86f3de51b8321c1e690f37ad0c788848605c1653567935845f0d35a8a1a37174dcbbd235caac8e969".HexToBytes(); + pubKey = "03661b86d54eb3a8e7ea2399e0db36ab65753f95fff661da53ae0121278b881ad0".HexToBytes(); + + Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Secp256k1) + .Should().BeTrue(); + + message = System.Text.Encoding.Default.GetBytes("中文"); + signature = "b8cba1ff42304d74d083e87706058f59cdd4f755b995926d2cd80a734c5a3c37e4583bfd4339ac762c1c91eee3782660a6baf62cd29e407eccd3da3e9de55a02".HexToBytes(); + pubKey = "03661b86d54eb3a8e7ea2399e0db36ab65753f95fff661da53ae0121278b881ad0".HexToBytes(); + + Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Secp256k1) + .Should().BeTrue(); + } } } diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index b38c71e2a5..681e36489f 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -70,13 +70,13 @@ public void TestContainsTransaction() [TestMethod] public void TestGetCurrentBlockHash() { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xdba446947a90b2862ef050703b44828ad8b02d11978f8ef59bd3e1c97aabf6e5")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xc9387b803c8b4c6c1f69f6c876ed7848482c414b0225eb2a3a5395af39425455")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xdba446947a90b2862ef050703b44828ad8b02d11978f8ef59bd3e1c97aabf6e5")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xc9387b803c8b4c6c1f69f6c876ed7848482c414b0225eb2a3a5395af39425455")); } [TestMethod] @@ -88,7 +88,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xdba446947a90b2862ef050703b44828ad8b02d11978f8ef59bd3e1c97aabf6e5")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xc9387b803c8b4c6c1f69f6c876ed7848482c414b0225eb2a3a5395af39425455")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } diff --git a/tests/neo.UnitTests/SmartContract/UT_Contract.cs b/tests/neo.UnitTests/SmartContract/UT_Contract.cs index 294094ccae..ee943c6477 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Contract.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Contract.cs @@ -26,7 +26,7 @@ public void TestGetAddress() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.ECDsaVerify), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); Assert.AreEqual(expectedArray.ToScriptHash().ToAddress(), contract.Address); } @@ -44,7 +44,7 @@ public void TestGetScriptHash() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.ECDsaVerify), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); Assert.AreEqual(expectedArray.ToScriptHash(), contract.ScriptHash); } @@ -86,7 +86,7 @@ public void TestCreateMultiSigContract() expectedArray[71] = (byte)OpCode.PUSH2; expectedArray[72] = (byte)OpCode.PUSHNULL; expectedArray[73] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.ECDsaCheckMultiSig), 0, expectedArray, 74, 4); + Array.Copy(BitConverter.GetBytes(InteropService.Crypto.CheckMultisigWithECDsaSecp256r1), 0, expectedArray, 74, 4); CollectionAssert.AreEqual(expectedArray, contract.Script); Assert.AreEqual(2, contract.ParameterList.Length); Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); @@ -122,7 +122,7 @@ public void TestCreateMultiSigRedeemScript() expectedArray[71] = (byte)OpCode.PUSH2; expectedArray[72] = (byte)OpCode.PUSHNULL; expectedArray[73] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.ECDsaCheckMultiSig), 0, expectedArray, 74, 4); + Array.Copy(BitConverter.GetBytes(InteropService.Crypto.CheckMultisigWithECDsaSecp256r1), 0, expectedArray, 74, 4); CollectionAssert.AreEqual(expectedArray, script); } @@ -140,7 +140,7 @@ public void TestCreateSignatureContract() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.ECDsaVerify), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); CollectionAssert.AreEqual(expectedArray, contract.Script); Assert.AreEqual(1, contract.ParameterList.Length); Assert.AreEqual(ContractParameterType.Signature, contract.ParameterList[0]); @@ -160,7 +160,7 @@ public void TestCreateSignatureRedeemScript() Array.Copy(key.PublicKey.EncodePoint(true), 0, expectedArray, 2, 33); expectedArray[35] = (byte)OpCode.PUSHNULL; expectedArray[36] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(InteropService.Crypto.ECDsaVerify), 0, expectedArray, 37, 4); + Array.Copy(BitConverter.GetBytes(InteropService.Crypto.VerifyWithECDsaSecp256r1), 0, expectedArray, 37, 4); CollectionAssert.AreEqual(expectedArray, script); } } diff --git a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index f5110b00ea..bfb0a53391 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -47,7 +47,7 @@ public void TestToString() var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); string str = context.ToString(); - str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAABmUJDLobcPtqo9vZKIdjXsd8fVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA=="",""items"":{""0x1bd5c777ec35768892bd3daab60fb7a1cb905066"":{""script"":""DCECb/A7lJJBzh2t1DUZ5pYOCoW0GmmgXDKBA6orzhWUyhYLQQqQatQ="",""parameters"":[{""type"":""Signature"",""value"":""AQ==""}]}}}"); + str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAABmUJDLobcPtqo9vZKIdjXsd8fVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA=="",""items"":{}}"); } [TestMethod] @@ -72,7 +72,7 @@ public void TestAdd() var context1 = new ContractParametersContext(tx); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + tx.Sender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); var context2 = new ContractParametersContext(tx); context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); //test repeatlly createItem @@ -83,7 +83,7 @@ public void TestAdd() public void TestGetParameter() { Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + tx.Sender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); var context = new ContractParametersContext(tx); context.GetParameter(tx.Sender, 0).Should().BeNull(); @@ -96,7 +96,7 @@ public void TestGetParameter() public void TestGetWitnesses() { Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + tx.Sender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); Witness[] witnesses = context.GetWitnesses(); @@ -109,7 +109,7 @@ public void TestGetWitnesses() public void TestAddSignature() { Transaction tx = TestUtils.GetTransaction(); - var singleSender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + var singleSender = UInt160.Parse("0xcd4ced947d791e887559b3829c3bc08fe37b0a64"); tx.Sender = singleSender; //singleSign @@ -139,7 +139,7 @@ public void TestAddSignature() key.PublicKey, key2.PublicKey }); - var multiSender = UInt160.Parse("0xd8e21c5f8b2e48c409220a3aff34a7fc4c87fbe9"); + var multiSender = UInt160.Parse("0x6bb1ea23cefb73dd959775c035a114018c2c1119"); tx.Sender = multiSender; context = new ContractParametersContext(tx); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 914e6bb012..84c80288d4 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -35,13 +35,13 @@ public void TestCheckSig() engine.CurrentContext.EvaluationStack.Push(signature); engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(false)); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaVerify).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); engine.CurrentContext.EvaluationStack.Push(signature); engine.CurrentContext.EvaluationStack.Push(new byte[70]); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaVerify).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); } @@ -77,14 +77,14 @@ public void TestCrypto_CheckMultiSig() engine.CurrentContext.EvaluationStack.Push(signatures); engine.CurrentContext.EvaluationStack.Push(pubkeys); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaCheckMultiSig).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); pubkeys = new VMArray(); engine.CurrentContext.EvaluationStack.Push(signatures); engine.CurrentContext.EvaluationStack.Push(pubkeys); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaCheckMultiSig).Should().BeFalse(); + InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeFalse(); pubkeys = new VMArray { @@ -95,7 +95,7 @@ public void TestCrypto_CheckMultiSig() engine.CurrentContext.EvaluationStack.Push(signatures); engine.CurrentContext.EvaluationStack.Push(pubkeys); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaCheckMultiSig).Should().BeFalse(); + InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeFalse(); pubkeys = new VMArray { @@ -110,7 +110,7 @@ public void TestCrypto_CheckMultiSig() engine.CurrentContext.EvaluationStack.Push(signatures); engine.CurrentContext.EvaluationStack.Push(pubkeys); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaCheckMultiSig).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); pubkeys = new VMArray @@ -126,7 +126,7 @@ public void TestCrypto_CheckMultiSig() engine.CurrentContext.EvaluationStack.Push(signatures); engine.CurrentContext.EvaluationStack.Push(pubkeys); engine.CurrentContext.EvaluationStack.Push(StackItem.Null); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaCheckMultiSig).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.CheckMultisigWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 5fb8cc4220..b599016336 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -391,7 +391,7 @@ public void TestCrypto_Verify() engine.CurrentContext.EvaluationStack.Push(signature); engine.CurrentContext.EvaluationStack.Push(pubkey.EncodePoint(false)); engine.CurrentContext.EvaluationStack.Push(message); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaVerify).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); byte[] wrongkey = pubkey.EncodePoint(false); @@ -399,7 +399,7 @@ public void TestCrypto_Verify() engine.CurrentContext.EvaluationStack.Push(signature); engine.CurrentContext.EvaluationStack.Push(wrongkey); engine.CurrentContext.EvaluationStack.Push(new InteropInterface(engine.ScriptContainer)); - InteropService.Invoke(engine, InteropService.Crypto.ECDsaVerify).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Peek().ToBoolean().Should().BeFalse(); } @@ -879,7 +879,7 @@ public void TestContract_CreateStandardAccount() engine.CurrentContext.EvaluationStack.Push(data); InteropService.Invoke(engine, InteropService.Contract.CreateStandardAccount).Should().BeTrue(); - engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().Should().BeEquivalentTo(UInt160.Parse("0x2c847208959ec1cc94dd13bfe231fa622a404a8a").ToArray()); + engine.CurrentContext.EvaluationStack.Pop().GetSpan().ToArray().ToHexString().Should().Be("68f96a15748750cccd548feb71be766e8a2c2733"); data = "064b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e".HexToBytes(); engine.CurrentContext.EvaluationStack.Push(data); diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 63ddb327fe..091caa2b65 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -171,9 +171,9 @@ public void TestGetVersion() public void TestGetAccount1() { MyWallet wallet = new MyWallet(); - wallet.CreateAccount(UInt160.Parse("0x7e471cf52f27edc291e29ec8f2d1ea2d210d6725")); + wallet.CreateAccount(UInt160.Parse("0xb3f1526d9f9670df1a21a5953d5296c3a9c9173c")); WalletAccount account = wallet.GetAccount(ECCurve.Secp256r1.G); - account.ScriptHash.Should().Be(UInt160.Parse("0x7e471cf52f27edc291e29ec8f2d1ea2d210d6725")); + account.ScriptHash.Should().Be(UInt160.Parse("0xb3f1526d9f9670df1a21a5953d5296c3a9c9173c")); } [TestMethod]