Exemplo n.º 1
0
        public void CredentialIssuance()
        {
            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), rnd, 4300000000000, new ZeroCredentialPool());

            {
                // Null request. This requests `numberOfCredentials` zero-value credentials.
                var(credentialRequest, validationData) = client.CreateRequestForZeroAmount();

                Assert.True(credentialRequest.IsNullRequest);
                Assert.Equal(ProtocolConstants.CredentialNumber, credentialRequest.Requested.Count());
                var requested = credentialRequest.Requested.ToArray();
                Assert.Empty(requested[0].BitCommitments);
                Assert.Empty(requested[1].BitCommitments);
                Assert.Equal(0, credentialRequest.Delta);

                // Issuer part.
                var issuer = new CredentialIssuer(sk, rnd, 4300000000000);

                var credentialResponse  = issuer.HandleRequest(credentialRequest);
                var valuableCredentials = client.HandleResponse(credentialResponse, validationData);
                Assert.Empty(valuableCredentials);
                var issuedCredential = client.Credentials.TakeZeroValue().First();
                Assert.True(issuedCredential.Amount.IsZero);
            }

            {
                var present = client.Credentials.TakeZeroValue();
                var(credentialRequest, validationData) = client.CreateRequest(new[] { 100_000_000L }, present);
Exemplo n.º 2
0
 /// <summary>
 /// Initializes a new instance of the CredentialIssuer class.
 /// </summary>
 /// <param name="credentialIssuerSecretKey">The <see cref="CredentialIssuerSecretKey">coordinator's secret key</see> used to issue the credentials.</param>
 /// <param name="numberOfCredentials">The number of credentials that the protocol handles in each request/response.</param>
 /// <param name="randomNumberGenerator">The random number generator.</param>
 public CredentialIssuer(CredentialIssuerSecretKey credentialIssuerSecretKey, int numberOfCredentials, WasabiRandom randomNumberGenerator)
 {
     CredentialIssuerSecretKey  = Guard.NotNull(nameof(credentialIssuerSecretKey), credentialIssuerSecretKey);
     NumberOfCredentials        = Guard.InRangeAndNotNull(nameof(numberOfCredentials), numberOfCredentials, 1, 100);
     CredentialIssuerParameters = CredentialIssuerSecretKey.ComputeCredentialIssuerParameters();
     RandomNumberGenerator      = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator);
 }
Exemplo n.º 3
0
    public void CannotBuildWrongMac()
    {
        var sk = new CredentialIssuerSecretKey(Rnd);

        Assert.Throws <ArgumentNullException>(() => MAC.ComputeMAC(null !, Generators.G, Scalar.One));
        Assert.Throws <ArgumentNullException>(() => MAC.ComputeMAC(sk, null !, Scalar.One));
        var ex = Assert.Throws <ArgumentException>(() => MAC.ComputeMAC(sk, Generators.G, Scalar.Zero));

        Assert.StartsWith("Value cannot be zero.", ex.Message);
    }
Exemplo n.º 4
0
    public void CanProduceAndVerifyMAC()
    {
        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));
    }
Exemplo n.º 5
0
 /// <summary>
 /// Initializes a new instance of the CredentialIssuer class.
 /// </summary>
 /// <param name="credentialIssuerSecretKey">The <see cref="CredentialIssuerSecretKey">coordinator's secret key</see> used to issue the credentials.</param>
 /// <param name="randomNumberGenerator">The random number generator.</param>
 public CredentialIssuer(
     CredentialIssuerSecretKey credentialIssuerSecretKey,
     WasabiRandom randomNumberGenerator,
     long maxAmount)
 {
     MaxAmount                  = maxAmount;
     RangeProofWidth            = (int)Math.Ceiling(Math.Log2(MaxAmount));
     CredentialIssuerSecretKey  = Guard.NotNull(nameof(credentialIssuerSecretKey), credentialIssuerSecretKey);
     CredentialIssuerParameters = CredentialIssuerSecretKey.ComputeCredentialIssuerParameters();
     RandomNumberGenerator      = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator);
 }
