API documentation and renaming a few things
MODIFY
WalletWasabi.Tests/UnitTests/Wabisabi/CredentialTests.cs
WalletWasabi.Tests/UnitTests/Wabisabi/CredentialTests.cs
@@ -137,7 +137,7 @@ namespace WalletWasabi.Tests.UnitTests.Wabisabi
// Test incorrect number of presentations (one instead of 3)
var presented = validCredentialRequest.Presented.ToArray();
- var invalidCredentialRequest = new RegistrationRequest(
+ var invalidCredentialRequest = new RegistrationRequestMessage(
validCredentialRequest.DeltaAmount,
new[] { presented[0] }, // Should present 3 credentials
validCredentialRequest.Requested,
@@ -149,7 +149,7 @@ namespace WalletWasabi.Tests.UnitTests.Wabisabi
// Test incorrect number of presentations (0 instead of 3)
presented = credentialRequest.Presented.ToArray();
- invalidCredentialRequest = new RegistrationRequest(
+ invalidCredentialRequest = new RegistrationRequestMessage(
Money.Coins(2),
new CredentialPresentation[0], // Should present 3 credentials
validCredentialRequest.Requested,
@@ -162,7 +162,7 @@ namespace WalletWasabi.Tests.UnitTests.Wabisabi
(validCredentialRequest, _) = client.CreateRequest(new Money[0], client.Credentials.All);
// Test incorrect number of credential requests
- invalidCredentialRequest = new RegistrationRequest(
+ invalidCredentialRequest = new RegistrationRequestMessage(
validCredentialRequest.DeltaAmount,
validCredentialRequest.Presented,
validCredentialRequest.Requested.Take(1),
@@ -173,7 +173,7 @@ namespace WalletWasabi.Tests.UnitTests.Wabisabi
Assert.Equal("3 credential requests were expected but 1 were received.", ex.Message);
// Test incorrect number of credential requests
- invalidCredentialRequest = new RegistrationRequest(
+ invalidCredentialRequest = new RegistrationRequestMessage(
Money.Coins(2),
new CredentialPresentation[0],
validCredentialRequest.Requested.Take(1),
@@ -186,7 +186,7 @@ namespace WalletWasabi.Tests.UnitTests.Wabisabi
// Test invalid range proof
var requested = validCredentialRequest.Requested.ToArray();
- invalidCredentialRequest = new RegistrationRequest(
+ invalidCredentialRequest = new RegistrationRequestMessage(
validCredentialRequest.DeltaAmount,
validCredentialRequest.Presented,
new[] { requested[0], requested[1], new IssuanceRequest(requested[2].Ma, new[] { GroupElement.Infinity }) },
@@ -203,7 +203,7 @@ namespace WalletWasabi.Tests.UnitTests.Wabisabi
// Test invalid proofs
var proofs = validCredentialRequest.Proofs.ToArray();
proofs[0] = proofs[1];
- var invalidCredentialRequest = new RegistrationRequest(
+ var invalidCredentialRequest = new RegistrationRequestMessage(
validCredentialRequest.DeltaAmount,
validCredentialRequest.Presented,
validCredentialRequest.Requested,

MODIFY
WalletWasabi/Wabisabi/CredentialIssuer.cs
WalletWasabi/Wabisabi/CredentialIssuer.cs
@@ -13,11 +13,44 @@ using WalletWasabi.Helpers;
namespace WalletWasabi.Wabisabi
{
+ /// <summary>
+ /// Issues anonymous credentials using the coordinator's secret key.
+ /// </summary>
+ /// <remarks>
+ /// CredentialIssuer is the coordinator's component used to issue anonymous credentials
+ /// requested by a WabiSabi client. This means this component abstracts receives
+ /// <see cref="RegistrationRequestMessage">RegistrationRequests</see>, validates the requested
+ /// amounts are in the valid range, serial numbers are not duplicated nor reused,
+ /// and finally issues the credentials using the coordinator's secret key (and also
+ /// proving to the WabiSabi client that the credentials were issued with the right
+ /// key).
+ ///
+ /// Note that this is a stateful component because it needs to keep track of the
+ /// presented credentials' serial numbers in order to prevent credential reuse.
+ /// Additionally it keeps also track of the `balance` in order to make sure it never
+ /// issues credentials for more money than the total presented amount. All this means
+ /// that the same instance has to be used for a given round (the coordinator needs to
+ /// maintain only one instances of this class per round)
+ ///
+ /// About replay requests: a replay request is a <see cref="RegistrationRequestMessage">request</see>
+ /// that has already been seen before. These kind of requests can be the result of misbehaving
+ /// clients or simply clients using a retry communication mechanism.
+ /// Reply requests are not handled by this component and they have to be handled by a different
+ /// component. A good solution is to use a caching feature where the request fingerprint is
+ /// used as a key, in this way using a standard solution it is possible to respond with the exact
+ /// same valid credentials to the client without performance penalties.
+ /// </remarks>
public class CredentialIssuer
{
- public CredentialIssuer(CoordinatorSecretKey sk, int numberOfCredentials, WasabiRandom randomNumberGenerator)
+ /// <summary>
+ /// Initializes a new instance of the CredentialIssuer class.
+ /// </summary>
+ /// <param name="coordinatorSecretKey">The <see cref="CoordinatorSecretKey">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(CoordinatorSecretKey coordinatorSecretKey, int numberOfCredentials, WasabiRandom randomNumberGenerator)
{
- CoordinatorSecretKey = Guard.NotNull(nameof(sk), sk);
+ CoordinatorSecretKey = Guard.NotNull(nameof(coordinatorSecretKey), coordinatorSecretKey);
NumberOfCredentials = Guard.InRangeAndNotNull(nameof(numberOfCredentials), numberOfCredentials, 1, 100);
CoordinatorParameters = CoordinatorSecretKey.ComputeCoordinatorParameters();
RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator);
@@ -36,11 +69,20 @@ namespace WalletWasabi.Wabisabi
private CoordinatorParameters CoordinatorParameters { get; }
- // Gets the number of credentials that have to be requested/presented
- // This parameter is called `k` in the wabisabi paper.
+ /// <summary>
+ /// Gets the number of credentials that have to be requested/presented
+ /// This parameter is called `k` in the WabiSabi paper.
+ /// </summary>
public int NumberOfCredentials { get; }
- public RegistrationResponse HandleRequest(RegistrationRequest registrationRequest)
+ /// <summary>
+ /// Process the <see cref="RegistrationRequestMessage">credentials registration requests</see> and
+ /// issues the credentials.
+ /// </summary>
+ /// <param name="registrationRequest">The request containing the credentials presentations, credential requests and the proofs.</param>
+ /// <returns>The <see cref="RegistrationResponseMessage">registration response</see> containing the requested credentials and the proofs.</returns>
+ /// <exception cref="WabiSabiException">Error code: <see cref="WabiSabiErrorCode">WabiSabiErrorCode</see></exception>
+ public RegistrationResponseMessage HandleRequest(RegistrationRequestMessage registrationRequest)
{
Guard.NotNull(nameof(registrationRequest), registrationRequest);
@@ -145,7 +187,7 @@ namespace WalletWasabi.Wabisabi
// Construct response.
var proofs = ProofSystem.Prove(transcript, credentials.Select(x => x.Knowledge), RandomNumberGenerator);
var macs = credentials.Select(x => x.Mac);
- var response = new RegistrationResponse(macs, proofs);
+ var response = new RegistrationResponseMessage(macs, proofs);
// Register the serial numbers to prevent credential reuse.
foreach (var presentation in presented)

MODIFY
WalletWasabi/Wabisabi/CredentialPool.cs
WalletWasabi/Wabisabi/CredentialPool.cs
@@ -4,6 +4,9 @@ using WalletWasabi.Crypto.ZeroKnowledge;
namespace WalletWasabi.Wabisabi
{
+ /// <summary>
+ /// Keeps a registry of credentials available.
+ /// </summary>
public class CredentialPool
{
internal CredentialPool()
@@ -12,12 +15,26 @@ namespace WalletWasabi.Wabisabi
private HashSet<Credential> Credentials { get; } = new HashSet<Credential>();
+ /// <summary>
+ /// Enumerates all the zero-value credentials available.
+ /// </summary>
public IEnumerable<Credential> ZeroValue => Credentials.Where(x => x.Amount.IsZero);
+ /// <summary>
+ /// Enumerates all the available credentials with non-zero value.
+ /// </summary>
public IEnumerable<Credential> Valuable => Credentials.Where(x => !x.Amount.IsZero);
+ /// <summary>
+ /// Enumerates all the available credentials.
+ /// </summary>
public IEnumerable<Credential> All => Credentials;
+ /// <summary>
+ /// Removes credentials that were used and registers those that were issued.
+ /// </summary>
+ /// <param name="newCredentials">Credentials received from the coordinator.</param>
+ /// <param name="oldCredentials">Credentials exchanged by the ones that were issued.</param>
internal void UpdateCredentials(IEnumerable<Credential> newCredentials, IEnumerable<Credential> oldCredentials)
{
var hs = oldCredentials.ToHashSet();

MODIFY
WalletWasabi/Wabisabi/IssuanceRequest.cs
WalletWasabi/Wabisabi/IssuanceRequest.cs
@@ -3,6 +3,9 @@ using WalletWasabi.Crypto.Groups;
namespace WalletWasabi.Wabisabi
{
+ /// <summary>
+ /// Represents a request for issuance a new credential.
+ /// </summary>
public class IssuanceRequest
{
internal IssuanceRequest(GroupElement ma, IEnumerable<GroupElement> bitCommitments)
@@ -11,8 +14,14 @@ namespace WalletWasabi.Wabisabi
BitCommitments = bitCommitments;
}
+ /// <summary>
+ /// Pedersen commitment to the credential amount.
+ /// </summary>
public GroupElement Ma { get; }
+ /// <summary>
+ /// Commitments the the value's bits decomposed amount.
+ /// </summary>
public IEnumerable<GroupElement> BitCommitments { get; }
}
}
\ No newline at end of file

MODIFY
WalletWasabi/Wabisabi/IssuanceValidationData.cs
WalletWasabi/Wabisabi/IssuanceValidationData.cs
@@ -13,10 +13,19 @@ namespace WalletWasabi.Wabisabi
Ma = ma;
}
+ /// <summary>
+ /// Amount committed in the pedersen commitment (<see cref="Ma">Ma</see>).
+ /// </summary>
public Money Amount { get; }
+ /// <summary>
+ /// Randomness used as blinding factor in the pedersen commitment (<see cref="Ma">Ma</see>).
+ /// </summary>
public Scalar Randomness { get; }
+ /// <summary>
+ /// Pedersen committed amount used to request the credential.
+ /// </summary>
public GroupElement Ma { get; }
}
}

DELETE
WalletWasabi/Wabisabi/RegistrationRequest.cs
-using System.Collections.Generic;
-using System.Linq;
-using NBitcoin;
-using WalletWasabi.Crypto.Groups;
-using WalletWasabi.Crypto.ZeroKnowledge;
-
-namespace WalletWasabi.Wabisabi
-{
- public class RegistrationRequest
- {
- internal RegistrationRequest(
- Money balance,
- IEnumerable<CredentialPresentation> presented,
- IEnumerable<IssuanceRequest> requested,
- IEnumerable<Proof> proofs)
- {
- DeltaAmount = balance;
- Presented = presented;
- Requested = requested;
- Proofs = proofs;
- }
-
- public Money DeltaAmount { get; }
-
- public IEnumerable<CredentialPresentation> Presented { get; }
-
- public IEnumerable<IssuanceRequest> Requested { get; }
-
- public IEnumerable<Proof> Proofs { get; }
-
- public bool IsNullRequest => DeltaAmount == Money.Zero && !Presented.Any();
-
- public IEnumerable<GroupElement> SerialNumbers => Presented.Select(x => x.S);
-
- public bool AreThereDuplicatedSerialNumbers => SerialNumbers.Distinct().Count() < SerialNumbers.Count();
- }
-}
\ No newline at end of file

DELETE
WalletWasabi/Wabisabi/RegistrationResponse.cs
-using System;
-using System.Collections.Generic;
-using WalletWasabi.Crypto;
-using WalletWasabi.Crypto.ZeroKnowledge;
-
-namespace WalletWasabi.Wabisabi
-{
- public class RegistrationResponse
- {
- public RegistrationResponse(IEnumerable<MAC> issuedCredentials, IEnumerable<Proof> proofs)
- {
- IssuedCredentials = issuedCredentials;
- Proofs = proofs;
- }
-
- public IEnumerable<MAC> IssuedCredentials { get; }
-
- public IEnumerable<Proof> Proofs { get; }
- }
-}
\ No newline at end of file

MODIFY
WalletWasabi/Wabisabi/RegistrationValidationData.cs
WalletWasabi/Wabisabi/RegistrationValidationData.cs
@@ -3,19 +3,35 @@ using WalletWasabi.Crypto.ZeroKnowledge;
namespace WalletWasabi.Wabisabi
{
+ /// <summary>
+ /// Maintains the state needed to validate the credentials once the coordinator
+ /// issues them.
+ /// </summary>
public class RegistrationValidationData
{
- internal RegistrationValidationData(Transcript transcript, IEnumerable<Credential> presented, IssuanceValidationData[] requested)
+ internal RegistrationValidationData(
+ Transcript transcript,
+ IEnumerable<Credential> presented,
+ IEnumerable<IssuanceValidationData> requested)
{
Transcript = transcript;
Presented = presented;
Requested = requested;
}
+ /// <summary>
+ /// The transcript in the correct state that must be use to validate the proofs presented by the coordinator.
+ /// </summary>
public Transcript Transcript { get; }
+ /// <summary>
+ /// The credentials that were presented to the coordinator.
+ /// </summary>
public IEnumerable<Credential> Presented { get; }
- public IssuanceValidationData[] Requested { get; }
+ /// <summary>
+ /// The data state that has to be use to validate the issued credentials.
+ /// </summary>
+ public IEnumerable<IssuanceValidationData> Requested { get; }
}
}

MODIFY
WalletWasabi/Wabisabi/WabiSabiClient.cs
WalletWasabi/Wabisabi/WabiSabiClient.cs
@@ -12,6 +12,10 @@ using WalletWasabi.Helpers;
namespace WalletWasabi.Wabisabi
{
+ /// <summary>
+ /// Provides the methods for creating <see cref="RegistrationRequestMessage">unified WabiSabi credential registration request messages</see>
+ /// and handle the <see cref="RegistrationResponseMessage">credential registration responses</see> received from the coordinator.
+ /// </summary>
public class WabiSabiClient
{
public WabiSabiClient(
@@ -29,11 +33,23 @@ namespace WalletWasabi.Wabisabi
private CoordinatorParameters CoordinatorParameters { get; }
- public CredentialPool Credentials { get; }
-
private WasabiRandom RandomNumberGenerator { get; }
- public (RegistrationRequest, RegistrationValidationData) CreateRequestForZeroAmount()
+ /// <summary>
+ /// The credentials pool containing the available credentials.
+ /// </summary>
+ public CredentialPool Credentials { get; }
+
+ /// <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];
@@ -52,7 +68,7 @@ namespace WalletWasabi.Wabisabi
var transcript = BuildTransnscript(isNullRequest: true);
return (
- new RegistrationRequest(
+ new RegistrationRequestMessage(
Money.Zero,
Enumerable.Empty<CredentialPresentation>(),
credentialsToRequest,
@@ -63,7 +79,17 @@ namespace WalletWasabi.Wabisabi
validationData));
}
- public (RegistrationRequest, RegistrationValidationData) CreateRequest(
+ /// <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)
{
@@ -139,7 +165,7 @@ namespace WalletWasabi.Wabisabi
var transcript = BuildTransnscript(isNullRequest: false);
return (
- new RegistrationRequest(
+ new RegistrationRequestMessage(
amountsToRequest.Sum() - credentialsToPresent.Sum(x => x.Amount.ToMoney()),
presentations,
credentialsToRequest,
@@ -150,7 +176,17 @@ namespace WalletWasabi.Wabisabi
validationData));
}
- public void HandleResponse(RegistrationResponse registrationResponse, RegistrationValidationData registrationValidationData)
+ /// <summary>
+ /// Handles the registration response received from the coordinator.
+ /// </summary>
+ /// <remarks>
+ /// Verifies the registration response message proofs, creates the credentials based on the issued MACs and
+ /// finally updates the credentials pool by removing those credentials that were presented and by adding
+ /// those that were issued.
+ /// </remarks>
+ /// <param name="registrationResponse">The registration response message receive from the coordinator.</param>
+ /// <param name="registrationValidationData">The state data required to validate the issued credentials and the proofs.</param>
+ public void HandleResponse(RegistrationResponseMessage registrationResponse, RegistrationValidationData registrationValidationData)
{
Guard.NotNull(nameof(registrationResponse), registrationResponse);
Guard.NotNull(nameof(registrationValidationData), registrationValidationData);

API documentation and renaming a few things