From ce996bd761b159c352fe405dd730a59f4eb787c0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 15 Jan 2020 19:34:48 +0100 Subject: [PATCH 01/11] Add Secp256k1 --- src/neo/Cryptography/Crypto.cs | 25 +++++++++++-- src/neo/Cryptography/ECC/ECCurve.cs | 6 ++++ src/neo/SmartContract/Contract.cs | 4 +-- src/neo/SmartContract/Helper.cs | 4 +-- .../SmartContract/InteropService.Crypto.cs | 36 +++++++++++++++---- src/neo/Wallets/Wallet.cs | 4 +-- .../SmartContract/UT_Contract.cs | 12 +++---- .../SmartContract/UT_InteropService.NEO.cs | 14 ++++---- .../SmartContract/UT_InteropService.cs | 4 +-- 9 files changed, 78 insertions(+), 31 deletions(-) diff --git a/src/neo/Cryptography/Crypto.cs b/src/neo/Cryptography/Crypto.cs index ee7b1418c8..c6b20462ff 100644 --- a/src/neo/Cryptography/Crypto.cs +++ b/src/neo/Cryptography/Crypto.cs @@ -32,13 +32,22 @@ 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, ReadOnlySpan pubkey, ECC.ECCurve.Curve curve = ECC.ECCurve.Curve.Secp256r1) { if (pubkey.Length == 33 && (pubkey[0] == 0x02 || pubkey[0] == 0x03)) { try { - pubkey = ECC.ECPoint.DecodePoint(pubkey, ECC.ECCurve.Secp256r1).EncodePoint(false).AsSpan(1); + switch (curve) + { + case ECC.ECCurve.Curve.Secp256r1: + pubkey = ECC.ECPoint.DecodePoint(pubkey, ECC.ECCurve.Secp256r1).EncodePoint(false).AsSpan(1); + break; + case ECC.ECCurve.Curve.Secp256k1: + pubkey = ECC.ECPoint.DecodePoint(pubkey, ECC.ECCurve.Secp256k1).EncodePoint(false).AsSpan(1); + break; + default: return false; + } } catch { @@ -53,9 +62,19 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan message = item0 switch @@ -40,7 +52,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) { @@ -49,7 +61,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.Curve.Secp256r1); + } + + private static bool Crypto_ECDsaSecp256k1CheckMultiSig(ApplicationEngine engine) + { + return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Curve.Secp256k1); + } + + private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine, Cryptography.ECC.ECCurve.Curve curve) { StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); ReadOnlySpan message = item0 switch @@ -97,7 +119,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/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 892cc40c1c..ec4dce0f19 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -354,7 +354,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); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaSecp256r1Verify, null); } else if (witness_script.IsMultiSigContract(out int m, out int n)) { @@ -366,7 +366,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) * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaSecp256r1Verify, null) * n; } else { diff --git a/tests/neo.UnitTests/SmartContract/UT_Contract.cs b/tests/neo.UnitTests/SmartContract/UT_Contract.cs index 294094ccae..3827eab606 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.ECDsaSecp256r1Verify), 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.ECDsaSecp256r1Verify), 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.ECDsaSecp256r1CheckMultiSig), 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.ECDsaSecp256r1CheckMultiSig), 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.ECDsaSecp256r1Verify), 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.ECDsaSecp256r1Verify), 0, expectedArray, 37, 4); CollectionAssert.AreEqual(expectedArray, script); } } diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 959eeecae8..dfd4fa6ff4 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -34,13 +34,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.ECDsaSecp256r1Verify).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.ECDsaSecp256r1Verify).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); } @@ -76,14 +76,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.ECDsaSecp256r1CheckMultiSig).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.ECDsaSecp256r1CheckMultiSig).Should().BeFalse(); pubkeys = new VMArray { @@ -94,7 +94,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.ECDsaSecp256r1CheckMultiSig).Should().BeFalse(); pubkeys = new VMArray { @@ -109,7 +109,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.ECDsaSecp256r1CheckMultiSig).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeFalse(); pubkeys = new VMArray @@ -125,7 +125,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.ECDsaSecp256r1CheckMultiSig).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 1fa676af60..97d24f3950 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -382,7 +382,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.ECDsaSecp256r1Verify).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Pop().ToBoolean().Should().BeTrue(); byte[] wrongkey = pubkey.EncodePoint(false); @@ -390,7 +390,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.ECDsaSecp256r1Verify).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Peek().ToBoolean().Should().BeFalse(); } From dde07619f8b0bb071cb9ebac8e8dc6949c012e23 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 15 Jan 2020 19:53:19 +0100 Subject: [PATCH 02/11] Crypto_SHA3Keccak256 --- .../SmartContract/InteropService.Crypto.cs | 36 +++++++++++++++++++ src/neo/neo.csproj | 1 + 2 files changed, 37 insertions(+) diff --git a/src/neo/SmartContract/InteropService.Crypto.cs b/src/neo/SmartContract/InteropService.Crypto.cs index acd96c77af..74bec64e9a 100644 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ b/src/neo/SmartContract/InteropService.Crypto.cs @@ -3,6 +3,7 @@ using Neo.Network.P2P.Payloads; using Neo.VM; using Neo.VM.Types; +using Org.BouncyCastle.Crypto.Digests; using System; using System.Linq; using Array = Neo.VM.Types.Array; @@ -13,6 +14,9 @@ partial class InteropService { public static class Crypto { + public static readonly InteropDescriptor SHA3Keccak256 = Register("Neo.Crypto.SHA3.Keccak256", Crypto_SHA3Keccak256, 0_01000000, 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 ECDsaSecp256r1Verify = Register("Neo.Crypto.ECDsa.Secp256r1.Verify", Crypto_ECDsaSecp256r1Verify, 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor ECDsaSecp256k1Verify = Register("Neo.Crypto.ECDsa.Secp256k1.Verify", Crypto_ECDsaSecp256k1Verify, 0_01000000, TriggerType.All, CallFlags.None); public static readonly InteropDescriptor ECDsaSecp256r1CheckMultiSig = Register("Neo.Crypto.ECDsa.Secp256r1.CheckMultiSig", Crypto_ECDsaSecp256r1CheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); @@ -29,6 +33,38 @@ private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack) return ECDsaSecp256r1Verify.Price * n; } + private static bool Crypto_SHA3Keccak256(ApplicationEngine engine) + { + StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); + ReadOnlySpan value = item0 switch + { + InteropInterface _interface => _interface.GetInterface().GetHashData(), + Null _ => engine.ScriptContainer.GetHashData(), + _ => item0.GetSpan() + }; + + var digest = new KeccakDigest(256); + var output = new byte[digest.GetDigestSize()]; + digest.BlockUpdate(value.ToArray(), 0, value.Length); + digest.DoFinal(output, 0); + engine.CurrentContext.EvaluationStack.Push(output); + return true; + } + + 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_ECDsaSecp256r1Verify(ApplicationEngine engine) { return Crypto_ECDsaVerify(engine, Cryptography.ECC.ECCurve.Curve.Secp256r1); diff --git a/src/neo/neo.csproj b/src/neo/neo.csproj index 075d17fb7f..b3c5d82652 100644 --- a/src/neo/neo.csproj +++ b/src/neo/neo.csproj @@ -22,6 +22,7 @@ + From 225ea651c976af6aa58e916ea4351761780c85a9 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 10 Mar 2020 17:50:54 +0100 Subject: [PATCH 03/11] Recover old verify, and use it instead of Bouncy Castle --- src/neo/Cryptography/Crypto.cs | 43 +++++++++------- src/neo/Cryptography/ECC/ECCurve.cs | 49 +++++++++++++++++++ .../SmartContract/InteropService.Crypto.cs | 20 -------- src/neo/neo.csproj | 1 - tests/neo.UnitTests/Cryptography/UT_Crypto.cs | 25 ++++++++++ 5 files changed, 100 insertions(+), 38 deletions(-) diff --git a/src/neo/Cryptography/Crypto.cs b/src/neo/Cryptography/Crypto.cs index c6b20462ff..491aeeaf57 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 @@ -63,26 +64,34 @@ public static bool VerifySignature(ReadOnlySpan message, 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 bool VerifySignature(ReadOnlySpan message, ECPoint publicKey, BigInteger r, BigInteger s) + { + if (r.Sign < 1 || s.Sign < 1 || r.CompareTo(N) >= 0 || s.CompareTo(N) >= 0) + return false; + BigInteger e = CalculateE(N, message); + BigInteger c = s.ModInverse(N); + BigInteger u1 = (e * c).Mod(N); + BigInteger u2 = (r * c).Mod(N); + ECPoint point = SumOfTwoMultiplies(G, u1, publicKey, u2); + BigInteger v = point.X.Value.Mod(N); + return v.Equals(r); + } + + 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 static readonly ECCurve Secp256k1 = new ECCurve ( BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", NumberStyles.AllowHexSpecifier), diff --git a/src/neo/SmartContract/InteropService.Crypto.cs b/src/neo/SmartContract/InteropService.Crypto.cs index 74bec64e9a..b79e4f3521 100644 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ b/src/neo/SmartContract/InteropService.Crypto.cs @@ -3,7 +3,6 @@ using Neo.Network.P2P.Payloads; using Neo.VM; using Neo.VM.Types; -using Org.BouncyCastle.Crypto.Digests; using System; using System.Linq; using Array = Neo.VM.Types.Array; @@ -14,7 +13,6 @@ partial class InteropService { public static class Crypto { - public static readonly InteropDescriptor SHA3Keccak256 = Register("Neo.Crypto.SHA3.Keccak256", Crypto_SHA3Keccak256, 0_01000000, 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 ECDsaSecp256r1Verify = Register("Neo.Crypto.ECDsa.Secp256r1.Verify", Crypto_ECDsaSecp256r1Verify, 0_01000000, TriggerType.All, CallFlags.None); @@ -33,24 +31,6 @@ private static long GetECDsaCheckMultiSigPrice(EvaluationStack stack) return ECDsaSecp256r1Verify.Price * n; } - private static bool Crypto_SHA3Keccak256(ApplicationEngine engine) - { - StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); - ReadOnlySpan value = item0 switch - { - InteropInterface _interface => _interface.GetInterface().GetHashData(), - Null _ => engine.ScriptContainer.GetHashData(), - _ => item0.GetSpan() - }; - - var digest = new KeccakDigest(256); - var output = new byte[digest.GetDigestSize()]; - digest.BlockUpdate(value.ToArray(), 0, value.Length); - digest.DoFinal(output, 0); - engine.CurrentContext.EvaluationStack.Push(output); - return true; - } - private static bool Crypto_SHA256(ApplicationEngine engine) { StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); diff --git a/src/neo/neo.csproj b/src/neo/neo.csproj index 62291dd97f..85efaaf594 100644 --- a/src/neo/neo.csproj +++ b/src/neo/neo.csproj @@ -22,7 +22,6 @@ - diff --git a/tests/neo.UnitTests/Cryptography/UT_Crypto.cs b/tests/neo.UnitTests/Cryptography/UT_Crypto.cs index 38f2006a7f..eb29138ce9 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Crypto.cs @@ -60,5 +60,30 @@ public void TestVerifySignature() Action action = () => Crypto.VerifySignature(message, signature, wrongKey).Should().BeFalse(); 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.Curve.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.Curve.Secp256k1) + .Should().BeTrue(); + + message = System.Text.Encoding.Default.GetBytes("中文"); + signature = "b8cba1ff42304d74d083e87706058f59cdd4f755b995926d2cd80a734c5a3c37e4583bfd4339ac762c1c91eee3782660a6baf62cd29e407eccd3da3e9de55a02".HexToBytes(); + pubKey = "03661b86d54eb3a8e7ea2399e0db36ab65753f95fff661da53ae0121278b881ad0".HexToBytes(); + + Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Curve.Secp256k1) + .Should().BeTrue(); + } } } From 29959c837925d31759b79e6a059a588d64d78356 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 10 Mar 2020 17:55:27 +0100 Subject: [PATCH 04/11] format --- src/neo/Cryptography/ECC/ECCurve.cs | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/neo/Cryptography/ECC/ECCurve.cs b/src/neo/Cryptography/ECC/ECCurve.cs index b549e41010..9ece11e18e 100644 --- a/src/neo/Cryptography/ECC/ECCurve.cs +++ b/src/neo/Cryptography/ECC/ECCurve.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Numerics; @@ -26,15 +26,15 @@ private ECCurve(BigInteger Q, BigInteger A, BigInteger B, BigInteger N, byte[] G this.G = ECPoint.DecodePoint(G, this); } - 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; + 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 bool VerifySignature(ReadOnlySpan message, ECPoint publicKey, BigInteger r, BigInteger s) @@ -50,28 +50,28 @@ public bool VerifySignature(ReadOnlySpan message, ECPoint publicKey, BigIn return v.Equals(r); } - 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; + 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 static readonly ECCurve Secp256k1 = new ECCurve From 9dbe6bba7d7974cc470c3a11a80256411979efb1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 21 Mar 2020 09:20:14 +0100 Subject: [PATCH 05/11] Fix UT --- src/neo/Wallets/Wallet.cs | 4 ++-- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 6 +++--- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 6 +++--- .../SmartContract/UT_ContractParameterContext.cs | 12 ++++++------ tests/neo.UnitTests/Wallets/UT_Wallet.cs | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 59c102db40..06905cdd5e 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -354,7 +354,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.ECDsaSecp256r1Verify, null); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaSecp256r1Verify, null, null); } else if (witness_script.IsMultiSigContract(out int m, out int n)) { @@ -366,7 +366,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.ECDsaSecp256r1Verify, null) * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaSecp256r1Verify, null, null) * n; } else { diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 4bdb0da2c5..80498ec4c1 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -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 diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 622f156b16..6326c95e8b 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("0x2b8a21dfaf989dc1a5f2694517aefdbda1dd340f3cf177187d73e038a58ad2bb")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x533c27382aea08712a9d2ba24b0afc0d19020d633458c89d2ce7ac11a987a75d")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x2b8a21dfaf989dc1a5f2694517aefdbda1dd340f3cf177187d73e038a58ad2bb")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x533c27382aea08712a9d2ba24b0afc0d19020d633458c89d2ce7ac11a987a75d")); } [TestMethod] @@ -88,7 +88,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x2b8a21dfaf989dc1a5f2694517aefdbda1dd340f3cf177187d73e038a58ad2bb")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x533c27382aea08712a9d2ba24b0afc0d19020d633458c89d2ce7ac11a987a75d")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } 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/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index a210cf581e..4ec3683a82 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -166,9 +166,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] From 319ed342829d0525fdc0381ef6dd1bc075573cee Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 22 Apr 2020 08:51:28 +0200 Subject: [PATCH 06/11] Fix UT --- tests/neo.UnitTests/SmartContract/UT_InteropService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 6cd27c4815..1a08173e5f 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -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); From 0a1cfb558b63832d0484493931832d160bf25de0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 24 Apr 2020 09:19:25 +0200 Subject: [PATCH 07/11] Remove enum --- src/neo/Consensus/ConsensusService.cs | 5 +- src/neo/Cryptography/Crypto.cs | 59 ++++++++----------- src/neo/Cryptography/ECC/ECCurve.cs | 6 -- .../SmartContract/InteropService.Crypto.cs | 12 ++-- .../SmartContract/Manifest/ContractGroup.cs | 2 +- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 8 +-- tests/neo.UnitTests/Cryptography/UT_Crypto.cs | 18 +++--- 7 files changed, 47 insertions(+), 63 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 9e59ba7283..4953384dc8 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -232,7 +232,8 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) existingCommitPayload = payload; } else if (Crypto.VerifySignature(hashData, commit.Signature, - context.Validators[payload.ValidatorIndex].EncodePoint(false))) + context.Validators[payload.ValidatorIndex].EncodePoint(false), + Cryptography.ECC.ECCurve.Secp256r1)) { existingCommitPayload = payload; CheckCommits(); @@ -433,7 +434,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].EncodePoint(false), Cryptography.ECC.ECCurve.Secp256r1)) context.CommitPayloads[i] = null; if (context.TransactionHashes.Length == 0) diff --git a/src/neo/Cryptography/Crypto.cs b/src/neo/Cryptography/Crypto.cs index 491aeeaf57..3ba2fb149f 100644 --- a/src/neo/Cryptography/Crypto.cs +++ b/src/neo/Cryptography/Crypto.cs @@ -33,22 +33,13 @@ public static byte[] Sign(byte[] message, byte[] prikey, byte[] pubkey) } } - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve.Curve curve = ECC.ECCurve.Curve.Secp256r1) + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve) { if (pubkey.Length == 33 && (pubkey[0] == 0x02 || pubkey[0] == 0x03)) { try { - switch (curve) - { - case ECC.ECCurve.Curve.Secp256r1: - pubkey = ECC.ECPoint.DecodePoint(pubkey, ECC.ECCurve.Secp256r1).EncodePoint(false).AsSpan(1); - break; - case ECC.ECCurve.Curve.Secp256k1: - pubkey = ECC.ECPoint.DecodePoint(pubkey, ECC.ECCurve.Secp256k1).EncodePoint(false).AsSpan(1); - break; - default: return false; - } + pubkey = ECC.ECPoint.DecodePoint(pubkey, curve).EncodePoint(false).AsSpan(1); } catch { @@ -64,35 +55,33 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan message = item0 switch @@ -80,15 +80,15 @@ private static bool Crypto_ECDsaVerify(ApplicationEngine engine, Cryptography.EC private static bool Crypto_ECDsaSecp256r1CheckMultiSig(ApplicationEngine engine) { - return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Curve.Secp256r1); + return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Secp256r1); } private static bool Crypto_ECDsaSecp256k1CheckMultiSig(ApplicationEngine engine) { - return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Curve.Secp256k1); + return Crypto_ECDsaCheckMultiSig(engine, Cryptography.ECC.ECCurve.Secp256k1); } - private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine, Cryptography.ECC.ECCurve.Curve curve) + private static bool Crypto_ECDsaCheckMultiSig(ApplicationEngine engine, Cryptography.ECC.ECCurve curve) { StackItem item0 = engine.CurrentContext.EvaluationStack.Pop(); ReadOnlySpan message = item0 switch diff --git a/src/neo/SmartContract/Manifest/ContractGroup.cs b/src/neo/SmartContract/Manifest/ContractGroup.cs index c10bcba283..fd191d4eb9 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.EncodePoint(false), Cryptography.ECC.ECCurve.Secp256r1); } public virtual JObject ToJson() diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 80498ec4c1..8f4f84cf13 100644 --- a/tests/neo.UnitTests/Consensus/UT_Consensus.cs +++ b/tests/neo.UnitTests/Consensus/UT_Consensus.cs @@ -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].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); + Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); + Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).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 eb29138ce9..950f54b8fa 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Crypto.cs @@ -44,20 +44,20 @@ 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.EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeTrue(); + Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false).Skip(1).ToArray(), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeTrue(); + Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false).Skip(1).ToArray(), Neo.Cryptography.ECC.ECCurve.Secp256r1).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).Should().BeFalse(); action.Should().Throw(); } @@ -68,21 +68,21 @@ public void TestSecp256k1() byte[] signature = "5331be791532d157df5b5620620d938bcb622ad02c81cfc184c460efdad18e695480d77440c511e9ad02ea30d773cb54e88f8cbb069644aefa283957085f38b5".HexToBytes(); byte[] pubKey = "03ea01cb94bdaf0cd1c01b159d474f9604f4af35a3e2196f6bdfdb33b2aa4961fa".HexToBytes(); - Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Curve.Secp256k1) + 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.Curve.Secp256k1) + 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.Curve.Secp256k1) + Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Secp256k1) .Should().BeTrue(); } } From 41baf8857557f4dd410a675d77da80036b085167 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sat, 25 Apr 2020 13:00:46 +0800 Subject: [PATCH 08/11] Update Crypto.cs --- src/neo/Cryptography/Crypto.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/neo/Cryptography/Crypto.cs b/src/neo/Cryptography/Crypto.cs index 3ba2fb149f..f50b0d32d4 100644 --- a/src/neo/Cryptography/Crypto.cs +++ b/src/neo/Cryptography/Crypto.cs @@ -57,11 +57,9 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan message, ReadOnlySpan message, ReadOnlySpan Date: Sat, 25 Apr 2020 13:26:30 +0800 Subject: [PATCH 09/11] Add overload --- src/neo/Consensus/ConsensusService.cs | 6 +- src/neo/Cryptography/Crypto.cs | 58 ++++++++++++++----- .../SmartContract/Manifest/ContractGroup.cs | 2 +- tests/neo.UnitTests/Consensus/UT_Consensus.cs | 10 ++-- tests/neo.UnitTests/Cryptography/UT_Crypto.cs | 6 +- 5 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 4953384dc8..788719ae14 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -231,9 +231,7 @@ private void OnCommitReceived(ConsensusPayload payload, Commit commit) { existingCommitPayload = payload; } - else if (Crypto.VerifySignature(hashData, commit.Signature, - context.Validators[payload.ValidatorIndex].EncodePoint(false), - Cryptography.ECC.ECCurve.Secp256r1)) + else if (Crypto.VerifySignature(hashData, commit.Signature, context.Validators[payload.ValidatorIndex])) { existingCommitPayload = payload; CheckCommits(); @@ -434,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), Cryptography.ECC.ECCurve.Secp256r1)) + 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 f50b0d32d4..779593a73e 100644 --- a/src/neo/Cryptography/Crypto.cs +++ b/src/neo/Cryptography/Crypto.cs @@ -33,30 +33,56 @@ public static byte[] Sign(byte[] message, byte[] prikey, byte[] pubkey) } } - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve) + 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, curve).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 r = new BigInteger(signature[..32], true, true); + var s = new BigInteger(signature[32..], true, true); + + return pubkey.Curve.VerifySignature(message.Sha256(), pubkey, r, s); } + } + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve) + { if (curve == ECC.ECCurve.Secp256r1) { + if (pubkey.Length == 33 && (pubkey[0] == 0x02 || pubkey[0] == 0x03)) + { + 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, @@ -72,9 +98,9 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpanReturn true or false public bool IsValid(UInt160 hash) { - return Crypto.VerifySignature(hash.ToArray(), Signature, PubKey.EncodePoint(false), Cryptography.ECC.ECCurve.Secp256r1); + return Crypto.VerifySignature(hash.ToArray(), Signature, PubKey); } public virtual JObject ToJson() diff --git a/tests/neo.UnitTests/Consensus/UT_Consensus.cs b/tests/neo.UnitTests/Consensus/UT_Consensus.cs index 8f4f84cf13..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 { @@ -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), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, cm.Signature, mockContext.Object.Validators[0].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); - Crypto.VerifySignature(originalBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); - Crypto.VerifySignature(updatedBlockHashData, ((Commit)cmPayloadTemp.ConsensusMessage).Signature, mockContext.Object.Validators[6].EncodePoint(false), Neo.Cryptography.ECC.ECCurve.Secp256r1).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 950f54b8fa..0154fea65a 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Crypto.cs @@ -44,9 +44,7 @@ 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), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeTrue(); - Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false).Skip(1).ToArray(), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeTrue(); - Crypto.VerifySignature(message, signature, key.PublicKey.EncodePoint(false).Skip(1).ToArray(), Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeTrue(); + Crypto.VerifySignature(message, signature, key.PublicKey).Should().BeTrue(); byte[] wrongKey = new byte[33]; wrongKey[0] = 0x02; @@ -57,7 +55,7 @@ public void TestVerifySignature() Crypto.VerifySignature(message, signature, wrongKey, Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); wrongKey = new byte[36]; - Action action = () => Crypto.VerifySignature(message, signature, wrongKey, Neo.Cryptography.ECC.ECCurve.Secp256r1).Should().BeFalse(); + Action action = () => Crypto.VerifySignature(message, signature, wrongKey, Neo.Cryptography.ECC.ECCurve.Secp256r1); action.Should().Throw(); } From a14a114785a792daabcbc51480ad029e52067e4b Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sat, 25 Apr 2020 13:37:48 +0800 Subject: [PATCH 10/11] Add ECDsa.cs --- src/neo/Cryptography/Crypto.cs | 9 ++- src/neo/Cryptography/ECC/ECCurve.cs | 49 ------------- src/neo/Cryptography/ECC/ECDsa.cs | 107 ++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 54 deletions(-) create mode 100644 src/neo/Cryptography/ECC/ECDsa.cs diff --git a/src/neo/Cryptography/Crypto.cs b/src/neo/Cryptography/Crypto.cs index 779593a73e..ddd010cc63 100644 --- a/src/neo/Cryptography/Crypto.cs +++ b/src/neo/Cryptography/Crypto.cs @@ -53,10 +53,10 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan message, 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 bool VerifySignature(ReadOnlySpan message, ECPoint publicKey, BigInteger r, BigInteger s) - { - if (r.Sign < 1 || s.Sign < 1 || r.CompareTo(N) >= 0 || s.CompareTo(N) >= 0) - return false; - BigInteger e = CalculateE(N, message); - BigInteger c = s.ModInverse(N); - BigInteger u1 = (e * c).Mod(N); - BigInteger u2 = (r * c).Mod(N); - ECPoint point = SumOfTwoMultiplies(G, u1, publicKey, u2); - BigInteger v = point.X.Value.Mod(N); - return v.Equals(r); - } - - 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 static readonly ECCurve Secp256k1 = new ECCurve ( BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", NumberStyles.AllowHexSpecifier), 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); + } + } +} From fd0a3b7834b0de3942bf17322072aeac87fe4262 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 25 Apr 2020 08:50:35 +0200 Subject: [PATCH 11/11] Rename --- src/neo/SmartContract/Contract.cs | 4 ++-- src/neo/SmartContract/Helper.cs | 4 ++-- src/neo/SmartContract/InteropService.Crypto.cs | 10 +++++----- src/neo/Wallets/Wallet.cs | 4 ++-- tests/neo.UnitTests/SmartContract/UT_Contract.cs | 12 ++++++------ .../SmartContract/UT_InteropService.NEO.cs | 14 +++++++------- .../SmartContract/UT_InteropService.cs | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/neo/SmartContract/Contract.cs b/src/neo/SmartContract/Contract.cs index 8769a1bde2..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.ECDsaSecp256r1CheckMultiSig); + 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.ECDsaSecp256r1Verify); + sb.EmitSysCall(InteropService.Crypto.VerifyWithECDsaSecp256r1); return sb.ToArray(); } } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index bbf5ccf9f9..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.ECDsaSecp256r1CheckMultiSig) + 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.ECDsaSecp256r1Verify) + || 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 c69e98df83..99b585885e 100644 --- a/src/neo/SmartContract/InteropService.Crypto.cs +++ b/src/neo/SmartContract/InteropService.Crypto.cs @@ -16,10 +16,10 @@ public static class Crypto { public static readonly InteropDescriptor SHA256 = Register("Neo.Crypto.SHA256", Crypto_SHA256, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ECDsaSecp256r1Verify = Register("Neo.Crypto.ECDsa.Secp256r1.Verify", Crypto_ECDsaSecp256r1Verify, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ECDsaSecp256k1Verify = Register("Neo.Crypto.ECDsa.Secp256k1.Verify", Crypto_ECDsaSecp256k1Verify, 0_01000000, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ECDsaSecp256r1CheckMultiSig = Register("Neo.Crypto.ECDsa.Secp256r1.CheckMultiSig", Crypto_ECDsaSecp256r1CheckMultiSig, GetECDsaCheckMultiSigPrice, TriggerType.All, CallFlags.None); - public static readonly InteropDescriptor ECDsaSecp256k1CheckMultiSig = Register("Neo.Crypto.ECDsa.Secp256k1.CheckMultiSig", Crypto_ECDsaSecp256k1CheckMultiSig, GetECDsaCheckMultiSigPrice, 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) { @@ -29,7 +29,7 @@ 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 ECDsaSecp256r1Verify.Price * n; + return VerifyWithECDsaSecp256r1.Price * n; } private static bool Crypto_SHA256(ApplicationEngine engine) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 727d854bde..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.ECDsaSecp256r1Verify, 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.ECDsaSecp256r1Verify, null, null) * n; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.VerifyWithECDsaSecp256r1, null, null) * n; } else { diff --git a/tests/neo.UnitTests/SmartContract/UT_Contract.cs b/tests/neo.UnitTests/SmartContract/UT_Contract.cs index 3827eab606..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.ECDsaSecp256r1Verify), 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.ECDsaSecp256r1Verify), 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.ECDsaSecp256r1CheckMultiSig), 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.ECDsaSecp256r1CheckMultiSig), 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.ECDsaSecp256r1Verify), 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.ECDsaSecp256r1Verify), 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_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 3d414c64ba..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.ECDsaSecp256r1Verify).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.ECDsaSecp256r1Verify).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.ECDsaSecp256r1CheckMultiSig).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.ECDsaSecp256r1CheckMultiSig).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.ECDsaSecp256r1CheckMultiSig).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.ECDsaSecp256r1CheckMultiSig).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.ECDsaSecp256r1CheckMultiSig).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 1a08173e5f..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.ECDsaSecp256r1Verify).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.ECDsaSecp256r1Verify).Should().BeTrue(); + InteropService.Invoke(engine, InteropService.Crypto.VerifyWithECDsaSecp256r1).Should().BeTrue(); engine.CurrentContext.EvaluationStack.Peek().ToBoolean().Should().BeFalse(); }