Implement ToString, handle generator point better, add more unit tests.
MODIFY
WalletWasabi.Tests/UnitTests/Crypto/GroupElementTests.cs
WalletWasabi.Tests/UnitTests/Crypto/GroupElementTests.cs
@@ -65,6 +65,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
var e = new GroupElement(GEJ.Infinity);
var f = new GroupElement(new GEJ(FE.Zero, FE.Zero, FE.Zero, infinity: true));
var g = new GroupElement(new GEJ(new FE(1), new FE(1), new FE(1), infinity: true));
+ var h = new GroupElement(new GE(EC.G.x, EC.G.y, infinity: true));
+ var i = new GroupElement(EC.G * Scalar.Zero);
Assert.True(a.IsInfinity);
Assert.True(b.IsInfinity);
@@ -73,6 +75,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
Assert.True(e.IsInfinity);
Assert.True(f.IsInfinity);
Assert.True(g.IsInfinity);
+ Assert.True(h.IsInfinity);
+ Assert.True(i.IsInfinity);
Assert.Equal(a, b);
Assert.Equal(a, c);
@@ -80,6 +84,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
Assert.Equal(a, e);
Assert.Equal(a, f);
Assert.Equal(a, g);
+ Assert.Equal(a, h);
+ Assert.Equal(a, i);
Assert.Equal(a.GetHashCode(), b.GetHashCode());
Assert.Equal(a.GetHashCode(), c.GetHashCode());
@@ -87,8 +93,10 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
Assert.Equal(a.GetHashCode(), e.GetHashCode());
Assert.Equal(a.GetHashCode(), f.GetHashCode());
Assert.Equal(a.GetHashCode(), g.GetHashCode());
+ Assert.Equal(a.GetHashCode(), h.GetHashCode());
+ Assert.Equal(a.GetHashCode(), i.GetHashCode());
- var singleSet = new HashSet<GroupElement> { a, b, c, d, e, f, g };
+ var singleSet = new HashSet<GroupElement> { a, b, c, d, e, f, g, h, i };
Assert.Single(singleSet);
}
@@ -153,7 +161,33 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
[Fact]
public void GeneratorCorrect()
{
- Assert.Equal(GroupElement.Generator, new GroupElement(EC.G));
+ var generator = new GroupElement(EC.G);
+ var generator2 = new GroupElement(new GE(EC.G.x, EC.G.y));
+ Assert.Equal(GroupElement.Generator, generator);
+ Assert.Equal(GroupElement.Generator, generator2);
+
+ Assert.True(generator.IsGenerator);
+ Assert.True(GroupElement.Generator.IsGenerator);
+
+ Assert.False(GroupElement.Infinity.IsGenerator);
+ Assert.False(new GroupElement(EC.G * Scalar.Zero).IsGenerator);
+ Assert.False(new GroupElement(EC.G * new Scalar(2)).IsGenerator);
+
+ var infinity = new GroupElement(new GE(EC.G.x, EC.G.y, infinity: true));
+ Assert.False(infinity.IsGenerator);
+ Assert.True(infinity.IsInfinity);
+ }
+
+ [Fact]
+ public void ToStringIsNice()
+ {
+ var expectedGenerator = "Generator, secp256k1_fe x = { 0x02F81798UL, 0x00A056C5UL, 0x028D959FUL, 0x036CB738UL, 0x03029BFCUL, 0x03A1C2C1UL, 0x0206295CUL, 0x02EEB156UL, 0x027EF9DCUL, 0x001E6F99UL, 1, 1 };secp256k1_fe y = { 0x0310D4B8UL, 0x01F423FEUL, 0x014199C4UL, 0x01229A15UL, 0x00FD17B4UL, 0x0384422AUL, 0x024FBFC0UL, 0x03119576UL, 0x027726A3UL, 0x00120EB6UL, 1, 1 };";
+ var expectedInfinity = "Infinity";
+ var expectedTwo = "secp256k1_fe x = { 0x00709EE5UL, 0x03026E57UL, 0x03CA7ABAUL, 0x012E33BCUL, 0x005C778EUL, 0x01701F36UL, 0x005406E9UL, 0x01F5B4C1UL, 0x039441EDUL, 0x0031811FUL, 1, 0 };secp256k1_fe y = { 0x00CFE52AUL, 0x010C6A54UL, 0x010E1236UL, 0x0194C99BUL, 0x02F7F632UL, 0x019B3ABBUL, 0x00584194UL, 0x030CE68FUL, 0x00FEA63DUL, 0x0006B85AUL, 1, 0 };";
+
+ Assert.Equal(expectedGenerator, GroupElement.Generator.ToString());
+ Assert.Equal(expectedInfinity, GroupElement.Infinity.ToString());
+ Assert.Equal(expectedTwo, new GroupElement(EC.G * new Scalar(2)).ToString());
}
}
}

ADD
WalletWasabi/Crypto/GeExtensions.cs
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace NBitcoin.Secp256k1
+{
+ public static class GeExtensions
+ {
+ public static bool IsGenerator(this GE me)
+ {
+ if (me.IsInfinity)
+ {
+ return false;
+ }
+ else if (me.x == EC.G.x && me.y == EC.G.y)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}

MODIFY
WalletWasabi/Crypto/GroupElement.cs
WalletWasabi/Crypto/GroupElement.cs
@@ -14,6 +14,10 @@ namespace WalletWasabi.Crypto
{
Ge = GE.Infinity;
}
+ else if (groupElement.IsGenerator())
+ {
+ Ge = EC.G;
+ }
else
{
Guard.True($"{nameof(groupElement)}.{nameof(groupElement.IsValidVariable)}", groupElement.IsValidVariable);
@@ -32,6 +36,7 @@ namespace WalletWasabi.Crypto
private GE Ge { get; }
public bool IsInfinity => Ge.IsInfinity;
+ public bool IsGenerator => Ge.IsGenerator();
public override bool Equals(object obj) => Equals(obj as GroupElement);
@@ -60,5 +65,24 @@ namespace WalletWasabi.Crypto
}
public static bool operator !=(GroupElement a, GroupElement b) => !(a == b);
+
+ /// <summary>
+ /// ToString is only used for nice visual representation during debugging. Do not rely on the result for anything else.
+ /// </summary>
+ public override string ToString()
+ {
+ if (IsInfinity)
+ {
+ return "Infinity";
+ }
+ else if (IsGenerator)
+ {
+ return $"Generator, {Ge.x.ToC("x")}{Ge.y.ToC("y")}";
+ }
+ else
+ {
+ return $"{Ge.x.ToC("x")}{Ge.y.ToC("y")}";
+ }
+ }
}
}

Implement ToString, handle generator point better, add more unit tests.