Exemplo n.º 6
0
        public void Splitting()
        {
            // Split 10 sats into 1, 1, 1, 1, 6.
            var numberOfCredentials = 2;

            using var rnd = new SecureRandom();
            var sk     = new CredentialIssuerSecretKey(rnd);
            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd, 4300000000000);
            var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd, 4300000000000);

            // Input Reg
            var(zeroCredentialRequest, zeroValidationData) = client.CreateRequestForZeroAmount();
            var zeroCredentialResponse = issuer.HandleRequest(zeroCredentialRequest);

            client.HandleResponse(zeroCredentialResponse, zeroValidationData);

            // Connection Conf
            var(credentialRequest, validationData)      = client.CreateRequest(new[] { 1L, 9L }, Array.Empty <Credential>());
            (zeroCredentialRequest, zeroValidationData) = client.CreateRequestForZeroAmount();

            Assert.Equal(10, credentialRequest.Delta);
            zeroCredentialResponse = issuer.HandleRequest(zeroCredentialRequest);
            var credentialResponse = issuer.HandleRequest(credentialRequest);

            client.HandleResponse(zeroCredentialResponse, zeroValidationData);
            client.HandleResponse(credentialResponse, validationData);

            // Output Reg
            (credentialRequest, validationData) = client.CreateRequest(new[] { 1L, 8L }, client.Credentials.Valuable);
            credentialResponse = issuer.HandleRequest(credentialRequest);
            client.HandleResponse(credentialResponse, validationData);
            Assert.Equal(-1, credentialRequest.Delta);

            (credentialRequest, validationData) = client.CreateRequest(new[] { 1L, 7L }, client.Credentials.Valuable);
            credentialResponse = issuer.HandleRequest(credentialRequest);
            client.HandleResponse(credentialResponse, validationData);
            Assert.Equal(-1, credentialRequest.Delta);

            (credentialRequest, validationData) = client.CreateRequest(new[] { 1L, 6L }, client.Credentials.Valuable);
            credentialResponse = issuer.HandleRequest(credentialRequest);
            client.HandleResponse(credentialResponse, validationData);
            Assert.Equal(-1, credentialRequest.Delta);

            (credentialRequest, validationData) = client.CreateRequest(Array.Empty <long>(), client.Credentials.Valuable.Where(x => x.Amount == Scalar.One).Take(1));
            credentialResponse = issuer.HandleRequest(credentialRequest);
            client.HandleResponse(credentialResponse, validationData);
            Assert.Equal(-1, credentialRequest.Delta);

            (credentialRequest, validationData) = client.CreateRequest(Array.Empty <long>(), client.Credentials.Valuable.Take(1));
            credentialResponse = issuer.HandleRequest(credentialRequest);
            client.HandleResponse(credentialResponse, validationData);
            Assert.Equal(-6, credentialRequest.Delta);
        }
Exemplo n.º 7
0
        public void CorrectRangeProof()
        {
            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), rnd, 4300000000000, new ZeroCredentialPool());
            var issuer = new CredentialIssuer(sk, rnd, 4300000000000);

            Assert.Equal(42, client.RangeProofWidth);
            Assert.Equal(42, issuer.RangeProofWidth);

            client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), rnd, 4400000000001, new ZeroCredentialPool());
            issuer = new CredentialIssuer(sk, rnd, 4400000000001);
            Assert.Equal(43, client.RangeProofWidth);
            Assert.Equal(43, issuer.RangeProofWidth);
        }
Exemplo n.º 8
0
    public void CorrectRangeProof()
    {
        SecureRandom rnd = SecureRandom.Instance;
        var          sk  = new CredentialIssuerSecretKey(rnd);

        var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), rnd, 4300000000000);
        var issuer = new CredentialIssuer(sk, rnd, 4300000000000);

        Assert.Equal(42, client.RangeProofWidth);
        Assert.Equal(42, issuer.RangeProofWidth);

        client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), rnd, 4400000000001);
        issuer = new CredentialIssuer(sk, rnd, 4400000000001);
        Assert.Equal(43, client.RangeProofWidth);
        Assert.Equal(43, issuer.RangeProofWidth);
    }
Exemplo n.º 9
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);
        }
