예제 #1
0
        public void CanProveAndVerifyZeroProofs()
        {
            using var rnd = new SecureRandom();

            var a0  = Scalar.Zero;
            var r0  = rnd.GetScalar();
            var ma0 = a0 * Generators.Gg + r0 * Generators.Gh;

            var a1  = Scalar.Zero;
            var r1  = rnd.GetScalar();
            var ma1 = a1 * Generators.Gg + r1 * Generators.Gh;

            var knowledge = new[]
            {
                ProofSystem.ZeroProofKnowledge(ma0, r0),
                ProofSystem.ZeroProofKnowledge(ma1, r1)
            };

            var proofs = ProofSystem.Prove(new Transcript(Array.Empty <byte>()), knowledge, rnd);

            var statements = new[]
            {
                ProofSystem.ZeroProofStatement(ma0),
                ProofSystem.ZeroProofStatement(ma1)
            };

            Assert.True(ProofSystem.Verify(new Transcript(Array.Empty <byte>()), statements, proofs));
        }
예제 #2
0
        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 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 blindingFactor = rnd.GetScalar();
            var Ma             = amount * Generators.G + blindingFactor * 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);

            var coordinatorStatement = ProofSystem.CreateStatement(coordinatorParameters, mac.V, Ma, t);
            var proverBuilder        = ProofSystem.CreateProver(coordinatorStatement, coordinatorKey);
            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, mac.V, Ma, mac.T);
            var verifierBuilder = ProofSystem.CreateVerifier(clientStatement);
            var macVerifier     = verifierBuilder(proofOfMac);
            var isValidProof    = macVerifier();

            Assert.True(isValidProof);
        }
예제 #3
0
        public void CanProveAndVerifyBalance(int presentedAmount, int requestedAmount)
        {
            var rnd = new SecureRandom();

            var a  = new Scalar((uint)presentedAmount);
            var r  = rnd.GetScalar();
            var z  = rnd.GetScalar();
            var Ca = z * Generators.Ga + a * Generators.Gg + r * Generators.Gh;

            var ap = new Scalar((uint)requestedAmount);
            var rp = rnd.GetScalar();
            var Ma = ap * Generators.Gg + rp * Generators.Gh;

            var delta = new Scalar((uint)Math.Abs(presentedAmount - requestedAmount));

            delta = presentedAmount > requestedAmount?delta.Negate() : delta;

            var knowledge = ProofSystem.BalanceProof(z, r + rp.Negate());

            var proofOfBalance = ProofSystem.Prove(knowledge, rnd);

            var statement = ProofSystem.BalanceProof(Ca + delta * Generators.Gg - Ma);

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

            var badStatement = ProofSystem.BalanceProof(Ca + (delta + Scalar.One) * Generators.Gg - Ma);

            Assert.False(ProofSystem.Verify(badStatement, proofOfBalance));
        }
        public void CanProveAndVerifyZeroProofs()
        {
            var rnd = new SecureRandom();

            var a0  = Scalar.Zero;
            var r0  = rnd.GetScalar();
            var Ma0 = a0 * Generators.Gg + r0 * Generators.Gh;

            var a1  = Scalar.Zero;
            var r1  = rnd.GetScalar();
            var Ma1 = a1 * Generators.Gg + r1 * Generators.Gh;

            var knowledge = new[]
            {
                ProofSystem.ZeroProof(Ma0, r0),
                ProofSystem.ZeroProof(Ma1, r1)
            };

            var proofs = ProofSystem.Prove(new Transcript(new byte[0]), knowledge, rnd);

            var statements = new[]
            {
                ProofSystem.ZeroProofStmt(Ma0),
                ProofSystem.ZeroProofStmt(Ma1)
            };

            Assert.True(ProofSystem.Verify(new Transcript(new byte[0]), statements, proofs));
        }
