public CredentialIssuer(CoordinatorSecretKey sk, int numberOfCredentials, WasabiRandom randomNumberGenerator) { CoordinatorSecretKey = Guard.NotNull(nameof(sk), sk); NumberOfCredentials = Guard.InRangeAndNotNull(nameof(numberOfCredentials), numberOfCredentials, 1, 100); CoordinatorParameters = CoordinatorSecretKey.ComputeCoordinatorParameters(); RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); }
public RoundParameters( WabiSabiConfig wabiSabiConfig, Network network, WasabiRandom random, FeeRate feeRate, Round?blameOf = null, Prison?prison = null) { Network = network; Random = random; FeeRate = feeRate; MaxInputCountByRound = wabiSabiConfig.MaxInputCountByRound; MinInputCountByRound = wabiSabiConfig.MinInputCountByRound; MinRegistrableAmount = wabiSabiConfig.MinRegistrableAmount; MaxRegistrableAmount = wabiSabiConfig.MaxRegistrableAmount; // Note that input registration timeouts can be modified runtime. StandardInputRegistrationTimeout = wabiSabiConfig.StandardInputRegistrationTimeout; ConnectionConfirmationTimeout = wabiSabiConfig.ConnectionConfirmationTimeout; OutputRegistrationTimeout = wabiSabiConfig.OutputRegistrationTimeout; TransactionSigningTimeout = wabiSabiConfig.TransactionSigningTimeout; BlameInputRegistrationTimeout = wabiSabiConfig.BlameInputRegistrationTimeout; BlameOf = blameOf; IsBlameRound = BlameOf is not null; BlameWhitelist = BlameOf ?.Alices .Select(x => x.Coin.Outpoint) .Where(x => prison is null || !prison.IsBanned(x)) .ToHashSet() ?? new HashSet <OutPoint>(); }
private RespondToChallenge CommitToNonces(Transcript transcript, WasabiRandom random) { // With all the statements committed, generate a vector of random secret // nonces for every equation in underlying proof system. In order to // ensure that nonces are never reused (e.g. due to an insecure RNG) with // different challenges which would leak the witness, these are generated // as synthetic nonces that also depend on the witness data. var secretNonceProvider = transcript.CreateSyntheticSecretNonceProvider(Knowledge.Witness, random); // Actually generate all of the required nonces and save them in an array // because if the enumerable is evaluated several times the results will // be different. // Note, ToArray() is needed to make sure that secretNonces is captured // once and shared between the phases. var equations = Knowledge.Statement.Equations; var secretNonces = secretNonceProvider.Sequence.Take(equations.Count()).ToArray(); // The prover then commits to these, adding the corresponding public // points to the transcript. var publicNonces = new GroupElementVector(equations.Zip(secretNonces, (equation, pointSecretNonces) => pointSecretNonces * equation.Generators)); transcript.CommitPublicNonces(publicNonces); return(() => Respond(transcript, publicNonces, secretNonces)); }
public RoundParameters( WabiSabiConfig wabiSabiConfig, Network network, WasabiRandom random, FeeRate feeRate, Round?blameOf = null) { Network = network; Random = random; FeeRate = feeRate; MaxInputCountByAlice = wabiSabiConfig.MaxInputCountByAlice; MinRegistrableAmount = wabiSabiConfig.MinRegistrableAmount; MaxRegistrableAmount = wabiSabiConfig.MaxRegistrableAmount; RegistrableWeightCredentials = wabiSabiConfig.RegistrableWeightCredentials; // Note that input registration timeouts can be modified runtime. ConnectionConfirmationTimeout = wabiSabiConfig.ConnectionConfirmationTimeout; OutputRegistrationTimeout = wabiSabiConfig.OutputRegistrationTimeout; TransactionSigningTimeout = wabiSabiConfig.TransactionSigningTimeout; BlameOf = blameOf; IsBlameRound = BlameOf is not null; BlameWhitelist = BlameOf ?.Alices .SelectMany(x => x.Coins) .Select(x => x.Outpoint) .ToHashSet() ?? new HashSet <OutPoint>(); }
public static string FromCharacters(int length, string characters, bool secureRandom = false) { WasabiRandom random = secureRandom ? SecureRandom.Instance : InsecureRandom.Instance; var res = random.GetString(length, characters); return(res); }
public static string FromCharacters(int length, string characters, bool secureRandom = false) { using WasabiRandom random = secureRandom ? new SecureRandom() : new InsecureRandom(); var res = random.GetString(length, characters); return(res); }
public WabiSabiClient( CredentialIssuerParameters credentialIssuerParameters, WasabiRandom randomNumberGenerator, long rangeProofUpperBound) { RangeProofWidth = (int)Math.Ceiling(Math.Log2(rangeProofUpperBound)); RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); CredentialIssuerParameters = Guard.NotNull(nameof(credentialIssuerParameters), credentialIssuerParameters); }
public WabiSabiClient( CoordinatorParameters coordinatorParameters, int numberOfCredentials, WasabiRandom randomNumberGenerator) { RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); NumberOfCredentials = Guard.InRangeAndNotNull(nameof(numberOfCredentials), numberOfCredentials, 1, 100); CoordinatorParameters = Guard.NotNull(nameof(coordinatorParameters), coordinatorParameters); Credentials = new CredentialPool(); }
/// <summary> /// Initializes a new instance of the CredentialIssuer class. /// </summary> /// <param name="credentialIssuerSecretKey">The <see cref="CredentialIssuerSecretKey">coordinator's secret key</see> used to issue the credentials.</param> /// <param name="randomNumberGenerator">The random number generator.</param> public CredentialIssuer( CredentialIssuerSecretKey credentialIssuerSecretKey, WasabiRandom randomNumberGenerator, long maxAmount) { MaxAmount = maxAmount; RangeProofWidth = (int)Math.Ceiling(Math.Log2(MaxAmount)); CredentialIssuerSecretKey = Guard.NotNull(nameof(credentialIssuerSecretKey), credentialIssuerSecretKey); CredentialIssuerParameters = CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(); RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); }
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 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 WabiSabiClient( CredentialIssuerParameters credentialIssuerParameters, WasabiRandom randomNumberGenerator, ulong maxAmount, CredentialPool?credentialPool = null) { MaxAmount = maxAmount; RangeProofWidth = (int)Math.Ceiling(Math.Log2(MaxAmount)); RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); CredentialIssuerParameters = Guard.NotNull(nameof(credentialIssuerParameters), credentialIssuerParameters); Credentials = credentialPool ?? new CredentialPool(); }
public WabiSabiClient( CredentialIssuerParameters credentialIssuerParameters, int numberOfCredentials, WasabiRandom randomNumberGenerator, ulong maxAmount) { MaxAmount = maxAmount; RangeProofWidth = (int)Math.Ceiling(Math.Log2(MaxAmount)); RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); NumberOfCredentials = Guard.InRangeAndNotNull(nameof(numberOfCredentials), numberOfCredentials, 1, 100); CredentialIssuerParameters = Guard.NotNull(nameof(credentialIssuerParameters), credentialIssuerParameters); Credentials = new CredentialPool(); }
/// <summary> /// Calculates how many inputs are desirable to be registered /// based on roughly the total number of coins in a wallet. /// Note: random biasing is applied. /// </summary> /// <returns>Desired input count.</returns> private static int GetInputTarget(int nonPrivateCount, int privateCount, WasabiRandom rnd) { var utxoCount = nonPrivateCount + privateCount; var utxoCountTarget = 21; var minPrivateUtxoCountTarget = 10; var maxUtxoCountTarget = 100; int targetInputCount; if (utxoCount < utxoCountTarget) { targetInputCount = 1; } else if (utxoCount > maxUtxoCountTarget || privateCount > utxoCountTarget || (privateCount > nonPrivateCount && privateCount >= minPrivateUtxoCountTarget)) { targetInputCount = MaxInputsRegistrableByWallet; } else { var min = 2; var max = MaxInputsRegistrableByWallet - 1; var percent = (double)(utxoCount - utxoCountTarget) / (maxUtxoCountTarget - utxoCountTarget); targetInputCount = (int)Math.Round((max - min) * percent + min); } var distance = new Dictionary <int, int>(); for (int i = 1; i <= MaxInputsRegistrableByWallet; i++) { distance.TryAdd(i, Math.Abs(i - targetInputCount)); } foreach (var best in distance.OrderBy(x => x.Value)) { if (rnd.GetInt(0, 10) < 5) { return(best.Key); } } return(targetInputCount); }
public Round(RoundParameters parameters, WasabiRandom random) { Parameters = parameters; CoinjoinState = new ConstructionState(Parameters); AmountCredentialIssuer = new(new(random), random, Parameters.MaxAmountCredentialValue); VsizeCredentialIssuer = new(new(random), random, Parameters.MaxVsizeCredentialValue); AmountCredentialIssuerParameters = AmountCredentialIssuer.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(); VsizeCredentialIssuerParameters = VsizeCredentialIssuer.CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(); InputRegistrationTimeFrame = TimeFrame.Create(Parameters.StandardInputRegistrationTimeout).StartNow(); ConnectionConfirmationTimeFrame = TimeFrame.Create(Parameters.ConnectionConfirmationTimeout); OutputRegistrationTimeFrame = TimeFrame.Create(Parameters.OutputRegistrationTimeout); TransactionSigningTimeFrame = TimeFrame.Create(Parameters.TransactionSigningTimeout); Id = CalculateHash(); }
public RoundParameters( WabiSabiConfig wabiSabiConfig, Network network, WasabiRandom random, FeeRate feeRate) { Network = network; Random = random; FeeRate = feeRate; MaxInputCountByRound = wabiSabiConfig.MaxInputCountByRound; MinInputCountByRound = wabiSabiConfig.MinInputCountByRound; MinRegistrableAmount = wabiSabiConfig.MinRegistrableAmount; MaxRegistrableAmount = wabiSabiConfig.MaxRegistrableAmount; // Note that input registration timeouts can be modified runtime. StandardInputRegistrationTimeout = wabiSabiConfig.StandardInputRegistrationTimeout; ConnectionConfirmationTimeout = wabiSabiConfig.ConnectionConfirmationTimeout; OutputRegistrationTimeout = wabiSabiConfig.OutputRegistrationTimeout; TransactionSigningTimeout = wabiSabiConfig.TransactionSigningTimeout; BlameInputRegistrationTimeout = wabiSabiConfig.BlameInputRegistrationTimeout; }
public static Proof Prove(Knowledge knowledge, WasabiRandom random) { return(ProofSystem.Prove(new Transcript(Array.Empty <byte>()), new[] { knowledge }, random).First()); }
internal static ImmutableList <SmartCoin> SelectCoinsForRound(IEnumerable <SmartCoin> coins, RoundParameters parameters, bool consolidationMode, int anonScoreTarget, WasabiRandom rnd) { var filteredCoins = coins .Where(x => parameters.AllowedInputAmounts.Contains(x.Amount)) .Where(x => parameters.AllowedInputTypes.Any(t => x.ScriptPubKey.IsScriptType(t))) .Where(x => x.EffectiveValue(parameters.MiningFeeRate) > Money.Zero) .ToShuffled() .ToArray(); var privateCoins = filteredCoins .Where(x => x.HdPubKey.AnonymitySet >= anonScoreTarget) .ToArray(); var nonPrivateCoins = filteredCoins .Where(x => x.HdPubKey.AnonymitySet < anonScoreTarget) .ToArray(); // Make sure it's ordered by 1 private and 1 non-private coins. // Otherwise we'd keep mixing private coins too much during the end of our mixing sessions. var organizedCoins = new List <SmartCoin>(); for (int i = 0; i < Math.Max(privateCoins.Length, nonPrivateCoins.Length); i++) { if (i < nonPrivateCoins.Length) { var npc = nonPrivateCoins[i]; organizedCoins.Add(npc); } if (i < privateCoins.Length) { var pc = privateCoins[i]; organizedCoins.Add(pc); } } // How many inputs do we want to provide to the mix? int inputCount = Math.Min( organizedCoins.Count, consolidationMode ? MaxInputsRegistrableByWallet : GetInputTarget(nonPrivateCoins.Length, privateCoins.Length, rnd)); // Always use the largest amounts, so we do not participate with insignificant amounts and fragment wallet needlessly. var largestAmounts = nonPrivateCoins .OrderByDescending(x => x.Amount) .Take(3) .ToArray(); // Select a group of coins those are close to each other by anonymity score. Dictionary <int, IEnumerable <SmartCoin> > groups = new(); // Create a bunch of combinations. var sw1 = Stopwatch.StartNew(); foreach (var coin in largestAmounts) { var baseGroup = organizedCoins.Except(new[] { coin }).Take(inputCount - 1).Concat(new[] { coin }); TryAddGroup(parameters, groups, baseGroup); var sw2 = Stopwatch.StartNew(); foreach (var group in organizedCoins .Except(new[] { coin }) .CombinationsWithoutRepetition(inputCount - 1) .Select(x => x.Concat(new[] { coin }))) { TryAddGroup(parameters, groups, group); if (sw2.Elapsed > TimeSpan.FromSeconds(1)) { break; } } sw2.Reset(); if (sw1.Elapsed > TimeSpan.FromSeconds(10)) { break; } } if (!groups.Any()) { return(ImmutableList <SmartCoin> .Empty); } // Select the group where the less coins coming from the same tx. var bestRep = groups.Values.Select(x => GetReps(x)).Min(x => x); var bestRepGroups = groups.Values.Where(x => GetReps(x) == bestRep); var remainingLargestAmounts = bestRepGroups .Select(x => x.OrderByDescending(x => x.Amount).First()) .ToHashSet(); var largestAmount = remainingLargestAmounts.RandomElement(); var finalCandidate = bestRepGroups .Where(x => x.OrderByDescending(x => x.Amount).First() == largestAmount) .RandomElement(); return(finalCandidate?.ToShuffled()?.ToImmutableList() ?? ImmutableList <SmartCoin> .Empty); }
public CredentialIssuerSecretKey(WasabiRandom rng) : this(rng.GetScalar(), rng.GetScalar(), rng.GetScalar(), rng.GetScalar(), rng.GetScalar()) { }
// Generate synthetic nonce using current state combined with additional randomness. public PublicNoncesSequence CreateSyntheticPublicNoncesProvider(IEnumerable <Scalar> secrets, WasabiRandom random) { // To integrate prior inputs for deterministic component of nonce // generation, first clone the state at the current point in the // transcript, which should already have the statement tag and public // inputs committed. var forked = _strobe.MakeCopy(); // add secret inputs as key material foreach (var secret in secrets) { forked.Key(secret.ToBytes(), false); } // Add additional randomness forked.Key(random.GetBytes(KeySizeInBytes), false); IEnumerable <Scalar> NoncesGenerator() { while (true) { yield return(new Scalar(forked.Prf(KeySizeInBytes, false))); } } // Generate a new scalar for each secret using this updated state as a seed. return(NoncesGenerator); }
public BlameRound(RoundParameters parameters, Round blameOf, ISet <OutPoint> blameWhitelist, WasabiRandom random) : base(parameters, random) { BlameOf = blameOf; BlameWhitelist = blameWhitelist; InputRegistrationTimeFrame = TimeFrame.Create(Parameters.BlameInputRegistrationTimeout).StartNow(); }
public static Proof Prove(Knowledge knowledge, WasabiRandom random) { return(Prover.Prove(new Transcript(new byte[0]), new[] { knowledge }, random).First()); }
// TODO swap return value order, remove GroupElement argument // expect nonce provider instead of WasabiRandom? public static (Knowledge knowledge, IEnumerable <GroupElement> bitCommitments) RangeProof(Scalar a, Scalar r, int width, WasabiRandom rnd) { var ma = a * Generators.Gg + r * Generators.Gh; var bits = Enumerable.Range(0, width).Select(i => a.GetBits(i, 1) == 0 ? Scalar.Zero : Scalar.One); // Generate bit commitments. // FIXME // - derive r_i from a, r, and additional randomness (like synthetic nonces)? // - maybe derive without randomness for idempotent requests? // (deterministic blinding terms)? probably simpler to just save // randomly generated credentials in memory or persistent storage, and // re-request by loading and re-sending. // - long term fee credentials will definitely need deterministic // randomness because the server can only give idempotent responses with // its own records. var randomness = Enumerable.Repeat(0, width).Select(_ => rnd.GetScalar()).ToArray(); var bitCommitments = bits.Zip(randomness, (b, r) => b * Generators.Gg + r * Generators.Gh); var columns = width * 3 + 1; // three witness terms per bit and one for the commitment
/// <summary> /// Initializes a new instance of the CredentialIssuer class. /// </summary> /// <param name="credentialIssuerSecretKey">The <see cref="CredentialIssuerSecretKey">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(CredentialIssuerSecretKey credentialIssuerSecretKey, int numberOfCredentials, WasabiRandom randomNumberGenerator) { CredentialIssuerSecretKey = Guard.NotNull(nameof(credentialIssuerSecretKey), credentialIssuerSecretKey); NumberOfCredentials = Guard.InRangeAndNotNull(nameof(numberOfCredentials), numberOfCredentials, 1, 100); CredentialIssuerParameters = CredentialIssuerSecretKey.ComputeCredentialIssuerParameters(); RandomNumberGenerator = Guard.NotNull(nameof(randomNumberGenerator), randomNumberGenerator); }
// Generate synthetic nonce using current state combined with additional randomness. public SyntheticSecretNonceProvider CreateSyntheticSecretNonceProvider(IEnumerable <Scalar> secrets, WasabiRandom random) => new(_strobe.MakeCopy(), secrets, random);
public static Proof Prove(Statement statement, Scalar witness, WasabiRandom random) { return(Prove(statement, new ScalarVector(witness), random)); }
public SyntheticSecretNonceProvider(Strobe128 strobe, IEnumerable <Scalar> secrets, WasabiRandom random) { Guard.NotNullOrEmpty(nameof(secrets), secrets); _strobe = strobe; _secretCount = secrets.Count(); // add secret inputs as key material foreach (var secret in secrets) { _strobe.Key(secret.ToBytes(), false); } _strobe.Key(random.GetBytes(32), false); }
public static Proof Prove(Statement statement, ScalarVector witness, WasabiRandom random) { return(Prove(new Knowledge(statement, witness), random)); }
public static IEnumerable <Proof> Prove(Transcript transcript, IEnumerable <Knowledge> knowledge, WasabiRandom random) { // Before anything else all components in a compound proof commit to the // individual sub-statement that will be proven, ensuring that the // challenges and therefore the responses depend on the statement as a // whole. foreach (var k in knowledge) { transcript.CommitStatement(k.Statement); } var deferredResponds = new List <DeferredProofCreator>(); foreach (var k in knowledge) { // With all the statements committed, generate a vector of random secret // nonces for every equation in underlying proof system. In order to // ensure that nonces are never reused (e.g. due to an insecure RNG) with // different challenges which would leak the witness, these are generated // as synthetic nonces that also depend on the witness data. var secretNonceProvider = transcript.CreateSyntheticSecretNonceProvider(k.Witness, random); ScalarVector secretNonces = secretNonceProvider.GetScalarVector(); // The prover then commits to these, adding the corresponding public // points to the transcript. var equations = k.Statement.Equations; var publicNonces = new GroupElementVector(equations.Select(equation => secretNonces * equation.Generators)); transcript.CommitPublicNonces(publicNonces); deferredResponds.Add((challenge) => new Proof(publicNonces, k.RespondToChallenge(challenge, secretNonces))); } // With the public nonces committed to the transcript the prover can then // derive a challenge that depend on the transcript state without needing // to interact with the verifier, but ensuring that they can't know the // challenge before the prover commitments are generated. Scalar challenge = transcript.GenerateChallenge(); return(deferredResponds.Select(createProof => createProof(challenge))); }
public CoordinatorSecretKey(WasabiRandom rng) : this(rng.GetScalar(), rng.GetScalar(), rng.GetScalar(), rng.GetScalar(), rng.GetScalar()) { }