Prevent zero scalars
MODIFY
WalletWasabi.Tests/UnitTests/Crypto/CredentialIssuerKeyTests.cs
WalletWasabi.Tests/UnitTests/Crypto/CredentialIssuerKeyTests.cs
+using System.Linq;
using Moq;
using NBitcoin.Secp256k1;
using WalletWasabi.Crypto;
@@ -9,44 +10,32 @@ namespace WalletWasabi.Tests.UnitTests.Crypto;
public class CredentialIssuerKeyTests
{
+ [Theory]
+ [InlineData(0, 1, 1, 1, 1)]
+ [InlineData(1, 0, 1, 1, 1)]
+ [InlineData(1, 1, 0, 1, 1)]
+ [InlineData(1, 1, 1, 0, 1)]
+ [InlineData(1, 1, 1, 1, 0)]
+ public void CannotGenerateIssuerSecretKeyWithZero(int w, int wp, int x0, int x1, int ya)
+ {
+ var keys = new [] { ("w", w), ("wp", wp), ("x0", x0), ("x1", x1), ("ya", ya) };
+ var mockRandom = new Mock<WasabiRandom>();
+ var seq = mockRandom.SetupSequence(rnd => rnd.GetScalar());
+ Array.ForEach(keys, k => seq.Returns(k.Item2 == 0 ? Scalar.Zero : Scalar.One));
+
+ var ex = Assert.Throws<ArgumentException>(() => new CredentialIssuerSecretKey(mockRandom.Object));
+ Assert.StartsWith($"Value cannot be zero. (Parameter '{keys.Single(k => k.Item2 == 0).Item1}')", ex.Message);
+ }
+
[Fact]
public void GenerateCredentialIssuerParameters()
{
- // Coordinator key is (0, 0, 0, 0, 0)
- var mockRandom = new Mock<WasabiRandom>();
- mockRandom.Setup(rnd => rnd.GetScalar(true)).Returns(Scalar.Zero);
- var key = new CredentialIssuerSecretKey(mockRandom.Object);
- var ex = Assert.Throws<ArgumentException>(key.ComputeCredentialIssuerParameters);
+ var inf = GroupElement.Infinity;
+ var g = Generators.G;
+ var ex = Assert.Throws<ArgumentException>(() => new CredentialIssuerParameters(inf, g));
Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);
- // Coordinator key is (0, 0, 1, 1, 1)
- mockRandom.SetupSequence(rnd => rnd.GetScalar(true))
- .Returns(Scalar.Zero)
- .Returns(Scalar.Zero)
- .Returns(Scalar.One)
- .Returns(Scalar.One)
- .Returns(Scalar.One);
- key = new CredentialIssuerSecretKey(mockRandom.Object);
- ex = Assert.Throws<ArgumentException>(key.ComputeCredentialIssuerParameters);
+ ex = Assert.Throws<ArgumentException>(() => new CredentialIssuerParameters(g, inf));
Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);
-
- // Coordinator key is (1, 1, 0, 0, 0)
- mockRandom.SetupSequence(rnd => rnd.GetScalar(true))
- .Returns(Scalar.One)
- .Returns(Scalar.One)
- .Returns(Scalar.Zero)
- .Returns(Scalar.Zero)
- .Returns(Scalar.Zero);
- key = new CredentialIssuerSecretKey(mockRandom.Object);
- var iparams = key.ComputeCredentialIssuerParameters();
- Assert.Equal(Generators.GV, iparams.I);
-
- // Coordinator key is (1, 1, 1, 1, 1)
- mockRandom.Setup(rnd => rnd.GetScalar(true))
- .Returns(Scalar.One);
- key = new CredentialIssuerSecretKey(mockRandom.Object);
- iparams = key.ComputeCredentialIssuerParameters();
- Assert.Equal(Generators.Gw + Generators.Gwp, iparams.Cw);
- Assert.Equal(Generators.GV - Generators.Gx0 - Generators.Gx1 - Generators.Ga, iparams.I);
}
}

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/RandomTests.cs
WalletWasabi.Tests/UnitTests/Crypto/RandomTests.cs
@@ -118,6 +118,7 @@ public class RandomTests
mockRandom.GetBytesResults.Add(Scalar.Zero.ToBytes());
var one = new Scalar(1);
mockRandom.GetBytesResults.Add(one.ToBytes());
+ mockRandom.GetBytesResults.Add(one.ToBytes());
var two = new Scalar(2);
mockRandom.GetBytesResults.Add(two.ToBytes());
var big = new Scalar(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue);
@@ -126,7 +127,7 @@ public class RandomTests
mockRandom.GetBytesResults.Add(biggest.ToBytes());
var randomScalar = mockRandom.GetScalar();
- Assert.Equal(Scalar.Zero, randomScalar);
+ Assert.Equal(one, randomScalar);
randomScalar = mockRandom.GetScalar();
Assert.Equal(one, randomScalar);
randomScalar = mockRandom.GetScalar();