예제 #5
0
        public void EqualityTests()
        {
            using var rnd = new SecureRandom();

            var right = (attribute : rnd.GetScalar() * Generators.G, sk : new CredentialIssuerSecretKey(rnd), t : rnd.GetScalar());
            var wrong = (attribute : rnd.GetScalar() * Generators.G, sk : new CredentialIssuerSecretKey(rnd), t : rnd.GetScalar());

            var cases = new[]
예제 #6
0
        public void EqualityTests()
        {
            var rnd = new SecureRandom();

            var right = (attribute : rnd.GetScalar() * Generators.G, sk : new CoordinatorSecretKey(rnd), t : rnd.GetScalar());
            var wrong = (attribute : rnd.GetScalar() * Generators.G, sk : new CoordinatorSecretKey(rnd), t : rnd.GetScalar());

            var cases = new[]
예제 #7
0
        public void CanProduceAndVerifyMAC()
        {
            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var attribute = rnd.GetScalar() * Generators.G;              // any random point
            var t         = rnd.GetScalar();

            var mac = MAC.ComputeMAC(sk, attribute, t);

            Assert.True(mac.VerifyMAC(sk, attribute));
        }
예제 #8
0
        public void EqualityTests()
        {
            var rnd = new SecureRandom();
            var sk  = new CoordinatorSecretKey(rnd);

            var attribute          = rnd.GetScalar() * Generators.G;     // any random point
            var differentAttribute = rnd.GetScalar() * Generators.G;     // any other random point
            var t = rnd.GetScalar();

            var right = (attribute : rnd.GetScalar() * Generators.G, sk : new CoordinatorSecretKey(rnd), t : rnd.GetScalar());
            var wrong = (attribute : rnd.GetScalar() * Generators.G, sk : new CoordinatorSecretKey(rnd), t : rnd.GetScalar());

            var cases = new[]
예제 #9
0
        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 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(coordinatorKey, Ma, t);

            var coordinatorKnowledge = ProofSystem.IssuerParameters(mac, Ma, coordinatorKey);
            var proofOfMac           = ProofSystem.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.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);
        }
예제 #10
0
        public void SyntheticNoncesTest()
        {
            var protocol = Encoding.UTF8.GetBytes("test TranscriptRng collisions");

            using var rnd = new SecureRandom();

            var commitment1 = new[] { Generators.Gx0 };
            var commitment2 = new[] { Generators.Gx1 };
            var witness1    = new[] { rnd.GetScalar() };
            var witness2    = new[] { rnd.GetScalar() };

            var transcript1 = new Transcript(protocol);
            var transcript2 = new Transcript(protocol);
            var transcript3 = new Transcript(protocol);
            var transcript4 = new Transcript(protocol);

            transcript1.CommitPublicNonces(commitment1);
            transcript2.CommitPublicNonces(commitment2);
            transcript3.CommitPublicNonces(commitment2);
            transcript4.CommitPublicNonces(commitment2);

            var secretNonceProvider1 = transcript1.CreateSyntheticSecretNonceProvider(witness1, rnd);
            var secretNonceProvider2 = transcript2.CreateSyntheticSecretNonceProvider(witness1, rnd);
            var secretNonceProvider3 = transcript3.CreateSyntheticSecretNonceProvider(witness2, rnd);
            var secretNonceProvider4 = transcript4.CreateSyntheticSecretNonceProvider(witness2, rnd);

            var secretNonce1 = secretNonceProvider1.GetScalar();
            var secretNonce2 = secretNonceProvider2.GetScalar();
            var secretNonce3 = secretNonceProvider3.GetScalar();
            var secretNonce4 = secretNonceProvider4.GetScalar();

            Assert.NotEqual(secretNonce1, secretNonce2);
            Assert.NotEqual(secretNonce1, secretNonce3);
            Assert.NotEqual(secretNonce1, secretNonce4);

            Assert.NotEqual(secretNonce2, secretNonce3);
            Assert.NotEqual(secretNonce2, secretNonce4);

            Assert.NotEqual(secretNonce3, secretNonce4);
        }
예제 #11
0
        public void SyntheticNoncesTest()
        {
            var protocol = Encoding.UTF8.GetBytes("test TranscriptRng collisions");
            var rnd      = new SecureRandom();

            var commitment1 = new[] { Generators.Gx0 };
            var commitment2 = new[] { Generators.Gx1 };
            var witness1    = new[] { rnd.GetScalar() };
            var witness2    = new[] { rnd.GetScalar() };

            var transcript1 = new Transcript(protocol);
            var transcript2 = new Transcript(protocol);
            var transcript3 = new Transcript(protocol);
            var transcript4 = new Transcript(protocol);

            transcript1.CommitPublicNonces(commitment1);
            transcript2.CommitPublicNonces(commitment2);
            transcript3.CommitPublicNonces(commitment2);
            transcript4.CommitPublicNonces(commitment2);

            var publicNonceGenerator1 = transcript1.CreateSyntheticPublicNoncesProvider(witness1, rnd);
            var publicNonceGenerator2 = transcript2.CreateSyntheticPublicNoncesProvider(witness1, rnd);
            var publicNonceGenerator3 = transcript3.CreateSyntheticPublicNoncesProvider(witness2, rnd);
            var publicNonceGenerator4 = transcript4.CreateSyntheticPublicNoncesProvider(witness2, rnd);

            var publicNonce1 = publicNonceGenerator1().First();
            var publicNonce2 = publicNonceGenerator2().First();
            var publicNonce3 = publicNonceGenerator3().First();
            var publicNonce4 = publicNonceGenerator4().First();

            Assert.NotEqual(publicNonce1, publicNonce2);
            Assert.NotEqual(publicNonce1, publicNonce3);
            Assert.NotEqual(publicNonce1, publicNonce4);

            Assert.NotEqual(publicNonce2, publicNonce3);
            Assert.NotEqual(publicNonce2, publicNonce4);

            Assert.NotEqual(publicNonce3, publicNonce4);
        }
예제 #12
0
        public void CanProveAndVerifyPresentedBalance()
        {
            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.BalanceProof(z, r);
            var proofOfBalance = ProofSystem.Prove(knowledge, rnd);

            var statement = ProofSystem.BalanceProof(Ca - a * Generators.Gg);

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

            var badStatement = ProofSystem.BalanceProof(Ca + Generators.Gg - a * Generators.Gg);

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

            badStatement = ProofSystem.BalanceProof(Ca);
            Assert.False(ProofSystem.Verify(badStatement, proofOfBalance));
        }
예제 #13
0
        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 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.ShowCredential(randomizedCredential, z, credential, coordinatorParameters);
            var proofOfMacShow       = ProofSystem.Prove(knowledge, rnd);

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

            Assert.Equal(Z, z * coordinatorParameters.I);

            var statement    = ProofSystem.ShowCredential(randomizedCredential, Z, coordinatorParameters);
            var isValidProof = ProofSystem.Verify(statement, proofOfMacShow);

            Assert.True(isValidProof);
        }
