Implement WabiSabi Generators
MODIFY
WalletWasabi.Tests/UnitTests/Crypto/GroupElements/GeneralTests.cs
WalletWasabi.Tests/UnitTests/Crypto/GroupElements/GeneralTests.cs
@@ -161,23 +161,6 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.GroupElements
Assert.Equal(a, c);
}
- [Fact]
- public void GeneratorCorrect()
- {
- var generator = new GroupElement(EC.G);
- var generator2 = new GroupElement(new GE(EC.G.x, EC.G.y));
- Assert.Equal(GroupElement.G, generator);
- Assert.Equal(GroupElement.G, generator2);
-
- Assert.NotEqual(GroupElement.G, GroupElement.Infinity);
- Assert.NotEqual(GroupElement.G, new GroupElement(EC.G * Scalar.Zero));
- Assert.NotEqual(GroupElement.G, new GroupElement(EC.G * new Scalar(2)));
-
- var infinity = new GroupElement(new GE(EC.G.x, EC.G.y, infinity: true));
- Assert.NotEqual(GroupElement.G, infinity);
- Assert.True(infinity.IsInfinity);
- }
-
[Fact]
public void ToStringIsNice()
{
@@ -322,5 +305,24 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.GroupElements
var ge2 = GroupElement.FromBytes(ge.ToBytes());
Assert.Equal(ge, ge2);
}
+
+ [Fact]
+ public void FromTextFails()
+ {
+ Assert.Throws<ArgumentNullException>(() => GroupElement.FromText(null));
+ }
+
+ [Theory]
+ [InlineData("", "035FECEB66FFC86F38D952786C6D696C79C2DBC239DD4E91B46729D73A27FB57E9")]
+ [InlineData(" ", "03E12A7E051731CF1DBEEFA2142A8E1ABB1EB5898E2CBE4AA522120829A5588DC7")]
+ [InlineData(" ", "0397D2E845C60987D38F0A97F9E0E0BC9946BF55A499A1F0E5257B0978BBEC85E3")]
+ [InlineData("a", "034E1195DF020DE59E0D65A33A4279F1183E7AE4E5D980E309F8B55ADFF2E61C3E")]
+ [InlineData("12345", "03DD712114FB283417DE4DA3512E17486ADBDA004060D0D1646508C8A2740D29B4")]
+ public void FromText(string text, string expectedHex)
+ {
+ var ge = GroupElement.FromText(text);
+ var hex = ByteHelpers.ToHex(ge.ToBytes());
+ Assert.Equal(expectedHex, hex);
+ }
}
}

ADD
WalletWasabi.Tests/UnitTests/Crypto/GroupElements/GeneratorTests.cs
+using NBitcoin.Secp256k1;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using WalletWasabi.Crypto;
+using Xunit;
+
+namespace WalletWasabi.Tests.UnitTests.Crypto.GroupElements
+{
+ public class GeneratorTests
+ {
+ [Fact]
+ public void StandardGenerator()
+ {
+ var generator = new GroupElement(EC.G);
+ var generator2 = new GroupElement(new GE(EC.G.x, EC.G.y));
+ Assert.Equal(GroupElement.G, generator);
+ Assert.Equal(GroupElement.G, generator2);
+
+ Assert.NotEqual(GroupElement.G, GroupElement.Infinity);
+ Assert.NotEqual(GroupElement.G, new GroupElement(EC.G * Scalar.Zero));
+ Assert.NotEqual(GroupElement.G, new GroupElement(EC.G * new Scalar(2)));
+
+ var infinity = new GroupElement(new GE(EC.G.x, EC.G.y, infinity: true));
+ Assert.NotEqual(GroupElement.G, infinity);
+ Assert.True(infinity.IsInfinity);
+ }
+
+ [Fact]
+ public void GeneratorsArentChanged()
+ {
+ Assert.Equal("0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", ByteHelpers.ToHex(GroupElement.G.ToBytes()));
+ Assert.Equal("032F7BF18F3EB9639FF9234D9B74C49E598E34BD3AF1CEEE7378E012E73E66ABAE", ByteHelpers.ToHex(GroupElement.Ga.ToBytes()));
+ Assert.Equal("034787C4A880CB54D4A13130E6A31BDEEB047FE9D67C558EAC3DE30CC3A66C277D", ByteHelpers.ToHex(GroupElement.Gg.ToBytes()));
+ Assert.Equal("035AF23B3B63E068D2D157513A77CD78BEC1B389EA5EDEC6C9A8DA1254C3DEAC03", ByteHelpers.ToHex(GroupElement.Gh.ToBytes()));
+ Assert.Equal("031B786490B66B665F09AE2F848EFC1C2B8D86E35FCDCEF67F61CF5A95FC8C7263", ByteHelpers.ToHex(GroupElement.Gs.ToBytes()));
+ Assert.Equal("0322C1EC0F8A3B41D1FB7184692428B0236E253AA643ACCBCF412CAE3231C14967", ByteHelpers.ToHex(GroupElement.GV.ToBytes()));
+ Assert.Equal("0338A4AAE54CCB98207FA4707DB4F711A9427B0444F97FC8F54EF9D00E25013C2F", ByteHelpers.ToHex(GroupElement.Gw.ToBytes()));
+ Assert.Equal("03A456261F53BFC99BF0DB0D71FE3E1A259961D9DA896217DAC475841DA3A4F16C", ByteHelpers.ToHex(GroupElement.Gwp.ToBytes()));
+ Assert.Equal("0381E7BCF60042263290325032954C500DCCE6D470A952C2FCDC62CF2280282D76", ByteHelpers.ToHex(GroupElement.Gx0.ToBytes()));
+ Assert.Equal("03A031FE97954902E3E84241D5E48264F06748FA741A9B2C35E8DA7C772C1A5105", ByteHelpers.ToHex(GroupElement.Gx1.ToBytes()));
+ }
+ }
+}