MODIFY
WalletWasabi/Crypto/CredentialIssuerSecretKey.cs
WalletWasabi/Crypto/CredentialIssuerSecretKey.cs
using NBitcoin.Secp256k1;
using WalletWasabi.Crypto.Groups;
using WalletWasabi.Crypto.Randomness;
+using WalletWasabi.Helpers;
namespace WalletWasabi.Crypto;
@@ -13,11 +14,11 @@ public record CredentialIssuerSecretKey
private CredentialIssuerSecretKey(Scalar w, Scalar wp, Scalar x0, Scalar x1, Scalar ya)
{
- W = w;
- Wp = wp;
- X0 = x0;
- X1 = x1;
- Ya = ya;
+ W = Guard.NotZero(nameof(w), w);
+ Wp = Guard.NotZero(nameof(wp), wp);
+ X0 = Guard.NotZero(nameof(x0), x0);
+ X1 = Guard.NotZero(nameof(x1), x1);
+ Ya = Guard.NotZero(nameof(ya), ya);
}
public Scalar W { get; }

MODIFY
WalletWasabi/Crypto/Randomness/WasabiRandom.cs
WalletWasabi/Crypto/Randomness/WasabiRandom.cs
@@ -33,24 +33,17 @@ public abstract class WasabiRandom : IRandom, IDisposable
return random;
}
- public virtual Scalar GetScalar(bool allowZero = true)
+ public virtual Scalar GetScalar()
{
Scalar randomScalar;
int overflow;
Span<byte> buffer = stackalloc byte[32];
- var randomWasZero = false;
do
{
GetBytes(buffer);
randomScalar = new Scalar(buffer, out overflow);
-
- if (randomScalar.IsZero && randomWasZero)
- {
- throw new InvalidOperationException("Random generator generated zero scalar twice in a row. Stop using this computer now!");
- }
- randomWasZero = randomScalar.IsZero;
}
- while (overflow != 0 || (!allowZero && randomScalar.IsZero));
+ while (overflow != 0 || randomScalar.IsZero);
return randomScalar;
}

MODIFY
WalletWasabi/WabiSabi/Crypto/WabiSabiClient.cs
WalletWasabi/WabiSabi/Crypto/WabiSabiClient.cs
@@ -55,7 +55,7 @@ public class WabiSabiClient
for (var i = 0; i < NumberOfCredentials; i++)
{
- var randomness = RandomNumberGenerator.GetScalar(allowZero: false);
+ var randomness = RandomNumberGenerator.GetScalar();
var ma = randomness * Generators.Gh;
knowledge[i] = ProofSystem.ZeroProofKnowledge(ma, randomness);
@@ -144,7 +144,7 @@ public class WabiSabiClient
var value = credentialAmountsToRequest[i];
var scalar = new Scalar((ulong)value);
- var randomness = RandomNumberGenerator.GetScalar(allowZero: false);
+ var randomness = RandomNumberGenerator.GetScalar();
var ma = ProofSystem.PedersenCommitment(scalar, randomness);
var (rangeKnowledge, bitCommitments) = ProofSystem.RangeProofKnowledge(scalar, randomness, RangeProofWidth, RandomNumberGenerator);

Prevent zero scalars