Ejemplo n.º 1
0
        /// <summary>
        /// Creates a <see cref="RegistrationRequestMessage">credential registration request messages</see>
        /// for requesting `k` zero-value credentials.
        /// </summary>
        /// <remarks>
        /// The request messages created by CreateRequestForZeroAmount are called null requests. The first
        /// registration request message that has to be sent to the coordinator is a null request, in this
        /// way the coordinator issues `k` zero-value credentials that can be used in following requests.
        /// </remarks>
        public (RegistrationRequestMessage, RegistrationValidationData) CreateRequestForZeroAmount()
        {
            var credentialsToRequest = new IssuanceRequest[NumberOfCredentials];
            var knowledge            = new Knowledge[NumberOfCredentials];
            var validationData       = new IssuanceValidationData[NumberOfCredentials];

            for (var i = 0; i < NumberOfCredentials; i++)
            {
                var randomness = RandomNumberGenerator.GetScalar(allowZero: false);
                var Ma         = randomness * Generators.Gh;

                knowledge[i]            = ProofSystem.ZeroProofKnowledge(Ma, randomness);
                credentialsToRequest[i] = new IssuanceRequest(Ma, Enumerable.Empty <GroupElement>());
                validationData[i]       = new IssuanceValidationData(Money.Zero, randomness, Ma);
            }

            var transcript = BuildTransnscript(isNullRequest: true);

            return(
                new RegistrationRequestMessage(
                    Money.Zero,
                    Enumerable.Empty <CredentialPresentation>(),
                    credentialsToRequest,
                    ProofSystem.Prove(transcript, knowledge, RandomNumberGenerator)),
                new RegistrationValidationData(
                    transcript,
                    Enumerable.Empty <Credential>(),
                    validationData));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a <see cref="RegistrationRequestMessage">credential registration request messages</see>
        /// for requesting `k` non-zero-value credentials.
        /// </summary>
        /// <param name="amountsToRequest">List of amounts requested in credentials.</param>
        /// <param name="credentialsToPresent">List of credentials to be presented to the coordinator.</param>
        /// <returns>
        /// A tuple containing the registration request message instance and the registration validation data
        /// to be used to validate the coordinator response message (the issued credentials).
        /// </returns>
        public (RegistrationRequestMessage, RegistrationValidationData) CreateRequest(
            IEnumerable <Money> amountsToRequest,
            IEnumerable <Credential> credentialsToPresent)
        {
            // Make sure we request always the same number of credentials
            var credentialAmountsToRequest = amountsToRequest.ToList();
            var missingCredentialRequests  = NumberOfCredentials - amountsToRequest.Count();

            for (var i = 0; i < missingCredentialRequests; i++)
            {
                credentialAmountsToRequest.Add(Money.Zero);
            }

            // Make sure we present always the same number of credentials (except for Null requests)
            var missingCredentialPresent = NumberOfCredentials - credentialsToPresent.Count();

            var alreadyPresentedZeroCredentials = credentialsToPresent.Where(x => x.Amount.IsZero);
            var availableZeroCredentials        = Credentials.ZeroValue.Except(alreadyPresentedZeroCredentials);

            // This should not be possible
            var availableZeroCredentialCount = availableZeroCredentials.Count();

            if (availableZeroCredentialCount < missingCredentialPresent)
            {
                throw new WabiSabiException(
                          WabiSabiErrorCode.NotEnoughZeroCredentialToFillTheRequest,
                          $"{missingCredentialPresent} credentials are missing but there are only {availableZeroCredentialCount} zero-value credentials available.");
            }

            credentialsToPresent = credentialsToPresent.Concat(availableZeroCredentials.Take(missingCredentialPresent)).ToList();
            var macsToPresent = credentialsToPresent.Select(x => x.Mac);

            if (macsToPresent.Distinct().Count() < macsToPresent.Count())
            {
                throw new WabiSabiException(WabiSabiErrorCode.CredentialToPresentDuplicated);
            }

            var zs = new List <Scalar>();
            var knowledgeToProve = new List <Knowledge>();
            var presentations    = new List <CredentialPresentation>();

            foreach (var credential in credentialsToPresent)
            {
                var z            = RandomNumberGenerator.GetScalar();
                var presentation = credential.Present(z);
                presentations.Add(presentation);
                knowledgeToProve.Add(ProofSystem.ShowCredentialKnowledge(presentation, z, credential, CoordinatorParameters));
                zs.Add(z);
            }

            // Generate RangeProofs (or ZeroProof) for each requested credential
            var credentialsToRequest = new IssuanceRequest[NumberOfCredentials];
            var validationData       = new IssuanceValidationData[NumberOfCredentials];

            for (var i = 0; i < NumberOfCredentials; i++)
            {
                var amount       = credentialAmountsToRequest[i];
                var scalarAmount = new Scalar((ulong)amount.Satoshi);

                var randomness = RandomNumberGenerator.GetScalar(allowZero: false);
                var Ma         = scalarAmount * Generators.Gg + randomness * Generators.Gh;

                var(rangeKnowledge, bitCommitments) = ProofSystem.RangeProofKnowledge(scalarAmount, randomness, Constants.RangeProofWidth, RandomNumberGenerator);
                knowledgeToProve.Add(rangeKnowledge);

                var credentialRequest = new IssuanceRequest(Ma, bitCommitments);
                credentialsToRequest[i] = credentialRequest;
                validationData[i]       = new IssuanceValidationData(amount, randomness, Ma);
            }

            // Generate Balance Proof
            var sumOfZ = zs.Sum();
            var cr     = credentialsToPresent.Select(x => x.Randomness).Sum();
            var r      = validationData.Select(x => x.Randomness).Sum();
            var deltaR = cr + r.Negate();

            var balanceKnowledge = ProofSystem.BalanceProofKnowledge(sumOfZ, deltaR);

            knowledgeToProve.Add(balanceKnowledge);

            var transcript = BuildTransnscript(isNullRequest: false);

            return(
                new RegistrationRequestMessage(
                    amountsToRequest.Sum() - credentialsToPresent.Sum(x => x.Amount.ToMoney()),
                    presentations,
                    credentialsToRequest,
                    ProofSystem.Prove(transcript, knowledgeToProve, RandomNumberGenerator)),
                new RegistrationValidationData(
                    transcript,
                    credentialsToPresent,
                    validationData));
        }