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

Nullable ECPoint and ECFieldElement #3758

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 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
2 changes: 2 additions & 0 deletions src/Neo.CLI/CLI/MainService.Tools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ private static string Base64Fixed(string str)
try
{
var pubKey = WIFToPublicKey(wif);
if (string.IsNullOrEmpty(pubKey)) return null;

return Contract.CreateSignatureContract(ECPoint.Parse(pubKey, ECCurve.Secp256r1)).ScriptHash.ToAddress(NeoSystem.Settings.AddressVersion);
}
catch (Exception)
Expand Down
16 changes: 12 additions & 4 deletions src/Neo.CLI/CLI/MainService.Vote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,14 +210,14 @@ private void OnGetNextBlockValidatorsCommand()
[ConsoleCommand("get accountstate", Category = "Vote Commands")]
private void OnGetAccountState(UInt160 address)
{
string notice = "No vote record!";
const string notice = "No vote record!";
var arg = new JObject
{
["type"] = "Hash160",
["value"] = address.ToString()
};

if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getAccountState", out StackItem result, null, new JArray(arg))) return;
if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getAccountState", out var result, null, new JArray(arg))) return;
Console.WriteLine();
if (result.IsNull)
{
Expand All @@ -231,15 +231,23 @@ private void OnGetAccountState(UInt160 address)
return;
}

foreach (StackItem value in resJArray)
foreach (var value in resJArray)
{
if (value.IsNull)
{
ConsoleHelper.Warning(notice);
return;
}
}
var publickey = ECPoint.Parse(((ByteString)resJArray[2])?.GetSpan().ToHexString(), ECCurve.Secp256r1);

var hexPubKey = ((ByteString)resJArray[2])?.GetSpan().ToHexString();
if (string.IsNullOrEmpty(hexPubKey))
{
ConsoleHelper.Error("Error parsing the result");
return;
}

var publickey = ECPoint.Parse(hexPubKey, ECCurve.Secp256r1);
Comment on lines +243 to +250
Copy link
Member

@cschuchardt88 cschuchardt88 Feb 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ECPoint.TryParse? Index for resJArray[2] could be out of range as well.

ConsoleHelper.Info("Voted: ", Contract.CreateSignatureRedeemScript(publickey).ToScriptHash().ToAddress(NeoSystem.Settings.AddressVersion));
ConsoleHelper.Info("Amount: ", new BigDecimal(((Integer)resJArray[0]).GetInteger(), NativeContract.NEO.Decimals).ToString());
ConsoleHelper.Info("Block: ", ((Integer)resJArray[1]).GetInteger().ToString());
Expand Down
80 changes: 43 additions & 37 deletions src/Neo/Cryptography/ECC/ECFieldElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

#nullable enable

using Neo.Extensions;
using System;
using System.Numerics;
Expand All @@ -18,26 +20,25 @@ namespace Neo.Cryptography.ECC
internal class ECFieldElement : IComparable<ECFieldElement>, IEquatable<ECFieldElement>
{
internal readonly BigInteger Value;
private readonly ECCurve curve;
private readonly ECCurve _curve;

public ECFieldElement(BigInteger value, ECCurve curve)
{
if (curve is null)
throw new ArgumentNullException(nameof(curve));
if (value >= curve.Q)
throw new ArgumentException("x value too large in field element");
Value = value;
this.curve = curve;
_curve = curve;
}

public int CompareTo(ECFieldElement other)
public int CompareTo(ECFieldElement? other)
{
if (ReferenceEquals(this, other)) return 0;
if (!curve.Equals(other.curve)) throw new InvalidOperationException("Invalid comparision for points with different curves");
if (other == null) throw new ArgumentNullException(nameof(other));
if (!_curve.Equals(other._curve)) throw new InvalidOperationException("Invalid comparision for points with different curves");
return Value.CompareTo(other.Value);
}

public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj == this)
return true;
Expand All @@ -48,15 +49,18 @@ public override bool Equals(object obj)
return Equals(other);
}

public bool Equals(ECFieldElement other)
public bool Equals(ECFieldElement? other)
{
return Value.Equals(other.Value) && curve.Equals(other.curve);
if (ReferenceEquals(this, other)) return true;
if (other == null) return false;

return Value.Equals(other.Value) && _curve.Equals(other._curve);
}

