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 / Participant | Alice | Bob | Charlie | David | Eve |
---|---|---|---|---|---|
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.