Example #1
0
        public void CanProveAndVerifyMAC()
        {
            // The coordinator generates a composed private key called CredentialIssuerSecretKey
            // and derives from that the coordinator's public parameters called credentialIssuerParameters.
            using var rnd = new SecureRandom();
            var credentialIssuerKey        = new CredentialIssuerSecretKey(rnd);
            var credentialIssuerParameters = credentialIssuerKey.ComputeCredentialIssuerParameters();

            // 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.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
            // to the client.
            var t   = rnd.GetScalar();
            var mac = MAC.ComputeMAC(credentialIssuerKey, ma, t);

            var coordinatorKnowledge = ProofSystem.IssuerParametersKnowledge(mac, ma, credentialIssuerKey);
            var proofOfMac           = ProofSystemHelpers.Prove(coordinatorKnowledge, rnd);

            // 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.IssuerParametersStatement(credentialIssuerParameters, mac, ma);
            var isValidProof    = ProofSystemHelpers.Verify(clientStatement, proofOfMac);

            Assert.True(isValidProof);

            var corruptedResponses = new ScalarVector(proofOfMac.Responses.Reverse());
            var invalidProofOfMac  = new Proof(proofOfMac.PublicNonces, corruptedResponses);

            isValidProof = ProofSystemHelpers.Verify(clientStatement, invalidProofOfMac);
            Assert.False(isValidProof);

            var corruptedPublicNonces = new GroupElementVector(proofOfMac.PublicNonces.Reverse());

            invalidProofOfMac = new Proof(corruptedPublicNonces, proofOfMac.Responses);
            isValidProof      = ProofSystemHelpers.Verify(clientStatement, invalidProofOfMac);
            Assert.False(isValidProof);
        }
Example #2
0
        public void CanProveAndVerifyRequestedBalance()
        {
            using var rnd = new SecureRandom();

            var a  = new Scalar(10_000u);
            var r  = rnd.GetScalar();
            var ma = a * Generators.Gg + r * Generators.Gh;

            var knowledge      = ProofSystem.BalanceProofKnowledge(Scalar.Zero, r.Negate());
            var proofOfBalance = ProofSystemHelpers.Prove(knowledge, rnd);

            var statement = ProofSystem.BalanceProofStatement(a * Generators.Gg - ma);

            Assert.True(ProofSystemHelpers.Verify(statement, proofOfBalance));

            var badStatement = ProofSystem.BalanceProofStatement(ma);

            Assert.False(ProofSystemHelpers.Verify(badStatement, proofOfBalance));
        }
Example #3
0
        public void CanProveAndVerifyCommitmentRange(ulong amount, int width, bool pass)
        {
            var rnd = new SecureRandom();

            var amountScalar = new Scalar(amount);
            var randomness   = rnd.GetScalar();
            var commitment   = amountScalar * Generators.Gg + randomness * Generators.Gh;

            var maskedScalar = new Scalar(amount & ((1ul << width) - 1));

            var(knowledge, bitCommitments) = ProofSystem.RangeProofKnowledge(maskedScalar, randomness, width, rnd);

            var rangeProof = ProofSystemHelpers.Prove(knowledge, rnd);

            Assert.Equal(pass, ProofSystemHelpers.Verify(ProofSystem.RangeProofStatement(commitment, bitCommitments), rangeProof));

            if (!pass)
            {
                Assert.Throws <ArgumentException>(() => ProofSystem.RangeProofKnowledge(amountScalar, randomness, width, rnd));
            }
        }