private static BigInteger[] FastLucasSequence(BigInteger p, BigInteger P, BigInteger Q, BigInteger k)
{
int n = (int)VM.Utility.GetBitLength(k);
int s = k.GetLowestSetBit();
var n = (int)VM.Utility.GetBitLength(k);
var s = k.GetLowestSetBit();

BigInteger Uh = 1;
BigInteger Vl = 2;
Expand Down Expand Up @@ -90,57 +94,57 @@ private static BigInteger[] FastLucasSequence(BigInteger p, BigInteger P, BigInt
Vl = (Vh * Vl - P * Ql).Mod(p);
Ql = (Ql * Qh).Mod(p);

for (int j = 1; j <= s; ++j)
for (var j = 1; j <= s; ++j)
{
Uh = Uh * Vl * p;
Vl = ((Vl * Vl) - (Ql << 1)).Mod(p);
Ql = (Ql * Ql).Mod(p);
}

return new BigInteger[] { Uh, Vl };
return [Uh, Vl];
}

public override int GetHashCode()
{
return Value.GetHashCode();
}

public ECFieldElement Sqrt()
public ECFieldElement? Sqrt()
{
if (curve.Q.TestBit(1))
if (_curve.Q.TestBit(1))
{
ECFieldElement z = new(BigInteger.ModPow(Value, (curve.Q >> 2) + 1, curve.Q), curve);
var z = new ECFieldElement(BigInteger.ModPow(Value, (_curve.Q >> 2) + 1, _curve.Q), _curve);
return z.Square().Equals(this) ? z : null;
}
BigInteger qMinusOne = curve.Q - 1;
BigInteger legendreExponent = qMinusOne >> 1;
if (BigInteger.ModPow(Value, legendreExponent, curve.Q) != 1)
var qMinusOne = _curve.Q - 1;
var legendreExponent = qMinusOne >> 1;
if (BigInteger.ModPow(Value, legendreExponent, _curve.Q) != 1)
return null;
BigInteger u = qMinusOne >> 2;
BigInteger k = (u << 1) + 1;
BigInteger Q = Value;
BigInteger fourQ = (Q << 2).Mod(curve.Q);
var u = qMinusOne >> 2;
var k = (u << 1) + 1;
var Q = Value;
var fourQ = (Q << 2).Mod(_curve.Q);
BigInteger U, V;
do
{
Random rand = new();
BigInteger P;
do
{
P = rand.NextBigInteger((int)VM.Utility.GetBitLength(curve.Q));
P = rand.NextBigInteger((int)VM.Utility.GetBitLength(_curve.Q));
}
while (P >= curve.Q || BigInteger.ModPow(P * P - fourQ, legendreExponent, curve.Q) != qMinusOne);
BigInteger[] result = FastLucasSequence(curve.Q, P, Q, k);
while (P >= _curve.Q || BigInteger.ModPow(P * P - fourQ, legendreExponent, _curve.Q) != qMinusOne);
var result = FastLucasSequence(_curve.Q, P, Q, k);
U = result[0];
V = result[1];
if ((V * V).Mod(curve.Q) == fourQ)
if ((V * V).Mod(_curve.Q) == fourQ)
{
if (V.TestBit(0))
{
V += curve.Q;
V += _curve.Q;
}
V >>= 1;
return new ECFieldElement(V, curve);
return new ECFieldElement(V, _curve);
}
}
while (U.Equals(BigInteger.One) || U.Equals(qMinusOne));
Expand All @@ -149,42 +153,44 @@ public ECFieldElement Sqrt()

public ECFieldElement Square()
{
return new ECFieldElement((Value * Value).Mod(curve.Q), curve);
return new ECFieldElement((Value * Value).Mod(_curve.Q), _curve);
}

public byte[] ToByteArray()
{
byte[] data = Value.ToByteArray(isUnsigned: true, isBigEndian: true);
var data = Value.ToByteArray(isUnsigned: true, isBigEndian: true);
if (data.Length == 32)
return data;
byte[] buffer = new byte[32];
var buffer = new byte[32];
Buffer.BlockCopy(data, 0, buffer, buffer.Length - data.Length, data.Length);
return buffer;
}

public static ECFieldElement operator -(ECFieldElement x)
{
return new ECFieldElement((-x.Value).Mod(x.curve.Q), x.curve);
return new ECFieldElement((-x.Value).Mod(x._curve.Q), x._curve);
}

public static ECFieldElement operator *(ECFieldElement x, ECFieldElement y)
{
return new ECFieldElement((x.Value * y.Value).Mod(x.curve.Q), x.curve);
return new ECFieldElement((x.Value * y.Value).Mod(x._curve.Q), x._curve);
}

public static ECFieldElement operator /(ECFieldElement x, ECFieldElement y)
{
return new ECFieldElement((x.Value * y.Value.ModInverse(x.curve.Q)).Mod(x.curve.Q), x.curve);
return new ECFieldElement((x.Value * y.Value.ModInverse(x._curve.Q)).Mod(x._curve.Q), x._curve);
}

public static ECFieldElement operator +(ECFieldElement x, ECFieldElement y)
{
return new ECFieldElement((x.Value + y.Value).Mod(x.curve.Q), x.curve);
return new ECFieldElement((x.Value + y.Value).Mod(x._curve.Q), x._curve);
}

public static ECFieldElement operator -(ECFieldElement x, ECFieldElement y)
{
return new ECFieldElement((x.Value - y.Value).Mod(x.curve.Q), x.curve);
return new ECFieldElement((x.Value - y.Value).Mod(x._curve.Q), x._curve);
}
}
}

#nullable disable
Loading