Add conn conf checks
MODIFY
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
WalletWasabi.Tests/Helpers/WabiSabiFactory.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using WalletWasabi.Crypto;
using WalletWasabi.Crypto.Randomness;
+using WalletWasabi.Crypto.ZeroKnowledge;
using WalletWasabi.WabiSabi.Backend;
using WalletWasabi.WabiSabi.Backend.Models;
using WalletWasabi.WabiSabi.Backend.Rounds;
@@ -99,24 +100,8 @@ namespace WalletWasabi.Tests.Helpers
{
var roundId = round?.Id ?? Guid.NewGuid();
var inputRoundSignaturePairs = pairs ?? CreateInputRoundSignaturePairs(1, round?.Hash);
- var rnd = new InsecureRandom();
- var amClient =
- round is null
- ? new WabiSabiClient(new CredentialIssuerSecretKey(rnd).ComputeCredentialIssuerParameters(), 2, rnd, 4300000000000)
- : new WabiSabiClient(
- round.AmountCredentialIssuer.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(),
- round.AmountCredentialIssuer.NumberOfCredentials,
- rnd,
- round.MaxRegistrableAmount);
- var weClient =
- round is null
- ? new WabiSabiClient(new CredentialIssuerSecretKey(rnd).ComputeCredentialIssuerParameters(), 2, rnd, 4300000000000)
- : new WabiSabiClient(
- round.WeightCredentialIssuer.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(),
- round.WeightCredentialIssuer.NumberOfCredentials,
- rnd,
- round.MaxRegistrableWeight);
+ (var amClient, var weClient, _, _) = CreateWabiSabiClientsAndIssuers(round);
var (zeroAmountCredentialRequest, _) = amClient.CreateRequestForZeroAmount();
var (zeroWeightCredentialRequest, _) = weClient.CreateRequestForZeroAmount();
@@ -126,5 +111,63 @@ namespace WalletWasabi.Tests.Helpers
zeroAmountCredentialRequest,
zeroWeightCredentialRequest);
}
+
+ public static (WabiSabiClient amountClient, WabiSabiClient weightClient, CredentialIssuer amountIssuer, CredentialIssuer weightIssuer) CreateWabiSabiClientsAndIssuers(Round? round)
+ {
+ var rnd = new InsecureRandom();
+ var ai = round?.AmountCredentialIssuer ?? new CredentialIssuer(new CredentialIssuerSecretKey(rnd), 2, rnd, 4300000000000);
+ var wi = round?.WeightCredentialIssuer ?? new CredentialIssuer(new CredentialIssuerSecretKey(rnd), 2, rnd, 4300000000000);
+ var ac = new WabiSabiClient(
+ ai.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(),
+ ai.NumberOfCredentials,
+ rnd,
+ round?.MaxRegistrableAmount ?? 4300000000000);
+
+ var wc = new WabiSabiClient(
+ wi.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(),
+ wi.NumberOfCredentials,
+ rnd,
+ round?.MaxRegistrableWeight ?? 4300000000000ul);
+
+ return (ac, wc, ai, wi);
+ }
+
+ public static (IEnumerable<Credential> amountCredentials, IEnumerable<Credential> weightCredentials) CreateZeroCredentials(Round? round)
+ {
+ (var amClient, var weClient, var amIssuer, var weIssuer) = CreateWabiSabiClientsAndIssuers(round);
+
+ var (zeroAmountCredentialRequest, amVal) = amClient.CreateRequestForZeroAmount();
+ var (zeroWeightCredentialRequest, weVal) = weClient.CreateRequestForZeroAmount();
+ var amCredResp = amIssuer.HandleRequest(zeroAmountCredentialRequest);
+ var weCredResp = weIssuer.HandleRequest(zeroWeightCredentialRequest);
+ amClient.HandleResponse(amCredResp, amVal);
+ weClient.HandleResponse(weCredResp, weVal);
+ return (amClient.Credentials.ZeroValue.Take(amIssuer.NumberOfCredentials), weClient.Credentials.ZeroValue.Take(weIssuer.NumberOfCredentials));
+ }
+
+ public static ConnectionConfirmationRequest CreateConnectionConfirmationRequest(Round? round = null)
+ {
+ (var amClient, var weClient, _, _) = CreateWabiSabiClientsAndIssuers(round);
+
+ var (zeroAmountCredentialRequest, _) = amClient.CreateRequestForZeroAmount();
+ var (zeroWeightCredentialRequest, _) = weClient.CreateRequestForZeroAmount();
+
+ var zeroPresentables = CreateZeroCredentials(round);
+ var alice = round?.Alices.FirstOrDefault();
+ var (realAmountCredentialRequest, _) = amClient.CreateRequest(
+ alice is null ? new[] { 1000L } : new[] { alice.Coins.Select(x => x.Amount.Satoshi).Sum() },
+ zeroPresentables.amountCredentials);
+ var (realWeightCredentialRequest, _) = weClient.CreateRequest(
+ new[] { 1000L },
+ zeroPresentables.weightCredentials);
+
+ return new ConnectionConfirmationRequest(
+ round?.Id ?? Guid.NewGuid(),
+ alice?.Id ?? Guid.NewGuid(),
+ zeroAmountCredentialRequest,
+ realAmountCredentialRequest,
+ zeroWeightCredentialRequest,
+ realWeightCredentialRequest);
+ }
}
}

