diff --git a/next.config.js b/next.config.js index edd244eb..9da0c1ab 100644 --- a/next.config.js +++ b/next.config.js @@ -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. diff --git a/pages/entropy/protocol-design.mdx b/pages/entropy/protocol-design.mdx index 11530d27..e6d488ec 100644 --- a/pages/entropy/protocol-design.mdx +++ b/pages/entropy/protocol-design.mdx @@ -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.