Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[neox-2.x] add interop services #1597

Merged
merged 21 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions neo.UnitTests/UT_ECDsa.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Cryptography;
using System.Numerics;
using System;

namespace Neo.Cryptography.ECC.Tests
{
[TestClass()]
public class UT_ECDsa
{
public static byte[] generatekey(int privateKeyLength)
{
byte[] privateKey = new byte[privateKeyLength];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(privateKey);
}
return privateKey;
}

[TestMethod()]
public void KeyRecoverTest()
{
KeyRecover(ECCurve.Secp256k1);
KeyRecover(ECCurve.Secp256r1);
}

public static void KeyRecover(ECCurve Curve)
{
byte[] privateKey = generatekey(32);
ECPoint publicKey = Curve.G * privateKey;
ECDsa ecdsa = new ECDsa(privateKey, Curve);
byte[] message = System.Text.Encoding.Default.GetBytes("HelloWorld");
BigInteger[] signatures = ecdsa.GenerateSignature(message);
BigInteger r = signatures[0];
BigInteger s = signatures[1];
bool v;
if (signatures[2] == 0)
{
v = true;
}
else
{
v = false;
}
ECPoint recoverKey = ECDsa.KeyRecover(Curve, r, s, message, v);
Assert.IsTrue(recoverKey.Equals(publicKey));
//wrong r part
r = new BigInteger(generatekey(32));
s = new BigInteger(generatekey(32));
try
{
recoverKey = ECDsa.KeyRecover(Curve, r, s, message, v);
Assert.IsFalse(recoverKey.Equals(publicKey));
}
catch (Exception e)
{
Assert.IsTrue(e.GetType() == typeof(ArithmeticException));
}
}
}
}
5 changes: 2 additions & 3 deletions neo.UnitTests/UT_Helper.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Network.P2P;
using Neo.SmartContract;
using Neo.Wallets;
using FluentAssertions;

namespace Neo.UnitTests
{
Expand Down Expand Up @@ -37,6 +37,5 @@ public void ToScriptHash()
UInt160 res = testByteArray.ToScriptHash();
res.Should().Be(UInt160.Parse("2d3b96ae1bcc5a585e075e3b81920210dec16302"));
}

}
}
53 changes: 51 additions & 2 deletions neo/Cryptography/ECC/ECDsa.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public BigInteger[] GenerateSignature(byte[] message)
if (privateKey == null) throw new InvalidOperationException();
BigInteger e = CalculateE(curve.N, message);
BigInteger d = new BigInteger(privateKey.Reverse().Concat(new byte[1]).ToArray());
BigInteger r, s;
BigInteger r, s, isEven;
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
do
Expand All @@ -53,6 +53,7 @@ public BigInteger[] GenerateSignature(byte[] message)
}
while (k.Sign == 0 || k.CompareTo(curve.N) >= 0);
ECPoint p = ECPoint.Multiply(curve.G, k);
isEven = p.Y.Value & 1;
BigInteger x = p.X.Value;
r = x.Mod(curve.N);
}
Expand All @@ -61,11 +62,12 @@ public BigInteger[] GenerateSignature(byte[] message)
if (s > curve.N / 2)
{
s = curve.N - s;
isEven = isEven ^ 1;
}
}
while (s.Sign == 0);
}
return new BigInteger[] { r, s };
return new BigInteger[] { r, s, isEven };
}

private static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
Expand Down Expand Up @@ -104,5 +106,52 @@ public bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
BigInteger v = point.X.Value.Mod(curve.N);
return v.Equals(r);
}