MODIFY
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/ConfirmConnectionTests.cs
WalletWasabi.Tests/UnitTests/WabiSabi/Backend/ConfirmConnectionTests.cs
@@ -16,6 +16,47 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
{
public class ConfirmConnectionTests
{
+ [Fact]
+ public async Task SuccessInInputRegistrationPhaseAsync()
+ {
+ MockArena arena = new();
+ WabiSabiConfig cfg = new();
+ var round = WabiSabiFactory.CreateRound(cfg);
+ var alice = WabiSabiFactory.CreateAlice();
+ round.Alices.Add(alice);
+ arena.OnTryGetRound = _ => round;
+
+ var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
+ await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
+ var resp = handler.ConfirmConnection(req);
+ Assert.NotNull(resp);
+ Assert.NotNull(resp.ZeroAmountCredentials);
+ Assert.NotNull(resp.ZeroWeightCredentials);
+ Assert.Null(resp.RealAmountCredentials);
+ Assert.Null(resp.RealWeightCredentials);
+ }
+
+ [Fact]
+ public async Task SuccessInConnectionConfirmationPhaseAsync()
+ {
+ MockArena arena = new();
+ WabiSabiConfig cfg = new();
+ var round = WabiSabiFactory.CreateRound(cfg);
+ round.Phase = Phase.ConnectionConfirmation;
+ var alice = WabiSabiFactory.CreateAlice();
+ round.Alices.Add(alice);
+ arena.OnTryGetRound = _ => round;
+
+ var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
+ await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
+ var resp = handler.ConfirmConnection(req);
+ Assert.NotNull(resp);
+ Assert.NotNull(resp.ZeroAmountCredentials);
+ Assert.NotNull(resp.ZeroWeightCredentials);
+ Assert.NotNull(resp.RealAmountCredentials);
+ Assert.NotNull(resp.RealWeightCredentials);
+ }
+
[Fact]
public async Task RoundNotFoundAsync()
{
@@ -23,7 +64,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
arena.OnTryGetRound = _ => null;
await using PostRequestHandler handler = new(new WabiSabiConfig(), new Prison(), arena, new MockRpcClient());
- var req = new ConnectionConfirmationRequest(Guid.NewGuid(), Guid.NewGuid(), null!, null!, null!, null!);
+ var req = WabiSabiFactory.CreateConnectionConfirmationRequest();
var ex = Assert.Throws<WabiSabiProtocolException>(() => handler.ConfirmConnection(req));
Assert.Equal(WabiSabiProtocolErrorCode.RoundNotFound, ex.ErrorCode);
}
@@ -34,9 +75,11 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
MockArena arena = new();
WabiSabiConfig cfg = new();
var round = WabiSabiFactory.CreateRound(cfg);
+ var alice = WabiSabiFactory.CreateAlice();
+ round.Alices.Add(alice);
arena.OnTryGetRound = _ => round;
- var req = new ConnectionConfirmationRequest(round.Id, Guid.NewGuid(), null!, null!, null!, null!);
+ var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
foreach (Phase phase in Enum.GetValues(typeof(Phase)))
{
if (phase != Phase.InputRegistration && phase != Phase.ConnectionConfirmation)
@@ -57,7 +100,7 @@ namespace WalletWasabi.Tests.UnitTests.WabiSabi.Backend
var round = WabiSabiFactory.CreateRound(cfg);
arena.OnTryGetRound = _ => round;
- var req = new ConnectionConfirmationRequest(round.Id, Guid.NewGuid(), null!, null!, null!, null!);
+ var req = WabiSabiFactory.CreateConnectionConfirmationRequest(round);
await using PostRequestHandler handler = new(cfg, new Prison(), arena, new MockRpcClient());
var ex = Assert.Throws<WabiSabiProtocolException>(() => handler.ConfirmConnection(req));
Assert.Equal(WabiSabiProtocolErrorCode.AliceNotFound, ex.ErrorCode);

MODIFY
WalletWasabi/WabiSabi/Backend/PostRequests/PostRequestHandler.cs
WalletWasabi/WabiSabi/Backend/PostRequests/PostRequestHandler.cs
@@ -110,16 +110,13 @@ namespace WalletWasabi.WabiSabi.Backend.PostRequests
{
throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.RoundNotFound);
}
- if (round.Phase != Phase.InputRegistration && round.Phase != Phase.ConnectionConfirmation)
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
- }
- if (!round.TryGetAlice(request.AliceId, out var alice))
- {
- throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.AliceNotFound);
- }
- throw new NotImplementedException();
+ return round.ConfirmAlice(
+ request.AliceId,
+ request.ZeroAmountCredentialRequests,
+ request.RealAmountCredentialRequests,
+ request.ZeroWeightCredentialRequests,
+ request.RealWeightCredentialRequests);
}
}

MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
WalletWasabi/WabiSabi/Backend/Rounds/Round.cs
@@ -158,6 +158,43 @@ namespace WalletWasabi.WabiSabi.Backend.Rounds
return new(alice.Id, amountCredentialResponse, weightCredentialResponse);
}
+ public ConnectionConfirmationResponse ConfirmAlice(Guid aliceId, ZeroCredentialsRequest zeroAmountCredentialRequests, RealCredentialsRequest realAmountCredentialRequests, ZeroCredentialsRequest zeroWeightCredentialRequests, RealCredentialsRequest realWeightCredentialRequests)
+ {
+ var amountZeroCredentialResponse = AmountCredentialIssuer.HandleRequest(zeroAmountCredentialRequests);
+ var weightZeroCredentialResponse = WeightCredentialIssuer.HandleRequest(zeroWeightCredentialRequests);
+
+ lock (Lock)
+ {
+ var alice = Alices.FirstOrDefault(x => x.Id == aliceId);
+ if (alice is null)
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.AliceNotFound);
+ }
+
+ if (Phase == Phase.InputRegistration)
+ {
+ return new ConnectionConfirmationResponse(
+ amountZeroCredentialResponse,
+ weightZeroCredentialResponse);
+ }
+ else if (Phase == Phase.ConnectionConfirmation)
+ {
+ var amountRealCredentialResponse = AmountCredentialIssuer.HandleRequest(realAmountCredentialRequests);
+ var weightRealCredentialResponse = WeightCredentialIssuer.HandleRequest(realWeightCredentialRequests);
+
+ return new ConnectionConfirmationResponse(
+ amountZeroCredentialResponse,
+ weightZeroCredentialResponse,
+ amountRealCredentialResponse,
+ weightRealCredentialResponse);
+ }
+ else
+ {
+ throw new WabiSabiProtocolException(WabiSabiProtocolErrorCode.WrongPhase);
+ }
+ }
+ }
+
internal void RemoveAlice(Guid aliceId)
{
lock (Lock)

MODIFY
WalletWasabi/WabiSabi/Crypto/WabiSabiClient.cs
WalletWasabi/WabiSabi/Crypto/WabiSabiClient.cs
@@ -87,7 +87,7 @@ namespace WalletWasabi.WabiSabi.Crypto
}
/// <summary>
- /// Creates a <see cref="CredentialsRequest">credential registration request messages</see>
+ /// Creates a <see cref="RealCredentialsRequest">credential registration request messages</see>
/// for requesting `k` non-zero-value credentials.
/// </summary>
/// <param name="amountsToRequest">List of amounts requested in credentials.</param>
@@ -96,7 +96,7 @@ namespace WalletWasabi.WabiSabi.Crypto
/// 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 (CredentialsRequest, CredentialsResponseValidation) CreateRequest(
+ public (RealCredentialsRequest, CredentialsResponseValidation) CreateRequest(
IEnumerable<long> amountsToRequest,
IEnumerable<Credential> credentialsToPresent)
{

Add conn conf checks