Skip to content

feat(entropy): add protocol explanation for callbacks + latex formulas #410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const withNextra = require("nextra")({
}),
},
},
latex: true,
});

// Use this array as a shorter way to specify redirect URLs so we can write down a lot of them.
Expand Down
62 changes: 38 additions & 24 deletions pages/entropy/protocol-design.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,61 @@
The Entropy protocol is an extension of a classical commit/reveal protocol.
The original version has the following steps:

1. Two parties A and B each draw secret random numbers, `x_A` and `x_B`.
2. A and B hash their random numbers and share the hashes, `h_A = hash(x_A)` and `h_B = hash(x_B)`
3. A and B reveal `x_A` and `x_B`
4. Both parties verify that `hash(x_A) == h_A` and `hash(x_B) == h_B`
5. The random number `r = hash(x_A, x_B)`
1. Two parties A and B each draw secret random numbers, $x_A$ and $x_B$.
2. A and B hash their random numbers and share the hashes, $h_A = \mathrm{hash}(x_A)$ and $h_B = \mathrm{hash}(x_B)$
3. A and B reveal $x_A$ and $x_B$
4. Both parties verify that $\mathrm{hash}(x_A) = h_A$ and $\mathrm{hash}(x_B) = h_B$
5. The random number $r = \mathrm{hash}(x_A, x_B)$

This protocol has the property that the result is random as long as either A or B are honest.
Thus, neither party needs to trust the other -- as long as they are themselves honest, they can
ensure that the result `r` is random.
ensure that the result $r$ is random.

Entropy implements a version of this protocol that is optimized for on-chain usage. The
key difference is that one of the participants (the provider) commits to a sequence of random numbers
up-front using a hash chain. Users of the protocol then simply grab the next random number in the sequence.

**Setup**: The provider P computes a sequence of `N` random numbers, `x_i` for `(i = 0...N-1)`:
**Setup**: The provider P computes a sequence of $N$ random numbers, $x_i$ for $0 \leq i \leq N-1$:

- `x_{N-1} = random()`
- `x_i = hash(x_{i + 1})`
- $x_{N-1} = \mathrm{random}()$
- $x_i = \mathrm{hash}(x_{i + 1})$

The provider commits to `x_0` by posting it to the Entropy contract.
Each random number in the sequence can then be verified against the previous one in the sequence by hashing it, i.e., `hash(x_i) == x_{i - 1}`
The provider commits to $x_0$ by posting it to the Entropy contract.
Each random number in the sequence can then be verified against the previous one in the sequence by hashing it, i.e., $\mathrm{hash}(x_i) = x_{i - 1}$

**Request**: To produce a random number, the following steps occur.

1. The user U draws a random number `x_U`, and submits `h_U = hash(x_U)` to the contract
2. The contract remembers `h_U` and assigns it an incrementing sequence number `i`, representing which
1. The user U draws a random number $x_U$, and submits $h_U = \mathrm{hash}(x_U)$ to the contract
2. The contract remembers $h_U$ and assigns it an incrementing sequence number $i$, representing which
of the provider's random numbers the user will receive.
3. The user submits an off-chain request (e.g. via HTTP) to the provider to reveal the `i`'th random number.
4. The provider checks the on-chain sequence number and ensures it is > `i`. If it is not, the provider
3. The user submits an off-chain request (e.g. via HTTP) to the provider to reveal the $i$'th random number.
4. The provider checks the on-chain sequence number and ensures it is > $i$. If it is not, the provider
refuses to reveal the ith random number. The provider should wait for a sufficient number of block confirmations
to ensure that the request does not get re-orged out of the blockchain.
5. The provider reveals `x_i` to the user.
6. The user submits both the provider's revealed number `x_i` and their own `x_U` to the contract.
7. The contract verifies `hash(x_i) == x_{i-1}` to prove that `x_i` is the `i`'th random number. The contract also checks that `hash(x_U) == h_U`.
The contract stores `x_i` as the `i`'th random number to reuse for future verifications.
8. If both of the above conditions are satisfied, the random number `r = hash(x_i, x_U)`.
5. The provider reveals $x_i$ to the user.
6. The user submits both the provider's revealed number $x_i$ and their own $x_U$ to the contract.
7. The contract verifies $\mathrm{hash}(x_i) = x_{i-1}$ to prove that $x_i$ is the $i$'th random number. The contract also checks that $\mathrm{hash}(x_U) = h_U$.
The contract stores $x_i$ as the $i$'th random number to reuse for future verifications.
8. If both of the above conditions are satisfied, the random number $r = \mathrm{hash}(x_i, x_U)$.
As an added security mechanism, this step can incorporate the blockhash of the block that the
request transaction landed in: `r = hash(x_i, x_U, blockhash)`.
request transaction landed in: $r = \mathrm{hash}(x_i, x_U, \mathrm{blockhash})$.

This protocol has the same security properties as the 2-party randomness protocol above: as long as either
the provider or user is honest, the number `r` is random. Honesty here means that the participant keeps their
random number `x` a secret until the revelation phase (step 5) of the protocol. Note that providers need to
the provider or user is honest, the number $r$ is random. Honesty here means that the participant keeps their
random number $x$ a secret until the revelation phase (step 5) of the protocol. Note that providers need to
be careful to ensure their off-chain service isn't compromised to reveal the random numbers -- if this occurs,
then users will be able to influence the random number `r`.
then users will be able to influence the random number $r$.

With automatic callbacks the flow is simplified:

1. The user U draws a random number $x_U$, and submits **both** $x_U$ and $h_U = \mathrm{hash}(x_U)$ to the contract
2. The contract remembers $h_U$ and assigns it an incrementing sequence number $i$, representing which
of the provider's random numbers the user will receive. $x_U$ is recorded in the event logs.
3. After sufficient block confirmations, the provider submits a reveal transaction with $x_i$ and $x_U$ to the contract.
4. The contract verifies $\mathrm{hash}(x_U) = h_U$ and $\mathrm{hash}(x_i) = x_{i-1}$ to prove that $x_i$ is the $i$'th random number.
5. If both of the above conditions are satisfied,
the random number $r = \mathrm{hash}(x_i, x_U)$ is generated and a callback is made to the requesting contract.

In this flow, providers can refuse revealing $x_i$ if the final random number $r$ is not in their favor, or
they may be able to access $x_U$ before on-chain submission (e.g. via mempool) and rotate their commitments to influence the random number $r$.
Of course, both of these behaviors are detectable and protocols can blacklist providers that exhibit them.
Loading