Exemplo n.º 10
0
        public void GenerateCredentialIssuerParameters()
        {
            // Coordinator key is (0, 0, 0, 0, 0)
            var mockRandom = new Mock <WasabiRandom>();

            mockRandom.Setup(rnd => rnd.GetScalar(true)).Returns(Scalar.Zero);
            var key = new CredentialIssuerSecretKey(mockRandom.Object);
            var ex  = Assert.Throws <ArgumentException>(key.ComputeCredentialIssuerParameters);

            Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);

            // Coordinator key is (0, 0, 1, 1, 1)
            mockRandom.SetupSequence(rnd => rnd.GetScalar(true))
            .Returns(Scalar.Zero)
            .Returns(Scalar.Zero)
            .Returns(Scalar.One)
            .Returns(Scalar.One)
            .Returns(Scalar.One);
            key = new CredentialIssuerSecretKey(mockRandom.Object);
            ex  = Assert.Throws <ArgumentException>(key.ComputeCredentialIssuerParameters);
            Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);

            // Coordinator key is (1, 1, 0, 0, 0)
            mockRandom.SetupSequence(rnd => rnd.GetScalar(true))
            .Returns(Scalar.One)
            .Returns(Scalar.One)
            .Returns(Scalar.Zero)
            .Returns(Scalar.Zero)
            .Returns(Scalar.Zero);
            key = new CredentialIssuerSecretKey(mockRandom.Object);
            var iparams = key.ComputeCredentialIssuerParameters();

            Assert.Equal(Generators.GV, iparams.I);

            // Coordinator key is (1, 1, 1, 1, 1)
            mockRandom.Setup(rnd => rnd.GetScalar(true))
            .Returns(Scalar.One);
            key     = new CredentialIssuerSecretKey(mockRandom.Object);
            iparams = key.ComputeCredentialIssuerParameters();
            Assert.Equal(Generators.Gw + Generators.Gwp, iparams.Cw);
            Assert.Equal(Generators.GV - Generators.Gx0 - Generators.Gx1 - Generators.Ga, iparams.I);
        }
Exemplo n.º 11
0
        public void RegistrationMessageSerialization()
        {
            var converters = new JsonConverter[]
            {
                new ScalarJsonConverter(),
                new GroupElementJsonConverter(),
                new MoneySatoshiJsonConverter()
            };

            var numberOfCredentials = 2;

            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd, 4300000000000);
            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd, 4300000000000);

            (CredentialsRequest credentialRequest, CredentialsResponseValidation validationData) = client.CreateRequestForZeroAmount();
            var credentialResponse = issuer.HandleRequest(credentialRequest);

            client.HandleResponse(credentialResponse, validationData);
            var present = client.Credentials.ZeroValue.Take(numberOfCredentials);

            (credentialRequest, _) = client.CreateRequest(new[] { 1L }, present);

            // Registration request message.
            var serializedRequestMessage = JsonConvert.SerializeObject(credentialRequest, converters);

            Assert.Throws <NotSupportedException>(() => JsonConvert.DeserializeObject <ZeroCredentialsRequest>(serializedRequestMessage, converters));
            var deserializedRequestMessage = JsonConvert.DeserializeObject <RealCredentialsRequest>(serializedRequestMessage, converters);
            var reserializedRequestMessage = JsonConvert.SerializeObject(deserializedRequestMessage, converters);

            Assert.Equal(serializedRequestMessage, reserializedRequestMessage);

            // Registration response message.
            var serializedResponseMessage   = JsonConvert.SerializeObject(credentialResponse, converters);
            var deserializedResponseMessage = JsonConvert.DeserializeObject <CredentialsResponse>(serializedResponseMessage, converters);
            var reserializedResponseMessage = JsonConvert.SerializeObject(deserializedResponseMessage, converters);

            Assert.Equal(serializedResponseMessage, reserializedResponseMessage);
        }
Exemplo n.º 12
0
        public void RegistrationMessageSerialization()
        {
            var converters = new JsonConverter[]
            {
                new ScalarJsonConverter(),
                new GroupElementJsonConverter(),
                new MoneySatoshiJsonConverter()
            };

            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var issuer = new CredentialIssuer(sk, rnd, 4300000000000);
            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), rnd, 4300000000000);

            (ICredentialsRequest credentialRequest, CredentialsResponseValidation validationData) = client.CreateRequestForZeroAmount();
            var credentialResponse = issuer.HandleRequest(credentialRequest);
            var present            = client.HandleResponse(credentialResponse, validationData);

            (credentialRequest, _) = client.CreateRequest(new[] { 1L }, present, CancellationToken.None);

            // Registration request message.
            var serializedRequestMessage = JsonConvert.SerializeObject(credentialRequest, converters);
            ZeroCredentialsRequest deserializedCredentialsRequest = JsonConvert.DeserializeObject <ZeroCredentialsRequest>(serializedRequestMessage, converters) !;

            Assert.NotSame(credentialRequest, deserializedCredentialsRequest);

            var deserializedRequestMessage = JsonConvert.DeserializeObject <RealCredentialsRequest>(serializedRequestMessage, converters);
            var reserializedRequestMessage = JsonConvert.SerializeObject(deserializedRequestMessage, converters);

            Assert.Equal(serializedRequestMessage, reserializedRequestMessage);

            // Registration response message.
            var serializedResponseMessage   = JsonConvert.SerializeObject(credentialResponse, converters);
            var deserializedResponseMessage = JsonConvert.DeserializeObject <CredentialsResponse>(serializedResponseMessage, converters);
            var reserializedResponseMessage = JsonConvert.SerializeObject(deserializedResponseMessage, converters);

            Assert.Equal(serializedResponseMessage, reserializedResponseMessage);
        }
