Introduce KnowledgeOf params
RENAME
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfDiscreteLogTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfDlogTests.cs
@@ -11,7 +11,7 @@ using Xunit;
namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
{
- public class KnowledgeOfDiscreteLogTests
+ public class KnowledgeOfDLogTests
{
[Theory]
[InlineData(1)]
@@ -27,7 +27,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var generator = Generators.G;
var publicPoint = secret * generator;
var statement = new Statement(publicPoint, generator);
- var proof = Prover.CreateProof(secret, statement);
+ var knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ var proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
}
@@ -39,7 +40,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var generator = Generators.G;
var publicPoint = secret * generator;
var statement = new Statement(publicPoint, generator);
- var proof = Prover.CreateProof(secret, statement);
+ var knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ var proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
}
}
@@ -52,29 +54,34 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var secret = new Scalar(val, val, val, val, val, val, val, val);
var p = secret * gen;
var statement = new Statement(p, gen);
- var proof = Prover.CreateProof(secret, statement);
+ var knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ var proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
secret = EC.N + (new Scalar(1)).Negate();
p = secret * gen;
statement = new Statement(p, gen);
- proof = Prover.CreateProof(secret, statement);
+ knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
secret = EC.NC;
p = secret * gen;
statement = new Statement(p, gen);
- proof = Prover.CreateProof(secret, statement);
+ knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
secret = EC.NC + new Scalar(1);
p = secret * gen;
statement = new Statement(p, gen);
- proof = Prover.CreateProof(secret, statement);
+ knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
secret = EC.NC + (new Scalar(1)).Negate();
p = secret * gen;
statement = new Statement(p, gen);
- proof = Prover.CreateProof(secret, statement);
+ knowledgeParams = new KnowledgeOfDlogParams(secret, statement);
+ proof = Prover.CreateProof(knowledgeParams);
Assert.True(Verifier.Verify(proof, statement));
}
@@ -105,15 +112,36 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
}
[Fact]
- public void Throws()
+ public void KnowledgeOfDlogThrows()
{
// Demonstrate when it shouldn't throw.
- new KnowledgeOfDiscreteLog(Generators.G, Scalar.One);
+ new KnowledgeOfDlog(Generators.G, Scalar.One);
// Infinity or zero cannot pass through.
- Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDiscreteLog(Generators.G, Scalar.Zero));
- Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDiscreteLog(GroupElement.Infinity, Scalar.One));
- Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDiscreteLog(GroupElement.Infinity, Scalar.Zero));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDlog(Generators.G, Scalar.Zero));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDlog(GroupElement.Infinity, Scalar.One));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDlog(GroupElement.Infinity, Scalar.Zero));
+ }
+
+ [Fact]
+ public void KnowledgeOfDlogParamsThrows()
+ {
+ var two = new Scalar(2);
+
+ // Demonstrate when it shouldn't throw.
+ new KnowledgeOfDlogParams(two, new Statement(two * Generators.G, Generators.G));
+
+ // Zero cannot pass through.
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDlogParams(Scalar.Zero, new Statement(Generators.G, Generators.G)));
+
+ // Public point must be generator * secret.
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfDlogParams(two, new Statement(Generators.G, Generators.G)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfDlogParams(two, new Statement(new Scalar(3) * Generators.G, Generators.G)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfDlogParams(two, new Statement(Scalar.One * Generators.G, Generators.G)));
+
+ // Secret cannot overflow.
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDlogParams(EC.N, new Statement(EC.N * Generators.G, Generators.G)));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfDlogParams(CryptoHelpers.ScalarLargestOverflow, new Statement(CryptoHelpers.ScalarLargestOverflow * Generators.G, Generators.G)));
}
}
}