MODIFY
WalletWasabi/Crypto/GroupElement.cs
WalletWasabi/Crypto/GroupElement.cs
@@ -34,6 +34,51 @@ namespace WalletWasabi.Crypto
/// </summary>
public static GroupElement G { get; } = new GroupElement(EC.G);
+ /// <summary>
+ /// Generators for MAC and Show.
+ /// </summary>
+ public static GroupElement Gw { get; } = FromText("Gw");
+
+ /// <summary>
+ /// Generators for MAC and Show.
+ /// </summary>
+ public static GroupElement Gwp { get; } = FromText("Gwp");
+
+ /// <summary>
+ /// Generators for MAC and Show.
+ /// </summary>
+ public static GroupElement Gx0 { get; } = FromText("Gx0");
+
+ /// <summary>
+ /// Generators for MAC and Show.
+ /// </summary>
+ public static GroupElement Gx1 { get; } = FromText("Gx1");
+
+ /// <summary>
+ /// Generators for MAC and Show.
+ /// </summary>
+ public static GroupElement GV { get; } = FromText("GV");
+
+ /// <summary>
+ /// Generators for Pedersen commitments.
+ /// </summary>
+ public static GroupElement Gg { get; } = FromText("Gg");
+
+ /// <summary>
+ /// Generators for Pedersen commitments.
+ /// </summary>
+ public static GroupElement Gh { get; } = FromText("Gh");
+
+ /// <summary>
+ /// Generator for attributes M_{ai}.
+ /// </summary>
+ public static GroupElement Ga { get; } = FromText("Ga");
+
+ /// <summary>
+ /// Generator for serial numbers.
+ /// </summary>
+ public static GroupElement Gs { get; } = FromText("Gs");
+
private GE Ge { get; }
public bool IsInfinity => Ge.IsInfinity;
@@ -160,5 +205,27 @@ namespace WalletWasabi.Crypto
_ => throw new ArgumentException($"Argument is not a well-formatted group element.", nameof(bytes))
};
}
+
+ /// <summary>
+ /// Deterministically creates a group element from the given text.
+ /// Uniqueness relies on the SHA256 hash function.
+ /// </summary>
+ public static GroupElement FromText(string text)
+ {
+ Guard.NotNull(nameof(text), text);
+
+ FE x;
+ GE ge;
+ int nonce = 0;
+ using var sha256 = System.Security.Cryptography.SHA256.Create();
+ do
+ {
+ x = new FE(sha256.ComputeHash(Encoding.UTF8.GetBytes(text + nonce)));
+ nonce++;
+ }
+ while (!GE.TryCreateXOVariable(x, true, out ge));
+
+ return new GroupElement(ge);
+ }
}
}

Implement WabiSabi Generators