Use separate R-s
MODIFY
WalletWasabi.Backend/Controllers/ChaumianCoinJoinController.cs
WalletWasabi.Backend/Controllers/ChaumianCoinJoinController.cs
@@ -62,8 +62,9 @@ namespace WalletWasabi.Backend.Controllers
{
Phase = round.Phase,
SignerPubKey = round.Signer.Key.PubKey,
+ RpubKey = round.Signer.R.PubKey,
AdditionalSignerPubKeys = round.AdditionalMixingLevels.Select(x => x.signer.Key.PubKey.ToHex()),
- RpubKey = round.Rkey.PubKey,
+ AdditionalRPubKeys = round.AdditionalMixingLevels.Select(x => x.signer.R.PubKey.ToHex()),
Denomination = round.Denomination,
RegisteredPeerCount = round.CountAlices(syncLock: false),
RequiredPeerCount = round.AnonymitySet,

MODIFY
WalletWasabi/Backend/Models/Responses/CcjRunningRoundState.cs
WalletWasabi/Backend/Models/Responses/CcjRunningRoundState.cs
@@ -19,11 +19,12 @@ namespace WalletWasabi.Backend.Models.Responses
[JsonConverter(typeof(PubKeyJsonConverter))]
public PubKey SignerPubKey { get; set; }
- public IEnumerable<string> AdditionalSignerPubKeys { get; set; }
-
[JsonConverter(typeof(PubKeyJsonConverter))]
public PubKey RpubKey { get; set; }
+ public IEnumerable<string> AdditionalSignerPubKeys { get; set; }
+ public IEnumerable<string> AdditionalRPubKeys { get; set; }
+
public int RegisteredPeerCount { get; set; }
public int RequiredPeerCount { get; set; }
@@ -55,6 +56,7 @@ namespace WalletWasabi.Backend.Models.Responses
Denomination = state.Denomination,
SignerPubKey = state.SignerPubKey,
AdditionalSignerPubKeys = state.AdditionalSignerPubKeys,
+ AdditionalRPubKeys = state.AdditionalRPubKeys,
RpubKey = state.RpubKey,
RegisteredPeerCount = registeredPeerCount,
RequiredPeerCount = state.RequiredPeerCount,

MODIFY
WalletWasabi/Models/ChaumianCoinJoin/CcjRound.cs
WalletWasabi/Models/ChaumianCoinJoin/CcjRound.cs
@@ -34,7 +34,6 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
public Transaction UnsignedCoinJoin { get; private set; }
private string _unsignedCoinJoinHex;
- public Key Rkey { get; }
public Signer Signer { get; }
public (Money denomination, Signer signer)[] AdditionalMixingLevels { get; }
@@ -161,13 +160,12 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
StatusLock = new object();
Status = CcjRoundStatus.NotStarted;
- Rkey = new Key();
- Signer = new Signer(new Key(), Rkey);
+ Signer = new Signer(new Key());
AdditionalMixingLevels = new (Money denomination, Signer signer)[10];
for (int i = 0; i < AdditionalMixingLevels.Length; i++)
{
- var signer = new Signer(new Key(), Rkey);
+ var signer = new Signer(new Key());
Money denomination;
if (i == 0)
{

MODIFY
WalletWasabi/Services/CcjClient.cs
WalletWasabi/Services/CcjClient.cs
@@ -19,6 +19,7 @@ using System.Collections.Concurrent;
using System.Net.Http;
using NBitcoin.Crypto;
using static NBitcoin.Crypto.ECDSABlinding;
+using NBitcoin.BouncyCastle.Math;
namespace WalletWasabi.Services
{
@@ -466,7 +467,7 @@ namespace WalletWasabi.Services
{
string activeLabel = "ZeroLink Mixed Coin";
IEnumerable<HdPubKey> allActiveKeys = allUnusedInternalKeys.Where(x => x.Label == activeLabel);
- HdPubKey activeKey = null;
+ List<HdPubKey> activeKeys = new List<HdPubKey>();
KeyManager.AssertLockedInternalKeysIndexed(14);
IEnumerable<HdPubKey> internalNotCachedLockedKeys = KeyManager.GetKeys(KeyState.Locked, isInternal: true).Except(AccessCache.Keys);
@@ -474,26 +475,46 @@ namespace WalletWasabi.Services
if (allActiveKeys.Count() >= 7 || !internalNotCachedLockedKeys.Any()) // Then don't generate new keys, because it'd bloat the wallet.
{
// Find the first one that we did not try to register in the current session.
- activeKey = allActiveKeys.FirstOrDefault(x => !AccessCache.ContainsKey(x));
+ foreach (var ac in allActiveKeys.Where(x => !AccessCache.ContainsKey(x)))
+ {
+ if (activeKeys.Count >= 10)
+ {
+ break;
+ }
+ activeKeys.Add(ac);
+ }
// If there is no such a key, then use the oldest, but make sure it's not the same as the change.
- if (activeKey == default)
+ if (activeKeys.Count < 10)
+ {
+ foreach (var ac in AccessCache.Where(x => allActiveKeys.Contains(x.Key) && changeAddress != x.Key.GetP2wpkhAddress(Network)).OrderBy(x => x.Value).Select(x => x.Key))
{
- activeKey = AccessCache.Where(x => allActiveKeys.Contains(x.Key) && changeAddress != x.Key.GetP2wpkhAddress(Network)).OrderBy(x => x.Value).First().Key;
+ if (activeKeys.Count >= 10)
+ {
+ break;
+ }
+ activeKeys.Add(ac);
+ }
}
- activeKey.SetLabel(activeLabel);
- activeKey.SetKeyState(KeyState.Locked);
-
- //activeAddress = activeKey.GetP2wpkhAddress(Network);
- activeOutputAddresses.Add(activeKey.GetP2wpkhAddress(Network));
}
else
{
- activeKey = internalNotCachedLockedKeys.Where(x => changeAddress != x.GetP2wpkhAddress(Network)).RandomElement();
- activeKey.SetLabel(activeLabel);
+ foreach (var ac in internalNotCachedLockedKeys.Where(x => changeAddress != x.GetP2wpkhAddress(Network)))
+ {
+ if (activeKeys.Count >= 10)
+ {
+ break;
+ }
+ activeKeys.Add(ac);
+ }
+ }
+
+ foreach (HdPubKey ac in activeKeys)
+ {
+ ac.SetLabel(activeLabel);
+ ac.SetKeyState(KeyState.Locked);
+ activeOutputAddresses.Add(ac.GetP2wpkhAddress(Network));
+ AccessCache.AddOrReplace(ac, DateTimeOffset.UtcNow);
}
- //activeAddress = activeKey.GetP2wpkhAddress(Network);
- activeOutputAddresses.Add(activeKey.GetP2wpkhAddress(Network));
- AccessCache.AddOrReplace(activeKey, DateTimeOffset.UtcNow);
}
}
@@ -502,19 +523,25 @@ namespace WalletWasabi.Services
var activeAddress = activeOutputAddresses.First();
var additionalActiveOutputAddresses = activeOutputAddresses.Skip(1);
PubKey signerPubKey = inputRegistrableRound.State.SignerPubKey;
+ PubKey rPubKey = inputRegistrableRound.State.RpubKey;
PubKey[] additionalSignerPubKeys = inputRegistrableRound.State.AdditionalSignerPubKeys.Select(x => new PubKey(x)).ToArray();
- PubKey roundRpubKey = inputRegistrableRound.State.RpubKey;
+ PubKey[] additionalRpubKeys = inputRegistrableRound.State.AdditionalRPubKeys.Select(x => new PubKey(x)).ToArray();
+
var outputScriptHash = new uint256(Hashes.SHA256(activeAddress.ScriptPubKey.ToBytes()));
var requester = new Requester();
- uint256 blindedOutputScriptHash = requester.BlindMessage(outputScriptHash, roundRpubKey, signerPubKey);
+ uint256 blindedOutputScriptHash = requester.BlindMessage(outputScriptHash, rPubKey, signerPubKey);
var additionalBlindedOutputScriptHashes = new List<uint256>();
+ var additionalRequesters = new List<Requester>();
uint256[] array = additionalActiveOutputAddresses.Select(x => new uint256(Hashes.SHA256(x.ScriptPubKey.ToBytes()))).ToArray();
for (int i = 0; i < array.Length; i++)
{
+ var ar = new Requester();
uint256 osh = (uint256)array[i];
- PubKey skp = additionalSignerPubKeys[i];
- additionalBlindedOutputScriptHashes.Add(requester.BlindMessage(osh, roundRpubKey, skp));
+ PubKey spk = additionalSignerPubKeys[i];
+ PubKey rpk = additionalRpubKeys[i];
+ additionalBlindedOutputScriptHashes.Add(ar.BlindMessage(osh, rpk, spk));
+ additionalRequesters.Add(ar);
}
var inputProofs = new List<InputProofModel>();
@@ -576,9 +603,11 @@ namespace WalletWasabi.Services
}
var additionalUnblindedSignatures = new List<BlindSignature>();
- foreach (var blindedOutputSignature in aliceClient.AdditionalBlindedOutputSignatures)
+ for (int i = 0; i < aliceClient.AdditionalBlindedOutputSignatures.Length; i++)
{
- BlindSignature us = requester.UnblindSignature(blindedOutputSignature);
+ BigInteger blindedOutputSignature = aliceClient.AdditionalBlindedOutputSignatures[i];
+ var ar = additionalRequesters.ToArray()[i];
+ BlindSignature us = ar.UnblindSignature(blindedOutputSignature);
if (!VerifySignature(outputScriptHash, us, signerPubKey))
{
throw new NotSupportedException("Coordinator did not sign the blinded output properly.");

Use separate R-s