/// <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)); }
/// <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)); }