Add MAC Show proof
MODIFY
WalletWasabi.Tests/UnitTests/Crypto/ProofSystemTests.cs
WalletWasabi.Tests/UnitTests/Crypto/ProofSystemTests.cs
@@ -27,8 +27,8 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
// value 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;
+ var r = rnd.GetScalar();
+ var Ma = amount * Generators.G + r * Generators.Gh;
// The coordinator generates a MAC and a proof that the MAC was generated using the
// coordinator's secret key. The coordinator sends the pair (MAC + proofOfMac) back
@@ -43,20 +43,16 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
// was generated with the coordinator's secret key.
var clientStatement = ProofSystem.IssuerParameters(coordinatorParameters, mac, Ma);
var isValidProof = ProofSystem.Verify(clientStatement, proofOfMac);
-
Assert.True(isValidProof);
- ////////
var corruptedResponses = new ScalarVector(proofOfMac.Responses.Reverse());
var invalidProofOfMac = new Proof(proofOfMac.PublicNonces, corruptedResponses);
isValidProof = ProofSystem.Verify(clientStatement, invalidProofOfMac);
-
Assert.False(isValidProof);
var corruptedPublicNonces = new GroupElementVector(proofOfMac.PublicNonces.Reverse());
invalidProofOfMac = new Proof(corruptedPublicNonces, proofOfMac.Responses);
isValidProof = ProofSystem.Verify(clientStatement, invalidProofOfMac);
-
Assert.False(isValidProof);
}
@@ -69,15 +65,65 @@ namespace WalletWasabi.Tests.UnitTests.Crypto
var r = rnd.GetScalar();
var a = rnd.GetScalar();
+ static (GroupElement Ca, GroupElement S) SerialNumberPublicPoints(Scalar z, Scalar a, Scalar r) =>
+ (z * Generators.Ga + r * Generators.Gh + a * Generators.Gg, r * Generators.Gs);
+
+ {
var witness = new ScalarVector(z, a, r);
- var Ca = z * Generators.Ga + r * Generators.Gh + a * Generators.Gg;
- var S = r * Generators.Gs;
+ var (Ca, S) = SerialNumberPublicPoints(z, a, r);
+ var statement = ProofSystem.SerialNumber(Ca, S);
+ var proofOfSerialNumber = ProofSystem.Prove(new Knowledge(statement, witness), rnd);
+
+ var isValidProof = ProofSystem.Verify(statement, proofOfSerialNumber);
+ Assert.True(isValidProof);
+ }
+ // Test zero amount
+ a = Scalar.Zero;
+ {
+ var witness = new ScalarVector(z, a, r);
+ var (Ca, S) = SerialNumberPublicPoints(z, a, r);
var statement = ProofSystem.SerialNumber(Ca, S);
var proofOfSerialNumber = ProofSystem.Prove(new Knowledge(statement, witness), rnd);
- // The coordinator must verify the blinded amout is zero
var isValidProof = ProofSystem.Verify(statement, proofOfSerialNumber);
+ Assert.True(isValidProof);
+ }
+ }
+
+ [Fact]
+ [Trait("UnitTest", "UnitTest")]
+ public void CanProveAndVerifyMacShow()
+ {
+ var rnd = new SecureRandom();
+ var coordinatorKey = new CoordinatorSecretKey(rnd);
+ var coordinatorParameters = coordinatorKey.ComputeCoordinatorParameters();
+
+ // A blinded amount is known as an `attribute`. In this case the attribute Ma is the
+ // value 10000 blinded with a random `blindingFactor`. This attribute is sent to
+ // the coordinator.
+ var amount = new Scalar(10_000);
+ var r = rnd.GetScalar();
+ var Ma = amount * Generators.Gg + r * Generators.Gh;
+
+ // The coordinator generates a MAC and a proof that the 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);
+
+ // The client randomizes the commitments before presenting the them to the coordinator
+ // proves to the coordinator that a credential is valid
+ var z = rnd.GetScalar();
+ var (knowledge, randomizedCommitments) = ProofSystem.MacShow(coordinatorParameters, mac, z, amount, r);
+ var proofOfMacShow = ProofSystem.Prove(knowledge, rnd);
+
+ // The coordinator must verify the received "randomized" credential is valid.
+ var Z = ProofSystem.ComputeZ(randomizedCommitments, coordinatorKey);
+ Assert.Equal(Z, z * coordinatorParameters.I);
+
+ var statement = ProofSystem.MacShow(coordinatorParameters, Z, randomizedCommitments.Cx0, randomizedCommitments.Cx1);
+ var isValidProof = ProofSystem.Verify(statement, proofOfMacShow);
Assert.True(isValidProof);
}

MODIFY
WalletWasabi/Crypto/ZeroKnowledge/ProofSystem.cs
WalletWasabi/Crypto/ZeroKnowledge/ProofSystem.cs
@@ -52,5 +52,28 @@ namespace WalletWasabi.Crypto.ZeroKnowledge
{ Ca, Generators.Ga, Generators.Gg, Generators.Gh },
{ S, O, O, Generators.Gs }
});
+
+ public static (Knowledge knowledge, RandomizedCommitments randomizedCommitments) MacShow(CoordinatorParameters iparams, MAC mac, Scalar z, Scalar a, Scalar r)
+ {
+ var Ca = z * Generators.Ga + a * Generators.Gg + r * Generators.Gh;
+ var Cx0 = z * Generators.Gx0 + mac.U;
+ var Cx1 = z * Generators.Gx1 + mac.T * mac.U;
+ var CV = z * Generators.GV + mac.V;
+ var Z = z * iparams.I;
+
+ return (new Knowledge(MacShow(iparams, Z, Cx0, Cx1), new ScalarVector(z, (mac.T * z).Negate(), mac.T)), new RandomizedCommitments(Ca, Cx0, Cx1, CV));
+ }
+
+ public static Statement MacShow(CoordinatorParameters iparams, GroupElement Z, GroupElement Cx0, GroupElement Cx1)
+ => new Statement(new GroupElement[,]
+ {
+ // public Witness terms:
+ // point z z0 t
+ { Z, iparams.I, O, O },
+ { Cx1, Generators.Gx1, Generators.Gx0, Cx0 }, // Cx1 = z*Gx1 + t*U, z0 cancels t*z*Gx0 out of t*Cx0 leaving z*Gx1 + t*U
+ });
+
+ public static GroupElement ComputeZ(RandomizedCommitments rc, CoordinatorSecretKey sk)
+ => rc.CV - (sk.W * Generators.Gw + sk.X0 * rc.Cx0 + sk.X1 * rc.Cx1 + sk.Ya * rc.Ca);
}
}

ADD
WalletWasabi/Crypto/ZeroKnowledge/RandomizedCommitments.cs
+using WalletWasabi.Crypto.Groups;
+
+namespace WalletWasabi.Crypto.ZeroKnowledge
+{
+ public class RandomizedCommitments
+ {
+ public RandomizedCommitments(GroupElement Ca, GroupElement Cx0, GroupElement Cx1, GroupElement CV)
+ {
+ this.Ca = Ca;
+ this.Cx0 = Cx0;
+ this.Cx1 = Cx1;
+ this.CV = CV;
+ }
+
+ public GroupElement Ca { get; }
+ public GroupElement Cx0 { get; }
+ public GroupElement Cx1 { get; }
+ public GroupElement CV { get; }
+ }
+}
\ No newline at end of file

Add MAC Show proof