Skip to content

Commit

Permalink
Merge pull request decentralized-identity#200 from dhh1128/coin-toss
Browse files Browse the repository at this point in the history
tweak: update verbiage slightly
  • Loading branch information
swcurran authored Aug 23, 2019
2 parents 4463d6c + 22c9a20 commit cec53ce
Showing 1 changed file with 19 additions and 17 deletions.
36 changes: 19 additions & 17 deletions features/0193-coin-flip/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ following [PIURI](https://github.com/hyperledger/aries-rfcs/blob/master/concepts

### Roles

There are 2 roles in the protocol: __caller__ and __flipper__. These role names parallel the roles in a physical coin flip: the _flipper_ randomly generates an outcome, and the _caller_ announces the outcome that they pick, before the outcome is known. If the caller predicts the outcome correctly, then the caller chooses what happens next; otherwise, the flipper chooses.
There are 2 roles in the protocol: __Recorder__ and __Caller__. These role names parallel the roles in a physical coin flip: the _Recorder_ performs a process that freezes/records the state of a flipped coin, and the _Caller_ announces the state that they predict, before the state is known. If the caller predicts the state correctly, then the caller chooses what happens next; otherwise, the recorder chooses.

### Algorithm

Before describing the messages, let's review the algorithm that will be used. This algorithm is not new; it is a simple commitment scheme [described on wikipedia](https://en.wikipedia.org/wiki/Coin_flipping#Telecommunications) and implemented in various places. The RFC merely formalizes the algorithm for DIDComm.

1. Caller chooses a random [UUID](https://tools.ietf.org/html/rfc4122) and sends it to Flipper using the [`propose` message described below](#propose). A [version 4 UUID](https://tools.ietf.org/html/rfc4122#section-4.4) is recommended, though any UUID version should be accepted. Note that the UUID is represented in lower case, with hyphens, and without enclosing curly braces. Suppose this value is `01bf7abd-aa80-4389-bf8c-dba0f250bb1b`.
1. Caller chooses a random [UUID](https://tools.ietf.org/html/rfc4122) and sends it to Recorder using the [`propose` message described below](#propose). A [version 4 UUID](https://tools.ietf.org/html/rfc4122#section-4.4) is recommended, though any UUID version should be accepted. Note that the UUID is represented in lower case, with hyphens, and without enclosing curly braces. Suppose this value is `01bf7abd-aa80-4389-bf8c-dba0f250bb1b`.

2. Flipper chooses a cooresponding random UUID -- say, `d96dfb58-60ba-4fcd-9ca0-a2be41181d6f`.
2. Recorder chooses a cooresponding random UUID -- say, `d96dfb58-60ba-4fcd-9ca0-a2be41181d6f`.

3. Flipper imagines an outcome for an imaginary coin flip -- either the string `heads` or the string `tails`. Suppose Flipper imagines `tails`.
3. Recorder captures an outcome for an imaginary coin flip -- either the string `heads` or the string `tails`. Suppose Recorder captures `tails`.

4. Flipper builds a __flip string__. This is single-space-separated concatenation of 3 inputs: `flipper-imagined-outcome flipper-uuid caller-uuid`. Given the random numbers and tails outcome in our example, this string would be `tails d96dfb58-60ba-4fcd-9ca0-a2be41181d6f 01bf7abd-aa80-4389-bf8c-dba0f250bb1b`. Flipper then computes a SHA256 hash of the flip string, which is `B78DC2D94F6E92B69491F13DC8C866C0A31F896069D3DD69472D0D7740967011` for our example, and sends it to Caller using the [`flip` message described below](#flip). This hash commits Flipper to all inputs, without revealing Flipper's UUID, and it is the Flipper's way of posing to the Caller the question, "heads or tails?"
4. Recorder builds a __flip string__. This is single-space-separated concatenation of 3 inputs: `recorder-captured-state recorder-uuid caller-uuid`. Given the random numbers and tails state in our example, this string would be `tails d96dfb58-60ba-4fcd-9ca0-a2be41181d6f 01bf7abd-aa80-4389-bf8c-dba0f250bb1b`. Recorder then computes a SHA256 hash of the flip string, which is `B78DC2D94F6E92B69491F13DC8C866C0A31F896069D3DD69472D0D7740967011` for our example, and sends it to Caller using the [`flip` message described below](#flip). This hash commits Recorder to all inputs, without revealing Recorder's UUID, and it is the Recorder's way of posing to the Caller the question, "heads or tails?"

5. Caller announces their committed choice -- for instance, "heads", using the ['call' message described below](#call). This commits Caller to a particular outcome.
5. Caller announces their committed choice -- for instance, "heads", using the ['call' message described below](#call). This commits Caller to a particular prediction about the state of the virtual coin.

6. Flipper uses a ['reveal' message](#reveal) to reveal _flip string_. Both parties discover who won the coin flip. If Caller predicted correctly, the outcome at the beginning of _flip string_ will match the Caller's choice in step 6, and Caller wins. Otherwise, Flipper wins. Neither party is able to manipulate the outcome. This is guaranteed by both parties checking to see that their UUIDs appear in the correct position in _flip string_, and that _flip string_ does indeed hash to the value computed in step 4.
6. Recorder uses a ['reveal' message](#reveal) to reveal _flip string_. Both parties discover who won the coin flip. If Caller predicted the state correctly, the state at the beginning of _flip string_ will match the Caller's choice in step 6, and Caller wins. Otherwise, Recorder wins. Neither party is able to manipulate the outcome. This is guaranteed by both parties checking to see that their UUIDs appear in the correct position in _flip string_, and that _flip string_ does indeed hash to the value computed in step 4.

### States

Expand Down Expand Up @@ -70,7 +70,7 @@ This diagram only depicts the so-called "happy path". It is possible to experien

#### `propose`

The protocol begins when Caller sends to Flipper a `propose` message that embodies Step 1 in the [algorithm above](#algorithm). It looks like this:
The protocol begins when Caller sends to Recorder a `propose` message that embodies Step 1 in the [algorithm above](#algorithm). It looks like this:

```jsonc
{
Expand All @@ -80,7 +80,7 @@ The protocol begins when Caller sends to Flipper a `propose` message that embodi
"comment": "Let's flip to see who goes first.",
"choice-id": "did:sov:SLfEi9esrjzybysFxQZbfq;spec/tictactoe/1.0/who-goes-first",
"caller-wins": "did:example:abc123", // Meaning of value defined in superprotocol
"flipper-wins": "did:example:xyz456", // Meaning of value defined in superprotocol
"recorder-wins": "did:example:xyz456", // Meaning of value defined in superprotocol
// Optional; connects to superprotocol
"~thread": {
"pthid": "a2be4118-4f60-bacd-c9a0-dfb581d6fd96"
Expand All @@ -90,7 +90,7 @@ The protocol begins when Caller sends to Flipper a `propose` message that embodi

The `@type` and `@id` fields are standard for DIDComm. The `caller-uuid` field conveys the data required by Step 1 of the algorithm. The optional `comment` field follows [localization conventions](../0043-l10n/README.md) and is irrelevant unless the coin flip intends to invite human participation. The `~thread.pthid` [decorator](../../concepts/0011-decorators/README.md) is optional but should be common; it [identifies the thread of the parent interaction](../../concepts/0008-message-id-and-threading/README.md#threaded-messages) (the [superprotocol](../../concepts/0003-protocols/README.md#composable)).

The `choice-id` field formally names a choice that a superprotocol has defined, and tells how the string values of the `caller-wins` and `flipper-wins` fields will be interpreted. In the example above, the choice is defined in the [Tic-Tac-Toe Protocol](../../concepts/0003-protocols/tictactoe/README.md#key-concepts), which also specifies that `caller-wins` and `flipper-wins` will contain DIDs of the parties playing the game. Some other combinations that might make sense include:
The `choice-id` field formally names a choice that a superprotocol has defined, and tells how the string values of the `caller-wins` and `recorder-wins` fields will be interpreted. In the example above, the choice is defined in the [Tic-Tac-Toe Protocol](../../concepts/0003-protocols/tictactoe/README.md#key-concepts), which also specifies that `caller-wins` and `recorder-wins` will contain DIDs of the parties playing the game. Some other combinations that might make sense include:

* In an auction protocol that uses a coin flip to break a tie between two bids of equal value, `choice-id` might be a string like `prefix/myauctionproto/1.0/bid-tie-break`, and the values of the `*-wins` fields might be the `id` properties of specific bid messages.

Expand All @@ -102,13 +102,13 @@ The [`~timing.expires_time` decorator](../0032-message-timing/README.md#tutorial

#### `flip`

This message is sent from Flipper to Caller. It embodies Step 2-5 of [the algorithm](#algorithm). It looks like this:
This message is sent from Recorder to Caller. It embodies Step 2-5 of [the algorithm](#algorithm). It looks like this:

```jsonc
{
"@type": "https://github.com/hyperledger/aries-rfcs/features/0193-coin-flip/1.0/flip",
"@id": "7a86e002-8dee-b3d5-456e-8fe47247518b",
"flip-string-hash": "B78DC2D94F6E92B69491F13DC8C866C0A31F896069D3DD69472D0D7740967011",
"commitment": "B78DC2D94F6E92B69491F13DC8C866C0A31F896069D3DD69472D0D7740967011",
"comment": "Here you go. Do you pick heads or tails?",
"~thread": {
"thid": "518be002-de8e-456e-b3d5-8fe472477a86",
Expand All @@ -123,7 +123,7 @@ The [`~timing.expires_time` decorator](../0032-message-timing/README.md#tutorial

#### `call`

This message is sent from Caller to Flipper, and embodies Step 6 of [the algorithm](#algorithm). It looks like this:
This message is sent from Caller to Recorder, and embodies Step 6 of [the algorithm](#algorithm). It looks like this:

```jsonc
{
Expand All @@ -144,7 +144,7 @@ The [`~timing.expires_time` decorator](../0032-message-timing/README.md#tutorial

#### `reveal`

This message is sent from Flipper to Caller, and embodies Step 7 of [the algorithm](#algorithm). It looks like this:
This message is sent from Recorder to Caller, and embodies Step 7 of [the algorithm](#algorithm). It looks like this:

```jsonc
{
Expand All @@ -161,13 +161,15 @@ This message is sent from Flipper to Caller, and embodies Step 7 of [the algorit
}
```

Note the use of `~thread.thid` and `sender_order: 1` to connect this `reveal` to the preceding `call`.

The Caller should validate this message as follows:

* Confirm that `flip_string` is a correctly formatted string consisting of 3 fields with no leading or trailing spaces, having exactly 1 space delimiter between each field, where the first field is the case-sensitive value "heads" or "tails", and the other two fields are correctly formatted UUIDs. This check is important because it eliminates the possibility that the Flipper could introduce variation to the commitment.
* Confirm that `flip_string` is a correctly formatted string consisting of 3 fields with no leading or trailing spaces, having exactly 1 space delimiter between each field, where the first field is the case-sensitive value "heads" or "tails", and the other two fields are correctly formatted UUIDs. This check is important because it eliminates the possibility that the Recorder could introduce variation to the commitment.
* Confirm that the third field in `flip_string` equals `caller-uuid` from the `propose` message.
* Confirm that `flip_string_hash` from the preceding `flip` equals the SHA256 hash of `flip_string`.

Having validated the message thus far, Caller determines the winner by checking to see if the value of the first field in `flip_string` equals the value of `called` from the preceding `call` message. If yes, then the value of the `winner` field must be `caller`; if no, then it must be `flipper`. The `winner` field must be present in the message, and its value must be correct, for the `reveal` message to be deemed fully valid. This confirms that both parties understand the outcome, and it prevents a Flipper from asserting a false outcome that is accepted by careless validation logic on the Caller side.
Having validated the message thus far, Caller determines the winner by checking to see if the value of the first field in `flip_string` equals the value of `called` from the preceding `call` message. If yes, then the value of the `winner` field must be `caller`; if no, then it must be `recorder`. The `winner` field must be present in the message, and its value must be correct, for the `reveal` message to be deemed fully valid. This confirms that both parties understand the outcome, and it prevents a Recorder from asserting a false outcome that is accepted by careless validation logic on the Caller side.

The [`~please_ack` decorator](../0015-acks/README.md#requesting-an-ack-please_ack) is optional. If a superprotocol specifies the next step after a Coin Flip with sufficient precision, it may be unnecessary. However, it should be supported by implementations. The resulting `ack` message, if sent, is hereby [adopted into the Coin Flip protocol](../0015-acks/README.md#adopting-acks).

Expand All @@ -187,7 +189,7 @@ As mentioned in the introduction, the algorithm used in this protocol is a simpl

## Unresolved questions

- Do we need to use hashlink so we can move to a new hash algorithm if SHA256 is every broken?
- Do we need to use hashlink so we can move to a new hash algorithm if SHA256 is ever broken?

## Implementations

Expand Down

0 comments on commit cec53ce

Please sign in to comment.