ADD
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfRepTests.cs
+using NBitcoin.Secp256k1;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using WalletWasabi.Crypto.Groups;
+using WalletWasabi.Crypto.ZeroKnowledge;
+using WalletWasabi.Tests.Helpers;
+using Xunit;
+
+namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
+{
+ public class KnowledgeOfRepTests
+ {
+ [Theory]
+ [InlineData(1, 1)]
+ [InlineData(1, 2)]
+ [InlineData(3, 5)]
+ [InlineData(5, 7)]
+ [InlineData(7, 11)]
+ [InlineData(short.MaxValue, uint.MaxValue)]
+ [InlineData(int.MaxValue, uint.MaxValue)]
+ [InlineData(uint.MaxValue, uint.MaxValue)]
+ public void End2EndVerificationSimple(uint scalarSeed1, uint scalarSeed2)
+ {
+ var secrets = new[] { new Scalar(scalarSeed1), new Scalar(scalarSeed2) };
+ var generators = new[] { Generators.G, Generators.Ga };
+ var publicPoint = GroupElement.Infinity;
+ foreach (var (secret, generator) in secrets.ZipForceEqualLength(generators))
+ {
+ publicPoint += secret * generator;
+ }
+
+ var statement = new Statement(publicPoint, generators);
+ var knowledge = new KnowledgeOfRepParams(secrets, statement);
+ var proof = Prover.CreateProof(knowledge);
+ Assert.True(Verifier.Verify(proof, statement));
+ }
+
+ [Fact]
+ public void End2EndVerification()
+ {
+ var goodScalars = CryptoHelpers.GetScalars(x => !x.IsOverflow && !x.IsZero);
+ foreach (var secret1 in goodScalars)
+ {
+ foreach (var secret2 in goodScalars.Where(x => x != secret1))
+ {
+ var secrets = new[] { secret1, secret2 };
+ var generators = new[] { Generators.G, Generators.Ga };
+ var publicPoint = GroupElement.Infinity;
+ foreach (var (secret, generator) in secrets.ZipForceEqualLength(generators))
+ {
+ publicPoint += secret * generator;
+ }
+ Statement statement = new Statement(publicPoint, generators);
+ var knowledge = new KnowledgeOfRepParams(secrets, statement);
+ var proof = Prover.CreateProof(knowledge);
+ Assert.True(Verifier.Verify(proof, statement));
+ }
+ }
+ }
+
+ [Fact]
+ public void KnowledgeOfRepThrows()
+ {
+ // Demonstrate when it shouldn't throw.
+ new KnowledgeOfRep(Generators.G, CryptoHelpers.ScalarOne, CryptoHelpers.ScalarTwo);
+
+ // Infinity or zero cannot pass through.
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRep(Generators.G, Scalar.Zero, CryptoHelpers.ScalarTwo));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRep(Generators.G, CryptoHelpers.ScalarOne, Scalar.Zero));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRep(GroupElement.Infinity, CryptoHelpers.ScalarOne, CryptoHelpers.ScalarTwo));
+ }
+
+ [Fact]
+ public void KnowledgeOfRepParamsThrows()
+ {
+ var two = new Scalar(2);
+ var three = new Scalar(3);
+
+ // Demonstrate when it shouldn't throw.
+ new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga));
+
+ // Zero cannot pass through.
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepParams(new[] { Scalar.Zero, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepParams(new[] { two, Scalar.Zero }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+
+ // Overflow cannot pass through.
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepParams(new[] { EC.N, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepParams(new[] { two, EC.N }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+
+ // Public point must be sum(generator * secret).
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(three * Generators.Ga, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.Ga, Generators.G)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Gg)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + Generators.Ga, Generators.G, Generators.Ga)));
+
+ // Generators and secrets cannot be empty.
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepParams(Array.Empty<Scalar>(), new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + three * Generators.Ga)));
+
+ // Generators and secrets must be equal.
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two }, new Statement(two * Generators.G, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three, new Scalar(4) }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G)));
+ Assert.ThrowsAny<InvalidOperationException>(() => new KnowledgeOfRepParams(new[] { two, three }, new Statement(two * Generators.G + three * Generators.Ga, Generators.G, Generators.Ga, Generators.Gg)));
+ }
+ }
+}