Example #4
0
        public void CanProveAndVerifyCommitmentRange(ulong amount, int width, bool pass)
        {
            using var rnd = new SecureRandom();

            var amountScalar = new Scalar(amount);
            var randomness   = rnd.GetScalar();
            var commitment   = amountScalar * Generators.Gg + randomness * Generators.Gh;

            // First, generate a proof for the given statement. This proof may
            // be invalid (verification equation fails to hold) if the statement
            // is in fact wrong, in which case the verifier should reject.
            var(knowledge, bitCommitments) = ProofSystem.RangeProofKnowledge(amountScalar, randomness, width, rnd);

            var rangeProof = ProofSystemHelpers.Prove(knowledge, rnd);

            Assert.Equal(pass, ProofSystemHelpers.Verify(ProofSystem.RangeProofStatement(commitment, bitCommitments, width), rangeProof));

            if (!pass)
            {
                Assert.Throws <ArgumentException>(() => knowledge.AssertSoundness());

                // When the statement is unprovable, modify the secret input by
                // clearing the high bits to make sure that the proof is always
                // formally valid, but when the original statement is false this
                // will be a valid proof of a different statement. The verifier
                // should still reject.
                var maskedScalar = new Scalar(amount & ((1ul << width) - 1));

                var(knowledgeOfSomethingElse, incompleteBitCommitments) = ProofSystem.RangeProofKnowledge(maskedScalar, randomness, width, rnd);

                var incorrectRangeProof = ProofSystemHelpers.Prove(knowledgeOfSomethingElse, rnd);

                Assert.False(ProofSystemHelpers.Verify(ProofSystem.RangeProofStatement(commitment, incompleteBitCommitments, width), incorrectRangeProof));

                // For completeness, make sure other corrupted statements are also rejected
                Assert.False(ProofSystemHelpers.Verify(ProofSystem.RangeProofStatement(commitment, bitCommitments, width), incorrectRangeProof));
                Assert.False(ProofSystemHelpers.Verify(ProofSystem.RangeProofStatement(commitment, incompleteBitCommitments, width), rangeProof));
            }
        }
Example #5
0
        public void CanProveAndVerifyPresentedBalance()
        {
            using var rnd = new SecureRandom();

            var a  = new Scalar(10_000u);
            var r  = rnd.GetScalar();
            var z  = rnd.GetScalar();
            var ca = z * Generators.Ga + a * Generators.Gg + r * Generators.Gh;

            var knowledge      = ProofSystem.BalanceProofKnowledge(z, r);
            var proofOfBalance = ProofSystemHelpers.Prove(knowledge, rnd);

            var statement = ProofSystem.BalanceProofStatement(ca - a * Generators.Gg);

            Assert.True(ProofSystemHelpers.Verify(statement, proofOfBalance));

            var badStatement = ProofSystem.BalanceProofStatement(ca + Generators.Gg - a * Generators.Gg);

            Assert.False(ProofSystemHelpers.Verify(badStatement, proofOfBalance));

            badStatement = ProofSystem.BalanceProofStatement(ca);
            Assert.False(ProofSystemHelpers.Verify(badStatement, proofOfBalance));
        }
Example #6
0
        public void CanProveAndVerifyMacShow()
        {
            using var rnd = new SecureRandom();
            var credentialIssuerKey        = new CredentialIssuerSecretKey(rnd);
            var credentialIssuerParameters = credentialIssuerKey.ComputeCredentialIssuerParameters();

            // 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(credentialIssuerKey, ma, t);

            // The client randomizes the commitments before presenting them to the coordinator proving to
            // the coordinator that a credential is valid (prover knows a valid MAC on non-randomized attribute)
            var credential           = new Credential(amount, r, mac);
            var z                    = rnd.GetScalar();
            var randomizedCredential = credential.Present(z);
            var knowledge            = ProofSystem.ShowCredentialKnowledge(randomizedCredential, z, credential, credentialIssuerParameters);
            var proofOfMacShow       = ProofSystemHelpers.Prove(knowledge, rnd);

            // The coordinator must verify the received randomized credential is valid.
            var capitalZ = randomizedCredential.ComputeZ(credentialIssuerKey);

            Assert.Equal(capitalZ, z * credentialIssuerParameters.I);

            var statement    = ProofSystem.ShowCredentialStatement(randomizedCredential, capitalZ, credentialIssuerParameters);
            var isValidProof = ProofSystemHelpers.Verify(statement, proofOfMacShow);

            Assert.True(isValidProof);
        }