public static ECPoint KeyRecover(ECCurve curve, BigInteger r, BigInteger s, byte[] msg, bool isEven)
{
shargon marked this conversation as resolved.
Show resolved Hide resolved
if (r < BigInteger.One || s < BigInteger.One)
{
throw new ArithmeticException("Invalid signature");
}
// calculate h
BigInteger h = (curve.Q + 1 + 2 * (BigInteger)Math.Sqrt((double)curve.Q)) / curve.N;
BigInteger e;
ECPoint Q = new ECPoint();
int messageBitLength;

for (int i = 0; i <= h; i++)
{
// step 1.1 x = (n * i) + r
BigInteger Rx = curve.N * i + r;
if (Rx > curve.Q) break;

// step 1.2 and 1.3 get point R
ECPoint R;
if (isEven)
{
R = ECPoint.DecompressPoint(0, Rx, curve);
}
else
{
R = ECPoint.DecompressPoint(1, Rx, curve);
}
if (ECPoint.Multiply(R, curve.N) != curve.Infinity)
continue;

// step 1.5 compute e
messageBitLength = msg.Length * 8;
e = new BigInteger(msg.Reverse().Concat(new byte[1]).ToArray());
if (curve.N.GetBitLength() < messageBitLength)
{
e >>= messageBitLength - curve.N.GetBitLength();
}

// step 1.6 Q = r^-1 (sR-eG)
BigInteger invr = r.ModInverse(curve.N);
ECPoint t0 = ECPoint.Multiply(R, s) - ECPoint.Multiply(curve.G, e);
Q = ECPoint.Multiply(t0, invr);
}
return Q;
}
}
}
2 changes: 1 addition & 1 deletion neo/Cryptography/ECC/ECPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static ECPoint DecodePoint(byte[] encoded, ECCurve curve)
return p;
}

private static ECPoint DecompressPoint(int yTilde, BigInteger X1, ECCurve curve)
public static ECPoint DecompressPoint(int yTilde, BigInteger X1, ECCurve curve)
{
ECFieldElement x = new ECFieldElement(X1, curve);
ECFieldElement alpha = x * (x.Square() + curve.A) + curve.B;
Expand Down
34 changes: 33 additions & 1 deletion neo/SmartContract/NeoService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Neo.Cryptography.ECC;
using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.Ledger;
using Neo.Network.P2P;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract.Enumerators;
Expand Down Expand Up @@ -99,6 +101,8 @@ public NeoService(TriggerType trigger, Snapshot snapshot)
Register("Neo.Iterator.Keys", Iterator_Keys, 1);
Register("Neo.Iterator.Values", Iterator_Values, 1);
Register("Neo.Iterator.Concat", Iterator_Concat, 1);
Register("Neo.Cryptography.Secp256k1Recover", Secp256k1Recover, 100);
Register("Neo.Cryptography.Secp256r1Recover", Secp256r1Recover, 100);

#region Aliases
Register("Neo.Iterator.Next", Enumerator_Next, 1);
Expand Down Expand Up @@ -165,6 +169,34 @@ public NeoService(TriggerType trigger, Snapshot snapshot)
#endregion
}

private bool Secp256k1Recover(ExecutionEngine engine)
{
return EccRecover(ECCurve.Secp256k1, engine);
}

private bool Secp256r1Recover(ExecutionEngine engine)
{
return EccRecover(ECCurve.Secp256r1, engine);
}

private bool EccRecover(ECCurve curve, ExecutionEngine engine)
{
var r = new System.Numerics.BigInteger(engine.CurrentContext.EvaluationStack.Pop().GetByteArray().Reverse().Concat(new byte[1]).ToArray());
shargon marked this conversation as resolved.
Show resolved Hide resolved
var s = new System.Numerics.BigInteger(engine.CurrentContext.EvaluationStack.Pop().GetByteArray().Reverse().Concat(new byte[1]).ToArray());
ZhangTao1596 marked this conversation as resolved.
Show resolved Hide resolved
bool v = engine.CurrentContext.EvaluationStack.Pop().GetBoolean();
byte[] messageHash = engine.CurrentContext.EvaluationStack.Pop().GetByteArray();
try
{
ECPoint point = ECDsa.KeyRecover(curve, r, s, messageHash, v);
engine.CurrentContext.EvaluationStack.Push(point.EncodePoint(false).Skip(1).ToArray());
}
catch
{
engine.CurrentContext.EvaluationStack.Push(new byte[0]);
}
return true;
}

private bool Blockchain_GetAccount(ExecutionEngine engine)
{
UInt160 hash = new UInt160(engine.CurrentContext.EvaluationStack.Pop().GetByteArray());
Expand Down
3 changes: 2 additions & 1 deletion neo/SmartContract/StandardService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Neo.Cryptography.ECC;
using Neo.Cryptography;
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Ledger;
using Neo.Network.P2P.Payloads;
Expand Down