Exemplo n.º 13
0
        public void Process()
        {
            var numberOfCredentials = k;
            var rnd = new SecureRandom();
            var sk  = new CredentialIssuerSecretKey(rnd);

            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd);

            var(credentialRequest, validationData) = client.CreateRequestForZeroAmount();
            var issuer             = new CredentialIssuer(sk, numberOfCredentials, rnd);
            var credentialResponse = issuer.HandleRequest(credentialRequest);

            client.HandleResponse(credentialResponse, validationData);

            var present = client.Credentials.ZeroValue.Take(numberOfCredentials);

            (credentialRequest, validationData) = client.CreateRequest(new[] { Money.Coins(1) }, present);
            var credentialRequested = credentialRequest.Requested.ToArray();

            credentialResponse = issuer.HandleRequest(credentialRequest);
            client.HandleResponse(credentialResponse, validationData);
        }
Exemplo n.º 14
0
    public void CanDetectInvalidMAC()
    {
        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));
    }
Exemplo n.º 15
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);
        }
        public void GenerateCredentialIssuerParameters()
        {
            // Coordinator key is (0, 0, 0, 0, 0)
            var rnd = new MockRandom();

            rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.Zero, 5));
            var key = new CredentialIssuerSecretKey(rnd);
            var ex  = Assert.Throws <ArgumentException>(key.ComputeCredentialIssuerParameters);

            Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);

            // Coordinator key is (0, 0, 1, 1, 1)
            rnd = new MockRandom();
            rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.Zero, 2));
            rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.One, 3));
            key = new CredentialIssuerSecretKey(rnd);
            ex  = Assert.Throws <ArgumentException>(key.ComputeCredentialIssuerParameters);
            Assert.StartsWith("Point at infinity is not a valid value.", ex.Message);

            // Coordinator key is (1, 1, 0, 0, 0)
            rnd = new MockRandom();
            rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.One, 2));
            rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.Zero, 3));
            key = new CredentialIssuerSecretKey(rnd);
            var iparams = key.ComputeCredentialIssuerParameters();

            Assert.Equal(Generators.GV, iparams.I);

            // Coordinator key is (1, 1, 1, 1, 1)
            rnd = new MockRandom();
            rnd.GetScalarResults.AddRange(Enumerable.Repeat(Scalar.One, 5));
            key     = new CredentialIssuerSecretKey(rnd);
            iparams = key.ComputeCredentialIssuerParameters();
            Assert.Equal(Generators.Gw + Generators.Gwp, iparams.Cw);
            Assert.Equal(Generators.GV - Generators.Gx0 - Generators.Gx1 - Generators.Ga, iparams.I);
        }
Exemplo n.º 17
0
 public static Knowledge IssuerParametersKnowledge(MAC mac, GroupElement ma, CredentialIssuerSecretKey sk)
 => new(IssuerParametersStatement(sk.ComputeCredentialIssuerParameters(), mac, ma), new ScalarVector(sk.W, sk.Wp, sk.X0, sk.X1, sk.Ya));
