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);
public ArenaClient( WabiSabiClient amountCredentialClient, WabiSabiClient vsizeCredentialClient, IWabiSabiApiRequestHandler requestHandler) { AmountCredentialClient = amountCredentialClient; VsizeCredentialClient = vsizeCredentialClient; RequestHandler = requestHandler; }
public ArenaClient( CredentialIssuerParameters amountCredentialIssuerParameters, CredentialIssuerParameters vsizeCredentialIssuerParameters, CredentialPool amountCredentialPool, CredentialPool vsizeCredentialPool, IArenaRequestHandler requestHandler, WasabiRandom random) { AmountCredentialClient = new WabiSabiClient(amountCredentialIssuerParameters, random, ProtocolConstants.MaxAmountPerAlice, amountCredentialPool); VsizeCredentialClient = new WabiSabiClient(vsizeCredentialIssuerParameters, random, ProtocolConstants.MaxVsizePerAlice, vsizeCredentialPool); RequestHandler = requestHandler; }
public ArenaClient( CredentialIssuerParameters amountCredentialIssuerParameters, CredentialIssuerParameters weightCredentialIssuerParameters, CredentialPool amountCredentialPool, CredentialPool weightCredentialPool, IArenaRequestHandler requestHandler, WasabiRandom random) { AmountCredentialClient = new WabiSabiClient(amountCredentialIssuerParameters, ProtocolCredentialNumber, random, ProtocolMaxAmountPerAlice, amountCredentialPool); WeightCredentialClient = new WabiSabiClient(weightCredentialIssuerParameters, ProtocolCredentialNumber, random, ProtocolMaxWeightPerAlice, weightCredentialPool); RequestHandler = requestHandler; }
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); }
public async Task SignTransactionAsync() { WabiSabiConfig config = new(); Round round = WabiSabiFactory.CreateRound(config); using Key key1 = new(); Alice alice1 = WabiSabiFactory.CreateAlice(key: key1); round.Alices.Add(alice1); using Key key2 = new(); Alice alice2 = WabiSabiFactory.CreateAlice(key: key2); round.Alices.Add(alice2); var coinjoin = round.Coinjoin; using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(config, round); var mockRpc = new Mock <IRPCClient>(); await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object); var rnd = new InsecureRandom(); var amountClient = new WabiSabiClient(round.AmountCredentialIssuerParameters, 2, rnd, 4300000000000ul); var weightClient = new WabiSabiClient(round.WeightCredentialIssuerParameters, 2, rnd, 2000ul); var apiClient = new ArenaClient(amountClient, weightClient, coordinator); round.SetPhase(Phase.TransactionSigning); // No inputs in the CoinJoin. await Assert.ThrowsAsync <ArgumentException>(async() => await apiClient.SignTransactionAsync(round.Id, alice1.Coins.ToArray(), new BitcoinSecret(key1, Network.Main), coinjoin)); coinjoin.Inputs.Add(alice1.Coins.First().Outpoint); // Trying to sign coins those are not in the CoinJoin. await Assert.ThrowsAsync <InvalidOperationException>(async() => await apiClient.SignTransactionAsync(round.Id, alice2.Coins.ToArray(), new BitcoinSecret(key2, Network.Main), coinjoin)); coinjoin.Inputs.Add(alice2.Coins.First().Outpoint); // Trying to sign coins with the wrong secret. await Assert.ThrowsAsync <InvalidOperationException>(async() => await apiClient.SignTransactionAsync(round.Id, alice1.Coins.ToArray(), new BitcoinSecret(key2, Network.Main), coinjoin)); Assert.False(round.Coinjoin.HasWitness); await apiClient.SignTransactionAsync(round.Id, alice1.Coins.ToArray(), new BitcoinSecret(key1, Network.Main), coinjoin); Assert.True(round.Coinjoin.Inputs.Where(i => alice1.Coins.Select(c => c.Outpoint).Contains(i.PrevOut)).All(i => i.HasWitScript())); await apiClient.SignTransactionAsync(round.Id, alice2.Coins.ToArray(), new BitcoinSecret(key2, Network.Main), coinjoin); Assert.True(round.Coinjoin.Inputs.Where(i => alice2.Coins.Select(c => c.Outpoint).Contains(i.PrevOut)).All(i => i.HasWitScript())); }
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); }
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); }
public static InputsRegistrationRequest CreateInputsRegistrationRequest(IEnumerable <InputRoundSignaturePair>?pairs, Round?round) { var roundId = round?.Id ?? Guid.NewGuid(); var inputRoundSignaturePairs = pairs ?? CreateInputRoundSignaturePairs(1, round?.Hash); var rnd = new InsecureRandom(); var client = new WabiSabiClient(new CredentialIssuerSecretKey(rnd).ComputeCredentialIssuerParameters(), 2, rnd, 4300000000000); // Input Reg var(zeroAmountCredentialRequest, _) = client.CreateRequestForZeroAmount(); var(zeroWeightCredentialRequest, _) = client.CreateRequestForZeroAmount(); return(new( roundId, inputRoundSignaturePairs, zeroAmountCredentialRequest, zeroWeightCredentialRequest)); }
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); }
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); }
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); }
public void RegistrationMessageSerialization() { var converters = new JsonConverter[] { new ScalarJsonConverter(), new GroupElementJsonConverter(), new MoneySatoshiJsonConverter() }; var numberOfCredentials = 2; var rnd = new SecureRandom(); var sk = new CoordinatorSecretKey(rnd); var issuer = new CredentialIssuer(sk, numberOfCredentials, rnd); var client = new WabiSabiClient(sk.ComputeCoordinatorParameters(), numberOfCredentials, rnd); var(credentialRequest, validationData) = client.CreateRequestForZeroAmount(); var credentialResponse = issuer.HandleRequest(credentialRequest); client.HandleResponse(credentialResponse, validationData); var present = client.Credentials.ZeroValue.Take(numberOfCredentials); (credentialRequest, _) = client.CreateRequest(new[] { Money.Coins(1) }, present); // Registration request message var serializedRequestMessage = JsonConvert.SerializeObject(credentialRequest, converters); var deserializedRequestMessage = JsonConvert.DeserializeObject <RegistrationRequestMessage>(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 <RegistrationResponseMessage>(serializedResponseMessage, converters); var reserializedResponseMessage = JsonConvert.SerializeObject(deserializedResponseMessage, converters); Assert.Equal(serializedResponseMessage, reserializedResponseMessage); }
public ArenaClient(WabiSabiClient amountCredentialClient, WabiSabiClient weightCredentialClient, IArenaRequestHandler requestHandler) { AmountCredentialClient = amountCredentialClient; WeightCredentialClient = weightCredentialClient; RequestHandler = requestHandler; }
public async Task RegisterInputAsyncTest() { var config = new WabiSabiConfig(); var round = WabiSabiFactory.CreateRound(config); using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(config, round); using var key = new Key(); var outpoint = BitcoinFactory.CreateOutPoint(); var mockRpc = new Mock <IRPCClient>(); mockRpc.Setup(rpc => rpc.GetTxOutAsync(outpoint.Hash, (int)outpoint.N, true)) .ReturnsAsync(new NBitcoin.RPC.GetTxOutResponse { IsCoinBase = false, Confirmations = 200, TxOut = new TxOut(Money.Coins(1m), key.PubKey.WitHash.GetAddress(Network.Main)), }); await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object); var rnd = new InsecureRandom(); var protocolCredentialNumber = 2; var protocolMaxWeightPerAlice = 1_000L; var amountClient = new WabiSabiClient(round.AmountCredentialIssuerParameters, protocolCredentialNumber, rnd, 4_300_000_000_000ul); var weightClient = new WabiSabiClient(round.WeightCredentialIssuerParameters, protocolCredentialNumber, rnd, (ulong)protocolMaxWeightPerAlice); var apiClient = new ArenaClient(amountClient, weightClient, coordinator); var aliceId = await apiClient.RegisterInputAsync(Money.Coins(1m), outpoint, key, round.Id, round.Hash); Assert.NotEqual(Guid.Empty, aliceId); Assert.Empty(apiClient.AmountCredentialClient.Credentials.Valuable); var reissuanceAmounts = new[] { Money.Coins(.75m) - round.FeeRate.GetFee(Constants.P2wpkhInputVirtualSize), Money.Coins(.25m) }; var inputWeight = 4 * Constants.P2wpkhInputVirtualSize; var inputRemainingWeights = new[] { protocolMaxWeightPerAlice - inputWeight }; // Phase: Input Registration await apiClient.ConfirmConnectionAsync( round.Id, aliceId, inputRemainingWeights, apiClient.AmountCredentialClient.Credentials.ZeroValue.Take(protocolCredentialNumber), reissuanceAmounts); Assert.Empty(apiClient.AmountCredentialClient.Credentials.Valuable); // Phase: Connection Confirmation round.SetPhase(Phase.ConnectionConfirmation); await apiClient.ConfirmConnectionAsync( round.Id, aliceId, inputRemainingWeights, apiClient.AmountCredentialClient.Credentials.ZeroValue.Take(protocolCredentialNumber), reissuanceAmounts); Assert.Single(apiClient.AmountCredentialClient.Credentials.Valuable, x => x.Amount.ToMoney() == reissuanceAmounts.First()); Assert.Single(apiClient.AmountCredentialClient.Credentials.Valuable, x => x.Amount.ToMoney() == reissuanceAmounts.Last()); }
public async Task SignTransactionAsync() { WabiSabiConfig config = new(); Round round = WabiSabiFactory.CreateRound(config); using Key key1 = new(); Alice alice1 = WabiSabiFactory.CreateAlice(key: key1, round: round); round.Alices.Add(alice1); using Key key2 = new(); Alice alice2 = WabiSabiFactory.CreateAlice(key: key2, round: round); round.Alices.Add(alice2); using Arena arena = await WabiSabiFactory.CreateAndStartArenaAsync(config, round); var mockRpc = new Mock <IRPCClient>(); await using var coordinator = new ArenaRequestHandler(config, new Prison(), arena, mockRpc.Object); var wabiSabiApi = new WabiSabiController(coordinator); var rnd = new InsecureRandom(); var amountClient = new WabiSabiClient(round.AmountCredentialIssuerParameters, rnd, 4300000000000L); var vsizeClient = new WabiSabiClient(round.VsizeCredentialIssuerParameters, rnd, 2000L); var apiClient = new ArenaClient(amountClient, vsizeClient, wabiSabiApi); round.SetPhase(Phase.TransactionSigning); var emptyState = round.Assert <ConstructionState>(); // We can't use ``emptyState.Finalize()` because this is not a valid transaction so we fake it var finalizedEmptyState = new SigningState(emptyState.Parameters, emptyState.Inputs, emptyState.Outputs); // No inputs in the CoinJoin. await Assert.ThrowsAsync <ArgumentException>(async() => await apiClient.SignTransactionAsync(round.Id, alice1.Coin, new BitcoinSecret(key1, Network.Main), finalizedEmptyState.CreateUnsignedTransaction(), CancellationToken.None)); var oneInput = emptyState.AddInput(alice1.Coin).Finalize(); round.CoinjoinState = oneInput; // Trying to sign coins those are not in the CoinJoin. await Assert.ThrowsAsync <InvalidOperationException>(async() => await apiClient.SignTransactionAsync(round.Id, alice2.Coin, new BitcoinSecret(key2, Network.Main), oneInput.CreateUnsignedTransaction(), CancellationToken.None)); var twoInputs = emptyState.AddInput(alice1.Coin).AddInput(alice2.Coin).Finalize(); round.CoinjoinState = twoInputs; // Trying to sign coins with the wrong secret. await Assert.ThrowsAsync <InvalidOperationException>(async() => await apiClient.SignTransactionAsync(round.Id, alice1.Coin, new BitcoinSecret(key2, Network.Main), twoInputs.CreateUnsignedTransaction(), CancellationToken.None)); Assert.False(round.Assert <SigningState>().IsFullySigned); var unsigned = round.Assert <SigningState>().CreateUnsignedTransaction(); await apiClient.SignTransactionAsync(round.Id, alice1.Coin, new BitcoinSecret(key1, Network.Main), unsigned, CancellationToken.None); Assert.True(round.Assert <SigningState>().IsInputSigned(alice1.Coin.Outpoint)); Assert.False(round.Assert <SigningState>().IsInputSigned(alice2.Coin.Outpoint)); Assert.False(round.Assert <SigningState>().IsFullySigned); await apiClient.SignTransactionAsync(round.Id, alice2.Coin, new BitcoinSecret(key2, Network.Main), unsigned, CancellationToken.None); Assert.True(round.Assert <SigningState>().IsInputSigned(alice2.Coin.Outpoint)); Assert.True(round.Assert <SigningState>().IsFullySigned); }
public async Task SignTransactionAsync() { WabiSabiConfig config = new(); Round round = WabiSabiFactory.CreateRound(config); var password = "******"; var km = ServiceFactory.CreateKeyManager(password); var keyChain = new KeyChain(km, new Kitchen(password)); var destinationProvider = new InternalDestinationProvider(km); var coins = destinationProvider.GetNextDestinations(2) .Select(dest => ( Coin: new Coin(BitcoinFactory.CreateOutPoint(), new TxOut(Money.Coins(1.0m), dest)), OwnershipProof: keyChain.GetOwnershipProof(dest, new CoinJoinInputCommitmentData("test", uint256.One)))) .ToArray(); Alice alice1 = WabiSabiFactory.CreateAlice(coins[0].Coin, coins[0].OwnershipProof, round: round); round.Alices.Add(alice1); Alice alice2 = WabiSabiFactory.CreateAlice(coins[1].Coin, coins[1].OwnershipProof, round: round); round.Alices.Add(alice2); using Arena arena = await ArenaBuilder.From(config).CreateAndStartAsync(round); var mockRpc = new Mock <IRPCClient>(); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); var idempotencyRequestCache = new IdempotencyRequestCache(memoryCache); using CoinJoinFeeRateStatStore coinJoinFeeRateStatStore = new(config, arena.Rpc); var wabiSabiApi = new WabiSabiController(idempotencyRequestCache, arena, coinJoinFeeRateStatStore); InsecureRandom rnd = InsecureRandom.Instance; var amountClient = new WabiSabiClient(round.AmountCredentialIssuerParameters, rnd, 4300000000000L); var vsizeClient = new WabiSabiClient(round.VsizeCredentialIssuerParameters, rnd, 2000L); var apiClient = new ArenaClient(amountClient, vsizeClient, wabiSabiApi); round.SetPhase(Phase.TransactionSigning); var emptyState = round.Assert <ConstructionState>(); // We can't use ``emptyState.Finalize()` because this is not a valid transaction so we fake it var finalizedEmptyState = new SigningState(round.Parameters, emptyState.Events); // No inputs in the coinjoin. await Assert.ThrowsAsync <ArgumentException>(async() => await apiClient.SignTransactionAsync(round.Id, alice1.Coin, coins[0].OwnershipProof, keyChain, finalizedEmptyState.CreateUnsignedTransaction(), CancellationToken.None)); var oneInput = emptyState.AddInput(alice1.Coin).Finalize(); round.CoinjoinState = oneInput; // Trying to sign coins those are not in the coinjoin. await Assert.ThrowsAsync <InvalidOperationException>(async() => await apiClient.SignTransactionAsync(round.Id, alice2.Coin, coins[1].OwnershipProof, keyChain, oneInput.CreateUnsignedTransaction(), CancellationToken.None)); var twoInputs = emptyState.AddInput(alice1.Coin).AddInput(alice2.Coin).Finalize(); round.CoinjoinState = twoInputs; Assert.False(round.Assert <SigningState>().IsFullySigned); var unsigned = round.Assert <SigningState>().CreateUnsignedTransaction(); await apiClient.SignTransactionAsync(round.Id, alice1.Coin, coins[0].OwnershipProof, keyChain, unsigned, CancellationToken.None); Assert.True(round.Assert <SigningState>().IsInputSigned(alice1.Coin.Outpoint)); Assert.False(round.Assert <SigningState>().IsInputSigned(alice2.Coin.Outpoint)); Assert.False(round.Assert <SigningState>().IsFullySigned); await apiClient.SignTransactionAsync(round.Id, alice2.Coin, coins[1].OwnershipProof, keyChain, unsigned, CancellationToken.None); Assert.True(round.Assert <SigningState>().IsInputSigned(alice2.Coin.Outpoint)); Assert.True(round.Assert <SigningState>().IsFullySigned); }
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()); } }
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); } }