Entropy
Protocol Design

Protocol Design

The Entropy protocol implements a secure 2-party random number generation procedure. The protocol is an extension of a simple commit/reveal protocol. The original version has the following steps:

  1. Two parties A and B each randomly sample secret contributions to the random number, xAx_A and xBx_B.
  2. A commits to their number by sharing hA=hash(xA)h_A = \mathrm{hash}(x_A)
  3. B reveals xBx_B
  4. A reveals xAx_A
  5. B verifies that hash(xA)==hA\mathrm{hash}(x_{A}) == h_A
  6. The random number r=hash(xA,xB)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. Honesty means that (1) they draw their value at random, and (2) for A, they keep xAx_A a secret until step 4. Thus, neither party needs to trust the other -- as long as they are themselves honest, they can ensure that the result rr 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 NN random numbers, xix_i for 0iN10 \leq i \leq N-1:

  • xN1=random()x_{N-1} = \mathrm{random}()
  • xi=hash(xi+1)x_i = \mathrm{hash}(x_{i + 1})

The provider commits to x0x_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(xi)=xi1\mathrm{hash}(x_i) = x_{i - 1}

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

  1. The user randomly samples their contribution xUx_U and submits it to the contract. (Users may also run this step using an on-chain PRNG if they trust the validator to not collude with the provider.)
  2. The contract remembers xUx_U and assigns it an incrementing sequence number ii, representing which of the provider's random numbers the user will receive.
  3. After sufficient block confirmations, the provider submits a transaction to the contract revealing their contribution xix_i to the contract.
  4. The contract verifies hash(xi)==xi1\mathrm{hash}(x_i) == x_{i-1} to prove that xix_i is the ii'th random number. The contract stores x_i as the i'th random number to reuse for future verifications.
  5. If the condition above is satisfied, the random number r=hash(xi,xU)r = \mathrm{hash}(x_i, x_U).
  6. The contract submits a callback to the calling contract with the random number rr.

This flow is secure as long as several trust assumptions hold:

  • Providers are trusted to reveal their random number xix_i regardless of what the final result rr is. Providers can compute rr off-chain before they reveal xix_i, which permits a censorship attack.
  • Providers are trusted not to front-run user transactions (via the mempool or colluding with the validator). Providers who observe user transactions can manipulate the result by inserting additional reuests or rotating their commitment.
  • Providers are trusted not to keep their hash chain a secret. Anyone with the hash chain can predict the result of a randomness request before it is requested, and therefore manipulate the result. This applies both to users of the protocol as well as blockchain validators who can use this information to manipulate the on-chain PRNG or reorder user transactions.

The code of default deployed provider can be found here (opens in a new tab).

Last updated on