Exemplo n.º 18
0
        public void InvalidCredentialRequests()
        {
            var numberOfCredentials = 3;

            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd);
            {
                var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd);

                // Null request. This requests `numberOfCredentials` zero-value credentials.
                var(credentialRequest, validationData) = client.CreateRequestForZeroAmount();

                var credentialResponse = issuer.HandleRequest(credentialRequest);
                client.HandleResponse(credentialResponse, validationData);

                var(validCredentialRequest, _) = client.CreateRequest(Array.Empty <Money>(), client.Credentials.ZeroValue.Take(1));

                // Test incorrect number of presentations (one instead of 3.)
                var presented = validCredentialRequest.Presented.ToArray();
                var invalidCredentialRequest = new RegistrationRequestMessage(
                    validCredentialRequest.DeltaAmount,
                    new[] { presented[0] },                     // Should present 3 credentials.
                    validCredentialRequest.Requested,
                    validCredentialRequest.Proofs);

                var ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(invalidCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.InvalidNumberOfPresentedCredentials, ex.ErrorCode);
                Assert.Equal("3 credential presentations were expected but 1 were received.", ex.Message);

                // Test incorrect number of presentations (0 instead of 3.)
                presented = credentialRequest.Presented.ToArray();
                invalidCredentialRequest = new RegistrationRequestMessage(
                    Money.Coins(2),
                    Array.Empty <CredentialPresentation>(),                    // Should present 3 credentials.
                    validCredentialRequest.Requested,
                    validCredentialRequest.Proofs);

                ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(invalidCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.InvalidNumberOfPresentedCredentials, ex.ErrorCode);
                Assert.Equal("3 credential presentations were expected but 0 were received.", ex.Message);

                (validCredentialRequest, _) = client.CreateRequest(Array.Empty <Money>(), client.Credentials.All);

                // Test incorrect number of credential requests.
                invalidCredentialRequest = new RegistrationRequestMessage(
                    validCredentialRequest.DeltaAmount,
                    validCredentialRequest.Presented,
                    validCredentialRequest.Requested.Take(1),
                    validCredentialRequest.Proofs);

                ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(invalidCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.InvalidNumberOfRequestedCredentials, ex.ErrorCode);
                Assert.Equal("3 credential requests were expected but 1 were received.", ex.Message);

                // Test incorrect number of credential requests.
                invalidCredentialRequest = new RegistrationRequestMessage(
                    Money.Coins(2),
                    Array.Empty <CredentialPresentation>(),
                    validCredentialRequest.Requested.Take(1),
                    validCredentialRequest.Proofs);

                ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(invalidCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.InvalidNumberOfRequestedCredentials, ex.ErrorCode);
                Assert.Equal("3 credential requests were expected but 1 were received.", ex.Message);

                // Test invalid range proof.
                var requested = validCredentialRequest.Requested.ToArray();

                invalidCredentialRequest = new RegistrationRequestMessage(
                    validCredentialRequest.DeltaAmount,
                    validCredentialRequest.Presented,
                    new[] { requested[0], requested[1], new IssuanceRequest(requested[2].Ma, new[] { GroupElement.Infinity }) },
                    validCredentialRequest.Proofs);

                ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(invalidCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.InvalidBitCommitment, ex.ErrorCode);
            }

            {
                var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd);
                var(validCredentialRequest, validationData) = client.CreateRequestForZeroAmount();

                // Test invalid proofs.
                var proofs = validCredentialRequest.Proofs.ToArray();
                proofs[0] = proofs[1];
                var invalidCredentialRequest = new RegistrationRequestMessage(
                    validCredentialRequest.DeltaAmount,
                    validCredentialRequest.Presented,
                    validCredentialRequest.Requested,
                    proofs);

                var ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(invalidCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.CoordinatorReceivedInvalidProofs, ex.ErrorCode);
            }

            {
                var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd);
                var(validCredentialRequest, validationData) = client.CreateRequestForZeroAmount();

                var credentialResponse = issuer.HandleRequest(validCredentialRequest);
                client.HandleResponse(credentialResponse, validationData);

                (validCredentialRequest, validationData) = client.CreateRequest(Enumerable.Empty <Money>(), client.Credentials.All);

                issuer.HandleRequest(validCredentialRequest);
                var ex = Assert.Throws <WabiSabiException>(() => issuer.HandleRequest(validCredentialRequest));
                Assert.Equal(WabiSabiErrorCode.SerialNumberAlreadyUsed, ex.ErrorCode);
            }
        }
 /// <summary>
 /// Computes the Z element.
 /// </summary>
 /// <param name="sk">The coordinator's secret key.</param>
 /// <returns>The Z element needed to verify that a randomized credential's proof is valid.</returns>
 public GroupElement ComputeZ(CredentialIssuerSecretKey sk)
 => CV - (sk.W * Generators.Gw + sk.X0 * Cx0 + sk.X1 * Cx1 + sk.Ya * Ca);
