Proof of iparams
ADD
WalletWasabi.Tests/UnitTests/Crypto/ProofSystemTests.cs
+using System;
+using NBitcoin.Secp256k1;
+using WalletWasabi.Crypto;
+using WalletWasabi.Crypto.Groups;
+using WalletWasabi.Crypto.Randomness;
+using WalletWasabi.Crypto.ZeroKnowledge;
+using Xunit;
+
+namespace WalletWasabi.Tests.UnitTests.Crypto
+{
+ public class ProofSystemTests
+ {
+ [Fact]
+ [Trait("UnitTest", "UnitTest")]
+ public void CanProveAndVerifyMAC()
+ {
+ // The coordinator generates a composed private key called CoordinatorSecretKey
+ // and derives from that the coordinator's public parameters called CoordinatorParameters.
+ var rnd = new SecureRandom();
+ var coordinatorKey = new CoordinatorSecretKey(rnd);
+ var coordinatorParameters = coordinatorKey.ComputeCoordinatorParameters();
+
+ // A blinded amout is known as an `attribute`. In this case the attribute Ma is the
+ // valued 10000 blinded with a random `blindingFactor`. This attribute is sent to
+ // the coordinator.
+ var amount = new Scalar(10_000);
+ var blindingFactor = rnd.GetScalar();
+ var Ma = amount * Generators.G + blindingFactor * Generators.Gh;
+
+ // The coordinator generates a MAC and a proof that that MAC was generated using the
+ // coordinator's secret key. The coordinator sends the pair (MAC + proofOfMac) back
+ // to the client.
+ var t = rnd.GetScalar();
+ var mac = MAC.ComputeMAC(coordinatorKey, Ma, t);
+
+ var coordinatorStatement = ProofSystem.CreateStatement(coordinatorParameters.Cw, coordinatorParameters.I, mac.V, MAC.GenerateU(t), Ma, t);
+ var proverBuilder = ProofSystem.CreateProver(coordinatorStatement.ToKnowledge(coordinatorKey.GetWitness(t)));
+ var macProver = proverBuilder(rnd);
+ var proofOfMac = macProver();
+
+ // The client receives the MAC and the proofOfMac which let the client know that the MAC
+ // was generated with the coordinator's secret key.
+ var clientStatement = ProofSystem.CreateStatement(coordinatorParameters.Cw, coordinatorParameters.I, mac.V, MAC.GenerateU(mac.T), Ma, mac.T);
+ var verifierBuilder = ProofSystem.CreateVerifier(clientStatement);
+ var macVerifier = verifierBuilder(proofOfMac);
+ var isValidProof = macVerifier();
+
+ Assert.True(isValidProof);
+ }
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi/Crypto/CoordinatorSecretKey.cs
WalletWasabi/Crypto/CoordinatorSecretKey.cs
@@ -30,5 +30,8 @@ namespace WalletWasabi.Crypto
new CoordinatorParameters(
cw: W * Generators.Gw + Wp * Generators.Gwp,
i: Generators.GV - (X0 * Generators.Gx0 + X1 * Generators.Gx1 + Ya * Generators.Ga));
+
+ public ScalarVector GetWitness(Scalar t) =>
+ new ScalarVector(W, Wp, X0, X1, t, Ya);
}
}

MODIFY
WalletWasabi/Crypto/Mac.cs
WalletWasabi/Crypto/Mac.cs
@@ -45,7 +45,7 @@ namespace WalletWasabi.Crypto
private static MAC ComputeAlgebraicMAC((Scalar x0, Scalar x1) sk, GroupElement m, Scalar t) =>
new MAC(t, (sk.x0 + sk.x1 * t) * GenerateU(t) + m);
- private static GroupElement GenerateU(Scalar t) =>
+ public static GroupElement GenerateU(Scalar t) =>
Generators.FromBuffer(t.ToBytes());
}
}

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/LinearRelation/Statement.cs
WalletWasabi/Crypto/ZeroKnowledge/LinearRelation/Statement.cs
@@ -37,6 +37,9 @@ namespace WalletWasabi.Crypto.ZeroKnowledge.LinearRelation
public IEnumerable<GroupElement> Generators =>
Equations.SelectMany(x => x.Generators);
+ public Knowledge ToKnowledge(ScalarVector witness) =>
+ new Knowledge(this, witness);
+
public bool CheckVerificationEquation(GroupElementVector publicNonces, Scalar challenge, IEnumerable<ScalarVector> allResponses)
{
// The responses matrix should match the generators in the equations and

ADD
WalletWasabi/Crypto/ZeroKnowledge/ProofSystem.cs
+using NBitcoin.Secp256k1;
+using System.Linq;
+using System.Text;
+using WalletWasabi.Crypto.Groups;
+using WalletWasabi.Crypto.ZeroKnowledge.LinearRelation;
+
+namespace WalletWasabi.Crypto.ZeroKnowledge
+{
+ public static class ProofSystem
+ {
+ private static GroupElement Inf = GroupElement.Infinity;
+ private static Transcript Transcript => new Transcript(Encoding.UTF8.GetBytes("proof-of-parameters"));
+
+ private static GroupElementVector[] ProofOfParametersGenerators(GroupElement U, GroupElement Ma, Scalar t) =>
+ new GroupElementVector[]
+ {
+ new GroupElementVector( Generators.Gw, Generators.Gwp, Inf, Inf, Inf, Inf ),
+ new GroupElementVector( Inf, Inf, Generators.Gx0, Generators.Gx1, Inf, Generators.Ga ),
+ new GroupElementVector( Generators.Gw, Inf, U, t*U, Inf, Ma )
+ };
+
+ public static LinearRelation.Statement CreateStatement(GroupElement Cw, GroupElement I, GroupElement V, GroupElement U, GroupElement Ma, Scalar t) =>
+ new LinearRelation.Statement(new[] {Cw, Generators.GV - I, V}.Zip(ProofOfParametersGenerators(U, Ma, t), (publicPoint, groupElement)
+ => new Equation (publicPoint, groupElement)));
+
+ public static NonInteractive.FiatShamirTransform.VerifierCommitToNonces CreateVerifier(LinearRelation.Statement statement) =>
+ new NonInteractive.FiatShamirTransform.Verifier(statement).CommitToStatements(Transcript);
+
+ public static NonInteractive.FiatShamirTransform.ProverCommitToNonces CreateProver(LinearRelation.Knowledge knowledge) =>
+ new NonInteractive.FiatShamirTransform.Prover(knowledge).CommitToStatements(Transcript);
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/Transcript.cs
WalletWasabi/Crypto/ZeroKnowledge/Transcript.cs
@@ -60,7 +60,7 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
public void CommitStatement(LinearRelation.Statement statement)
{
- CryptoGuard.NotNullOrInfinity(nameof(statement.Generators), statement.Generators);
+ //CryptoGuard.NotNullOrInfinity(nameof(statement.Generators), statement.Generators);
CryptoGuard.NotNullOrInfinity(nameof(statement.PublicPoints), statement.PublicPoints);
AddMessages(StatementTag, statement.PublicPoints.Select(x => x.ToBytes()).Concat(statement.Generators.Select(x => x.ToBytes())));
}

Proof of iparams