예제 #14
0
        public void CanDetectInvalidMAC()
        {
            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var attribute          = rnd.GetScalar() * Generators.G;     // any random point
            var differentAttribute = rnd.GetScalar() * Generators.G;     // any other random point
            var t = rnd.GetScalar();

            // Create MAC for realAttribute and verify with fake/wrong attribute
            var mac = MAC.ComputeMAC(sk, attribute, t);

            Assert.False(mac.VerifyMAC(sk, differentAttribute));

            var differentT   = rnd.GetScalar();
            var differentMac = MAC.ComputeMAC(sk, attribute, differentT);

            Assert.NotEqual(mac, differentMac);

            mac = MAC.ComputeMAC(sk, attribute, differentT);
            var differentSk = new CredentialIssuerSecretKey(rnd);

            Assert.False(mac.VerifyMAC(differentSk, attribute));
        }
예제 #15
0
        public void CanProveAndVerifyRequestedBalance()
        {
            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.BalanceProof(Scalar.Zero, r.Negate());
            var proofOfBalance = ProofSystem.Prove(knowledge, rnd);

            var statement = ProofSystem.BalanceProof(a * Generators.Gg - Ma);

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

            var badStatement = ProofSystem.BalanceProof(Ma);

            Assert.False(ProofSystem.Verify(badStatement, proofOfBalance));
        }
예제 #16
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.RangeProof(maskedScalar, randomness, width, rnd);

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

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

            if (!pass)
            {
                Assert.Throws <ArgumentOutOfRangeException>(() => ProofSystem.RangeProof(amountScalar, randomness, width, rnd));
            }
        }
예제 #17
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));
            }
        }