Practical Example

Assume we have 5 participants that want to shuffle their UTXOs. Each participant has a UTXO with the same ERC20 tokens and amount, for example 5 USDT tokens, and they want to shuffle them to 5 unknown addresses.

Lets name them Alice, Bob, Charlie, David, and Eve:

flowchart TB
    Alice
    Bob
    Charlie
    David
    Eve

Alice, Bob, Charlie, David, and Eve want to send their UTXOs to some 5 addresses, and they don't want to reveal receivers of that UTXOs to anybody. So, for coordination, they will use a service which implements Coin Shuffle protocol.

flowchart TB
    Alice --- Service
    Bob --- Service
    Charlie --- Service
    David --- Service
    Eve --- Service

Alice, Bob, Charlie, David, and Eve will register in the service by providing their UTXOs with proof of ownership.

Service will organize them into queue until enough participants will be registered.

In this example, we will assume that 5 participants are enough to shuffle.

flowchart TB
    Alice --> alice_utxo(5$A + Alice's signature)
    Bob --> bob_utxo(5$B + Bob's signature)
    Charlie --> charlie_utxo(5$C + Charlie's signature)
    David --> david_utxo(5$D + David's signature)
    Eve --> eve_utxo(5$E + Eve's signature)
    alice_utxo --> Service
    bob_utxo --> Service
    charlie_utxo --> Service
    david_utxo --> Service
    eve_utxo --> Service
    
    Service --> queue[[Queue: E, A, D, B, C]]

Then, when enough participants will be registered, service will form a room, and notify the participants, so they can send their RSA public keys.

flowchart TB
    Service --> room[[Room: A, B, C, D, E]]

As a response, participants will send their RSA public keys to the service:

flowchart TB
    Alice --> alice_pk(Alice's RSA public key)
    Bob --> bob_pk(Bob's RSA public key)
    Charlie --> charlie_pk(Charlie's RSA public key)
    David --> david_pk(David's RSA public key)
    Eve --> eve_pk(Eve's RSA public key)
    alice_pk --> Service
    bob_pk --> Service
    charlie_pk --> Service
    david_pk --> Service
    eve_pk --> Service

Service will define the order of shuffling and send RSA public keys that are required for outputs encoding and decoding to each participant:

flowchart TB
    Service --> alice_keys[[Alice's keys: B, C, D, E]]
    Service --> bob_keys[[Bob's keys: C, D, E]]
    Service --> charlie_keys[[Charlie's keys: D, E]]
    Service --> david_keys[[David's keys: E]]
    Service --> eve_keys[[Eve's keys:]]
    alice_keys --> Alice
    bob_keys --> Bob
    charlie_keys --> Charlie
    david_keys --> David
    eve_keys --> Eve

Note, that each participant already knows his public key.

Table of keys that each participant has:

Key / ParticipantAliceBobCharlieDavidEve
Alice
Bob
Charlie
David
Eve

Then service will send encrypted outputs to each participant, starting with Alice:

Alice is the first participant in the room, so she will receive list of empty encrypted inputs, and encrypt her output.

Firstly, Alice will encrypt her output with her public keys:

flowchart LR
    alice_output["@A"]-- Eve's key -->alice_output1["E[ @A ]"]
    alice_output1-- David's key -->alice_output2["D[ E[ @A ] ]"]
    alice_output2-- Charlie's key -->alice_output3["C[ D[ E[ @A ] ] ]"]
    alice_output3-- Bob's key -->alice_output4["B[ C[ D[ E[ @A ] ] ] ]"]

Then, Alice will send encrypted output to Bob through service. Bob knows, that received encrypted output is encrypted with his RSA the public key, so he will decrypt it using his secret key:

flowchart LR
    alice_output3["B[ C[ D[ E[ @A ] ] ] ]"]-- Bob's secret key -->bob_output1["C[ D[ E[ @A ] ] ]"]

Then Bob will encrypt his output with his public keys:

flowchart LR
    bob_output["@B"] -- Eve's key -->bob_output1["E[ @B ]"]
    bob_output1 -- David's key -->bob_output2["D[ E[ @B ] ]"]
    bob_output2 -- Charlie's key -->bob_output3["C[ D[ E[ @B ] ] ]"]

Then, Bob will shuffle them, and send encrypted outputs to Charlie through service.

flowchart LR
    Bob --- bobs_outputs[["C[ D[ E[ @B ] ] ] <br> C[ D[ E[ @A ] ] ]"]]
    bobs_outputs --> Service
    Service --> Charlie

Charlie will decrypt its upper layers with her secret key:

flowchart LR
    bobs_outputs["C[ D[ E[ @A ] ] ]<br> C[ D[ E[ @B ] ] ]"]-- Charlie's secret key -->charlie_output1["D[ E[ @A ] ]<br> D[ E[ @B ] ]"]

Then Charlie will encrypt her output with her public keys:

flowchart LR
    charlie_output["@C"] -- Eve's key -->charlie_output1["E[ @C ]"]
    charlie_output1 -- David's key -->charlie_output2["D[ E[ @C ] ]"]

Shuffle them, and send them to David:

flowchart LR
    Charlie --- charlies_outputs[["D[ E[ @A ] ] <br> D[ E[ @C ] ] <br> D[ E[ @B ] ]"]]
    charlies_outputs --> Service
    Service --> David

The process will continue until Eve will receive encrypted outputs from David. Eve will finally get fully decrypted outputs from all participants:

flowchart LR
    davids_outputs["E[ @C ]<br> E[ @D ]<br> E[ @A ]<br> E[ @B ]"]-- Eve's secret key -->eve_output1["@C<br> @D<br> @A<br> @B"]

Eve will send that outputs to service, service will form transaction with all inputs and outputs, and send it to all participants for signing.

flowchart TB
    Service --> transaction[["Transaction. <br> Inputs: $5D, $5C, $5B, $5A, $5E <br> Outputs: @C, @D, @A, @B, @E"]]
    transaction --> Alice
    transaction --> Bob
    transaction --> Charlie
    transaction --> David
    transaction --> Eve

Each participant will see, that transaction is valid and at least contains their input and output, so they will sign it and send it back to service.

The service will gather all required signatures, and then send them to the network.