And what's a "valid" input? Is there such a terminology in their repository?
Yes, anything that passes the input registration phase is valid.
private async Task MoveToConnectionConfirmationAsync()
{
using (BenchmarkLogger.Measure(LogLevel.Info, nameof(RemoveAlicesIfAnInputRefusedByMempoolNoLockAsync)))
{
await RemoveAlicesIfAnInputRefusedByMempoolNoLockAsync().ConfigureAwait(false);
}
using (BenchmarkLogger.Measure(LogLevel.Info, nameof(RemoveAliceIfCoinsAreNaughtyAsync)))
{
await RemoveAliceIfCoinsAreNaughtyAsync().ConfigureAwait(false);
It's probably worth a bit of logic in how the coordinator operates, ZKsnacks operates chaumian coinjoin structure, it runs through five main phases which are
Input Registration
Connection Confirmation
Output registration
Signing
Broadcasting
This could be further understood in the
CoordinatorRound class
Input Registration: in this phase, the client would sent an input and a blinded output, this is where the "banning" is done.
You can see the old code was
var round = new CoordinatorRound(RpcClient, UtxoReferee, RoundConfig, confirmationTarget, RoundConfig.ConfirmationTarget, RoundConfig.ConfirmationTargetReductionRate, TimeSpan.FromSeconds(RoundConfig.InputRegistrationTimeout));
changed to
var round = new CoordinatorRound(RpcClient, UtxoReferee, RoundConfig, confirmationTarget, RoundConfig.ConfirmationTarget, RoundConfig.ConfirmationTargetReductionRate, TimeSpan.FromSeconds(RoundConfig.InputRegistrationTimeout), CoinVerifier);
They added a new dependency called "CoinVerifier" which is called by the "naughty" method you mentioned above, basically the Coinverfier class interacts with ApiResponseItem that gets the ban/approve from an HTTP response.
Now if you check the private asynchronous method called Task MoveToConnectionConfirmationAsync()
private async Task MoveToConnectionConfirmationAsync()
{
using (BenchmarkLogger.Measure(LogLevel.Info, nameof(RemoveAlicesIfAnInputRefusedByMempoolNoLockAsync)))
{
await RemoveAlicesIfAnInputRefusedByMempoolNoLockAsync().ConfigureAwait(false);
}
using (BenchmarkLogger.Measure(LogLevel.Info, nameof(RemoveAliceIfCoinsAreNaughtyAsync)))
{
await RemoveAliceIfCoinsAreNaughtyAsync().ConfigureAwait(false);
}
Phase = RoundPhase.ConnectionConfirmation;
}
so before moving to the second phase of Connection Confirmation, all the filtering is done, your coins become invalid either due to them being "naughty" or "Invalid", let's just assume the input registration is invalidated for no valid reason.
Up to this point, you have only provided input and a blinded output (no Sybil attack is possible) since the coordinator did not receive an output from you, and you are not yet enrolled in a coinjoin, so if they want to Sybil attack you, they would need to sign the blinded output and send it back to you
If you pass this phase, the coordinator will now need to sign the blinded output and send it back to you with a new identity/UniqueId(still no Sybil attack or its detection is possible yet)
So let's just assume it's only me and you trying to coinjoin this round, you got your inputs registered and I got mine, we both got our blinded outputs signed and received our unique-Ids, we would now enter the Connection Confirmation phase, and whereby we both send our uniqeIds to the coordinator and we both know they are valid and the coordinator MUST accept them.
If the coordinator were to reject my connection confirmation it would be safe to assume that they are launching a Sybil attack against you (of course I don't know whom they are launching the attack against but having refused my connection while I have a valid unique id the proves that I have registered x input means they are doing the attack), there is no VALID reason for them to refuse my conn-conf, it should be accepted and after the timeout we need to move OutputRegistration phase, you can check the code to find that Phase = RoundPhase.OutputRegistration; doesn't have any valid conditions of which they can reject you for "no reason".
This applies to the rest of the phases, if the coordinator accepted your input registration -- there is no valid for reason them to stop you from going forward, I am not saying they "can't" of course they can reject your connection confirmation or even claim that your output registration was invalid, they can even claim that you did not register your input to start with, but given that the code is open-source it MUST act as it says it does, otherwise, people/observers would see that they are being refused for no reason which means the code which is run by the coordinator isn't exactly what they say it is and/or, they are trying out some attacks.
If Wasabi going to sybil one input they put all other inputs in a different round. Very easy for them. And undetectable.
Round ID, Input count, current phase, time to next phase are all publically available, your claim would be valid if you register two inputs to the same round and they end up in different rounds, otherwise, how do you suggest doing that without anyone noticing? obviously, most users don't check all this info and just use the next GUI and set their auto-conjoin, but don't you think there are enough people (Wasabi rivals for example) logging every round detail to showcase how Wasabi is doing all of these claims? besides, whatever you suggested could be applied to all other Coinjoins that use a centralized coordinator, which is why I said "let's keep criticism" fair.
My main issue with Wasabi is the fact that their default coordinator and funding firm ZKsnacks censors transactions for no valid reasons.
Okay, but if they wanted to target individual UTXOs every now and then, that might be feasible, right?
It's always doable, I am just not sure about how feasible if enough people are observing these rounds and actually are spending time and money to detect such attacks (mainly their competitors), if you see all the research Samourai Wallet team does on Wasabi, you would probably guess that there are enough people watching them, of course tho, just because nobody caught them -- doesn't mean they have never done it.