DELETE
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/KnowledgeOfRepresentationTests.cs
-using NBitcoin.Secp256k1;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using WalletWasabi.Crypto.Groups;
-using WalletWasabi.Crypto.ZeroKnowledge;
-using WalletWasabi.Tests.Helpers;
-using Xunit;
-
-namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
-{
- public class KnowledgeOfRepresentationTests
- {
- [Theory]
- [InlineData(1, 1)]
- [InlineData(1, 2)]
- [InlineData(3, 5)]
- [InlineData(5, 7)]
- [InlineData(7, 11)]
- [InlineData(short.MaxValue, uint.MaxValue)]
- [InlineData(int.MaxValue, uint.MaxValue)]
- [InlineData(uint.MaxValue, uint.MaxValue)]
- public void End2EndVerificationSimple(uint scalarSeed1, uint scalarSeed2)
- {
- var secrets = new[] { new Scalar(scalarSeed1), new Scalar(scalarSeed2) };
- var generators = new[] { Generators.G, Generators.Ga };
- var publicPoint = GroupElement.Infinity;
- foreach (var (secret, generator) in secrets.ZipForceEqualLength(generators))
- {
- publicPoint += secret * generator;
- }
-
- Statement statement = new Statement(publicPoint, generators);
- var proof = Prover.CreateProof(secrets, statement);
- Assert.True(Verifier.Verify(proof, statement));
- }
-
- [Fact]
- public void End2EndVerification()
- {
- var goodScalars = CryptoHelpers.GetScalars(x => !x.IsOverflow && !x.IsZero);
- foreach (var secret1 in goodScalars)
- {
- foreach (var secret2 in goodScalars.Where(x => x != secret1))
- {
- var secrets = new[] { secret1, secret2 };
- var generators = new[] { Generators.G, Generators.Ga };
- var publicPoint = GroupElement.Infinity;
- foreach (var (secret, generator) in secrets.ZipForceEqualLength(generators))
- {
- publicPoint += secret * generator;
- }
- Statement statement = new Statement(publicPoint, generators);
- var proof = Prover.CreateProof(secrets, statement);
- Assert.True(Verifier.Verify(proof, statement));
- }
- }
- }
-
- [Fact]
- public void Throws()
- {
- // Demonstrate when it shouldn't throw.
- new KnowledgeOfRepresentation(Generators.G, CryptoHelpers.ScalarOne, CryptoHelpers.ScalarTwo);
-
- // Infinity or zero cannot pass through.
- Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepresentation(Generators.G, Scalar.Zero, CryptoHelpers.ScalarTwo));
- Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepresentation(Generators.G, CryptoHelpers.ScalarOne, Scalar.Zero));
- Assert.ThrowsAny<ArgumentException>(() => new KnowledgeOfRepresentation(GroupElement.Infinity, CryptoHelpers.ScalarOne, CryptoHelpers.ScalarTwo));
- }
- }
-}

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/ProverTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/ProverTests.cs
@@ -12,27 +12,6 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
{
public class ProverTests
{
- [Fact]
- public void Throws()
- {
- var two = new Scalar(2);
-
- // Demonstrate when it shouldn't throw.
- Prover.CreateProof(two, new Statement(two * Generators.G, Generators.G));
-
- // Zero cannot pass through.
- Assert.ThrowsAny<ArgumentException>(() => Prover.CreateProof(Scalar.Zero, new Statement(Generators.G, Generators.G)));
-
- // Public point must be generator * secret.
- Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(two, new Statement(Generators.G, Generators.G)));
- Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(two, new Statement(new Scalar(3) * Generators.G, Generators.G)));
- Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(two, new Statement(Scalar.One * Generators.G, Generators.G)));
-
- // Secret cannot overflow.
- Assert.ThrowsAny<ArgumentException>(() => Prover.CreateProof(EC.N, new Statement(EC.N * Generators.G, Generators.G)));
- Assert.ThrowsAny<ArgumentException>(() => Prover.CreateProof(CryptoHelpers.ScalarLargestOverflow, new Statement(CryptoHelpers.ScalarLargestOverflow * Generators.G, Generators.G)));
- }
-
[Fact]
public void RandomOverflow()
{
@@ -41,7 +20,7 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
{
mockRandom.GetScalarResults.Add(scalar);
- Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(Scalar.One, new Statement(Scalar.One * Generators.G, Generators.G), mockRandom));
+ Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(new KnowledgeOfDlogParams(Scalar.One, new Statement(Scalar.One * Generators.G, Generators.G)), mockRandom));
}
}
@@ -54,7 +33,7 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
// Don't tolerate if the second zero scalar random is received.
mockRandom.GetScalarResults.Add(Scalar.Zero);
- Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(Scalar.One, new Statement(Scalar.One * Generators.G, Generators.G), mockRandom));
+ Assert.ThrowsAny<InvalidOperationException>(() => Prover.CreateProof(new KnowledgeOfDlogParams(Scalar.One, new Statement(Scalar.One * Generators.G, Generators.G)), mockRandom));
}
}
}

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/StatementTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/StatementTests.cs
@@ -10,7 +10,7 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
public class StatementTests
{
[Fact]
- public void StatementThrows()
+ public void Throws()
{
// Demonstrate when it shouldn't throw.
new Statement(Generators.G, Generators.Ga);

MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/VerifierTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ZeroKnowledge/VerifierTests.cs
@@ -27,7 +27,7 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var challenge = Challenge.Build(nonce, statement);
var response = randomScalar + (secret + Scalar.One) * challenge;
- var proof = new KnowledgeOfDiscreteLog(nonce, response);
+ var proof = new KnowledgeOfDlog(nonce, response);
Assert.False(Verifier.Verify(proof, statement));
// Other false verification tests.
@@ -36,7 +36,7 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
var scalar = new Scalar(11);
var gen = Generators.G;
- proof = new KnowledgeOfDiscreteLog(point1, scalar);
+ proof = new KnowledgeOfDlog(point1, scalar);
var statement2 = new Statement(point2, gen);
Assert.False(Verifier.Verify(proof, statement2));
}
@@ -44,8 +44,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto.ZeroKnowledge
[Fact]
public void Throws()
{
- var dlProof = new KnowledgeOfDiscreteLog(Generators.G, Scalar.One);
- var repProof = new KnowledgeOfRepresentation(Generators.G, Scalar.One, CryptoHelpers.ScalarThree);
+ var dlProof = new KnowledgeOfDlog(Generators.G, Scalar.One);
+ var repProof = new KnowledgeOfRep(Generators.G, Scalar.One, CryptoHelpers.ScalarThree);
// Demonstrate when it shouldn't throw.
var validStatement1 = new Statement(Generators.Ga, Generators.Gg);

RENAME
WalletWasabi/Crypto/ZeroKnowledge/KnowledgeOfDiscreteLog.cs
WalletWasabi/Crypto/ZeroKnowledge/KnowledgeOfDlog.cs
@@ -8,9 +8,9 @@ using WalletWasabi.Helpers;
namespace WalletWasabi.Crypto.ZeroKnowledge
{
- public class KnowledgeOfDiscreteLog : KnowledgeOfRepresentation
+ public class KnowledgeOfDlog : KnowledgeOfRep
{
- public KnowledgeOfDiscreteLog(GroupElement nonce, Scalar response)
+ public KnowledgeOfDlog(GroupElement nonce, Scalar response)
: base(nonce, new[] { response })
{

ADD
WalletWasabi/Crypto/ZeroKnowledge/KnowledgeOfDlogParams.cs
+using NBitcoin.Secp256k1;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace WalletWasabi.Crypto.ZeroKnowledge
+{
+ public class KnowledgeOfDlogParams : KnowledgeOfRepParams
+ {
+ public KnowledgeOfDlogParams(Scalar secret, Statement statement)
+ : base(new[] { secret }, statement)
+ {
+ }
+
+ public Scalar Secret => Secrets.First();
+ }
+}

RENAME
WalletWasabi/Crypto/ZeroKnowledge/KnowledgeOfRepresentation.cs
WalletWasabi/Crypto/ZeroKnowledge/KnowledgeOfRep.cs
@@ -7,9 +7,9 @@ using WalletWasabi.Helpers;
namespace WalletWasabi.Crypto.ZeroKnowledge
{
- public class KnowledgeOfRepresentation
+ public class KnowledgeOfRep
{
- public KnowledgeOfRepresentation(GroupElement nonce, IEnumerable<Scalar> responses)
+ public KnowledgeOfRep(GroupElement nonce, IEnumerable<Scalar> responses)
{
Guard.False($"{nameof(nonce)}.{nameof(nonce.IsInfinity)}", nonce.IsInfinity);
Guard.NotNullOrEmpty(nameof(responses), responses);
@@ -22,7 +22,7 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
Responses = responses;
}
- public KnowledgeOfRepresentation(GroupElement nonce, params Scalar[] responses)
+ public KnowledgeOfRep(GroupElement nonce, params Scalar[] responses)
: this(nonce, responses as IEnumerable<Scalar>)
{
}

ADD
WalletWasabi/Crypto/ZeroKnowledge/KnowledgeOfRepParams.cs
+using NBitcoin.Secp256k1;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using WalletWasabi.Crypto.Groups;
+using WalletWasabi.Helpers;
+
+namespace WalletWasabi.Crypto.ZeroKnowledge
+{
+ public class KnowledgeOfRepParams
+ {
+ public KnowledgeOfRepParams(IEnumerable<Scalar> secrets, Statement statement)
+ {
+ Guard.NotNullOrEmpty(nameof(secrets), secrets);
+ var secretsCount = secrets.Count();
+ IEnumerable<GroupElement> generators = statement.Generators;
+ var generatorsCount = generators.Count();
+ if (secretsCount != generatorsCount)
+ {
+ const string NameofGenerators = nameof(generators);
+ const string NameofSecrets = nameof(secrets);
+ throw new InvalidOperationException($"Must provide exactly as many {NameofGenerators} as {NameofSecrets}. {NameofGenerators}: {generatorsCount}, {NameofSecrets}: {secretsCount}.");
+ }
+
+ var publicPointSanity = statement.PublicPoint;
+ foreach (var (secret, generator) in secrets.ZipForceEqualLength<Scalar, GroupElement>(generators))
+ {
+ Guard.False($"{nameof(secret)}.{nameof(secret.IsOverflow)}", secret.IsOverflow);
+ Guard.False($"{nameof(secret)}.{nameof(secret.IsZero)}", secret.IsZero);
+ publicPointSanity -= secret * generator;
+ }
+
+ if (publicPointSanity != GroupElement.Infinity)
+ {
+ throw new InvalidOperationException($"{nameof(statement.PublicPoint)} was incorrectly constructed.");
+ }
+
+ Secrets = secrets;
+ Statement = statement;
+ }
+
+ public IEnumerable<Scalar> Secrets { get; }
+ public Statement Statement { get; }
+
+ public IEnumerable<(Scalar, GroupElement)> SecretGeneratorPairs => Secrets.ZipForceEqualLength(Statement.Generators);
+ }
+}

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/Prover.cs
WalletWasabi/Crypto/ZeroKnowledge/Prover.cs
@@ -11,55 +11,36 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
{
public static class Prover
{
- public static KnowledgeOfDiscreteLog CreateProof(Scalar secret, Statement statement, WasabiRandom? random = null)
+ public static KnowledgeOfDlog CreateProof(KnowledgeOfDlogParams parameters, WasabiRandom? random = null)
{
- var proof = CreateProof(new Scalar[] { secret }, statement, random);
+ var proof = CreateProof(parameters as KnowledgeOfRepParams, random);
- return new KnowledgeOfDiscreteLog(proof.Nonce, proof.Responses.First());
+ return new KnowledgeOfDlog(proof.Nonce, proof.Responses.First());
}
- public static KnowledgeOfRepresentation CreateProof(IEnumerable<Scalar> secrets, Statement statement, WasabiRandom? random = null)
+ public static KnowledgeOfRep CreateProof(KnowledgeOfRepParams parameters, WasabiRandom? random = null)
{
- var secretsCount = secrets.Count();
- IEnumerable<GroupElement> generators = statement.Generators;
- var generatorsCount = generators.Count();
- if (secretsCount != generatorsCount)
- {
- const string NameofGenerators = nameof(generators);
- const string NameofSecrets = nameof(secrets);
- throw new InvalidOperationException($"Must provide exactly as many {NameofGenerators} as {NameofSecrets}. {NameofGenerators}: {generatorsCount}, {NameofSecrets}: {secretsCount}.");
- }
-
var nonce = GroupElement.Infinity;
var randomScalars = new List<Scalar>();
- var publicPointSanity = statement.PublicPoint;
- foreach (var (secret, generator) in secrets.ZipForceEqualLength<Scalar, GroupElement>(generators))
+ foreach (var (secret, generator) in parameters.SecretGeneratorPairs)
{
- Guard.False($"{nameof(secret)}.{nameof(secret.IsOverflow)}", secret.IsOverflow);
- Guard.False($"{nameof(secret)}.{nameof(secret.IsZero)}", secret.IsZero);
- publicPointSanity -= secret * generator;
-
var randomScalar = GetNonZeroRandomScalar(random);
randomScalars.Add(randomScalar);
var randomPoint = randomScalar * generator;
nonce += randomPoint;
}
- if (publicPointSanity != GroupElement.Infinity)
- {
- throw new InvalidOperationException($"{nameof(statement.PublicPoint)} was incorrectly constructed.");
- }
-
+ var statement = parameters.Statement;
var challenge = Challenge.Build(nonce, statement);
var responses = new List<Scalar>();
- foreach (var (secret, randomScalar) in secrets.ZipForceEqualLength(randomScalars))
+ foreach (var (secret, randomScalar) in parameters.Secrets.ZipForceEqualLength(randomScalars))
{
var response = randomScalar + secret * challenge;
responses.Add(response);
}
- var proof = new KnowledgeOfRepresentation(nonce, responses);
+ var proof = new KnowledgeOfRep(nonce, responses);
// Sanity check:
if (!Verifier.Verify(proof, statement))

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/Verifier.cs
WalletWasabi/Crypto/ZeroKnowledge/Verifier.cs
@@ -9,7 +9,7 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
{
public static class Verifier
{
- public static bool Verify(KnowledgeOfRepresentation proof, Statement statement)
+ public static bool Verify(KnowledgeOfRep proof, Statement statement)
{
var publicPoint = statement.PublicPoint;
if (publicPoint == proof.Nonce)
@@ -31,7 +31,7 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
return a == b;
}
- public static bool Verify(KnowledgeOfDiscreteLog proof, Statement statement)
- => Verify(proof as KnowledgeOfRepresentation, statement);
+ public static bool Verify(KnowledgeOfDlog proof, Statement statement)
+ => Verify(proof as KnowledgeOfRep, statement);
}
}

Introduce KnowledgeOf params