Exemplo n.º 20
0
        public void CredentialIssuance()
        {
            var numberOfCredentials = 3;

            using var rnd = new SecureRandom();
            var sk = new CredentialIssuerSecretKey(rnd);

            var client = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd);

            {
                // Null request. This requests `numberOfCredentials` zero-value credentials.
                var(credentialRequest, validationData) = client.CreateRequestForZeroAmount();

                Assert.True(credentialRequest.IsNullRequest);
                Assert.Equal(numberOfCredentials, credentialRequest.Requested.Count());
                var requested = credentialRequest.Requested.ToArray();
                Assert.Empty(requested[0].BitCommitments);
                Assert.Empty(requested[1].BitCommitments);
                Assert.Empty(requested[2].BitCommitments);
                Assert.Equal(Money.Zero, credentialRequest.DeltaAmount);

                // Issuer part.
                var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd);

                var credentialResponse = issuer.HandleRequest(credentialRequest);
                client.HandleResponse(credentialResponse, validationData);
                Assert.Equal(numberOfCredentials, client.Credentials.ZeroValue.Count());
                Assert.Empty(client.Credentials.Valuable);
                var issuedCredential = client.Credentials.ZeroValue.First();
                Assert.True(issuedCredential.Amount.IsZero);
            }

            {
                var present = client.Credentials.ZeroValue.Take(numberOfCredentials);
                var(credentialRequest, validationData) = client.CreateRequest(new[] { Money.Coins(1) }, present);

                Assert.False(credentialRequest.IsNullRequest);
                var credentialRequested = credentialRequest.Requested.ToArray();
                Assert.Equal(numberOfCredentials, credentialRequested.Length);
                Assert.NotEmpty(credentialRequested[0].BitCommitments);
                Assert.NotEmpty(credentialRequested[1].BitCommitments);

                // Issuer part.
                var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd);

                var credentialResponse = issuer.HandleRequest(credentialRequest);
                client.HandleResponse(credentialResponse, validationData);
                var issuedCredential = Assert.Single(client.Credentials.Valuable);
                Assert.Equal(new Scalar(100_000_000), issuedCredential.Amount);

                Assert.Equal(2, client.Credentials.ZeroValue.Count());
                Assert.Equal(3, client.Credentials.All.Count());
            }

            {
                var valuableCredential = client.Credentials.Valuable.Take(1);
                var amounts            = Enumerable.Repeat(Money.Coins(0.5m), 2);
                var(credentialRequest, validationData) = client.CreateRequest(amounts, valuableCredential);

                Assert.False(credentialRequest.IsNullRequest);
                var requested = credentialRequest.Requested.ToArray();
                Assert.Equal(numberOfCredentials, requested.Length);
                Assert.NotEmpty(requested[0].BitCommitments);
                Assert.NotEmpty(requested[1].BitCommitments);
                Assert.Equal(Money.Zero, credentialRequest.DeltaAmount);

                // Issuer part.
                var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd);

                var credentialResponse = issuer.HandleRequest(credentialRequest);
                client.HandleResponse(credentialResponse, validationData);
                var credentials = client.Credentials.All.ToArray();
                Assert.NotEmpty(credentials);
                Assert.Equal(3, credentials.Length);

                var valuableCredentials = client.Credentials.Valuable.ToArray();
                Assert.Equal(new Scalar(50_000_000), valuableCredentials[0].Amount);
                Assert.Equal(new Scalar(50_000_000), valuableCredentials[1].Amount);
            }

            {
                var client0 = new WabiSabiClient(sk.ComputeCredentialIssuerParameters(), numberOfCredentials, rnd);
                var(credentialRequest, validationData) = client0.CreateRequestForZeroAmount();

                var issuer             = new CredentialIssuer(sk, numberOfCredentials, rnd);
                var credentialResponse = issuer.HandleRequest(credentialRequest);
                client0.HandleResponse(credentialResponse, validationData);

                (credentialRequest, validationData) = client0.CreateRequest(new[] { Money.Coins(1m) }, Enumerable.Empty <Credential>());

                credentialResponse = issuer.HandleRequest(credentialRequest);
                client0.HandleResponse(credentialResponse, validationData);

                (credentialRequest, validationData) = client0.CreateRequest(Array.Empty <Money>(), client0.Credentials.Valuable);

                credentialResponse = issuer.HandleRequest(credentialRequest);
                client0.HandleResponse(credentialResponse, validationData);
                Assert.NotEmpty(client0.Credentials.All);
                Assert.Equal(numberOfCredentials, client0.Credentials.All.Count());
            }
        }