Browse Source

feat(entropy): Minor items to prep for testnet deployments (#2673)

* rename stuff

* fix test
Jayant Krishnamurthy 6 months ago
parent
commit
f9f8dd9db6

+ 55 - 61
target_chains/ethereum/contracts/contracts/entropy/Entropy.sol

@@ -16,14 +16,16 @@ import "./EntropyStructConverter.sol";
 // Entropy 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 draw a random number x_{A,B}
-// 2. A and B then share h_{A,B} = hash(x_{A,B})
-// 3. A and B reveal x_{A,B}
-// 4. Both parties verify that hash(x_{A, B}) == h_{A,B}
-// 5. The random number r = hash(x_A, x_B)
+// 1. Two parties A and B each randomly sample a contribution x_{A,B} to the random number
+// 2. A commits to their number by sharing h_A = hash(x_A)
+// 3. B reveals x_B
+// 4. A reveals x_A
+// 5. B verifies that hash(x_{A}) == h_A
+// 6. The random number r = 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
+// Honesty means that (1) they draw their value at random, and (2) for A, they keep x_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 r is random.
 //
 // Entropy implements a version of this protocol that is optimized for on-chain usage. The
@@ -37,26 +39,19 @@ import "./EntropyStructConverter.sol";
 // verified against the previous one in the sequence by hashing it, i.e., hash(x_i) == x_{i - 1}
 //
 // Request: To produce a random number, the following steps occur.
-// 1. The user draws a random number x_U, and submits h_U = hash(x_U) to this contract
-// 2. The contract remembers h_U and assigns it an incrementing sequence number i, representing which
+// 1. The user randomly samples their contribution x_U and submits it to the contract
+// 2. The contract remembers x_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
-//    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.
+// 3. The provider submits a transaction to the contract revealing their contribution x_i to the contract.
+// 4. The contract verifies hash(x_i) == x_{i-1} to prove that x_i is the i'th random number.
 //    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).
-//    (Optional) as an added security mechanism, this step can further incorporate the blockhash of the block that the
-//    request transaction landed in: r = hash(x_i, x_U, blockhash).
+// 5. If the condition above is satisfied, the random number r = hash(x_i, x_U).
+// 6. The contract submits a callback to the calling contract with the random number `r`.
 //
 // 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
-// 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.
+// the provider or user is honest, the number r is random. Note that this analysis assumes that
+// providers cannot frontrun user transactions -- a dishonest provider who frontruns user transaction can
+// manipulate the result.
 //
 // The Entropy implementation of the above protocol allows anyone to permissionlessly register to be a
 // randomness provider. Users then choose which provider to request randomness from. Each provider can set
@@ -71,13 +66,6 @@ import "./EntropyStructConverter.sol";
 // a compromised sequence. On rotation, any in-flight requests continue to use the pre-rotation commitment.
 // Providers can use the sequence number of the request along with the event log of their registrations to determine
 // which hash chain contains the requested random number.
-//
-// Warning to integrators:
-// An important caveat of this protocol is that the user can compute the random number r before
-// revealing their own number to the contract. This property means that the user can choose to halt the
-// protocol prior to the random number being revealed (i.e., prior to step (6) above). Integrators should ensure that
-// the user is always incentivized to reveal their random number, and that the protocol has an escape hatch for
-// cases where the user chooses not to reveal.
 abstract contract Entropy is IEntropy, EntropyState {
     using ExcessivelySafeCall for address;
 
@@ -357,24 +345,24 @@ abstract contract Entropy is IEntropy, EntropyState {
     // Note that excess value is *not* refunded to the caller.
     function requestWithCallback(
         address provider,
-        bytes32 userRandomNumber
+        bytes32 userContribution
     ) public payable override returns (uint64) {
         return
             requestV2(
                 provider,
-                userRandomNumber,
+                userContribution,
                 0 // Passing 0 will assign the request the provider's default gas limit
             );
     }
 
     function requestV2(
         address provider,
-        bytes32 userRandomNumber,
+        bytes32 userContribution,
         uint32 gasLimit
     ) public payable override returns (uint64) {
         EntropyStructsV2.Request storage req = requestHelper(
             provider,
-            constructUserCommitment(userRandomNumber),
+            constructUserCommitment(userContribution),
             // If useBlockHash is set to true, it allows a scenario in which the provider and miner can collude.
             // If we remove the blockHash from this, the provider would have no choice but to provide its committed
             // random number. Hence, useBlockHash is set to false.
@@ -387,14 +375,14 @@ abstract contract Entropy is IEntropy, EntropyState {
             provider,
             req.requester,
             req.sequenceNumber,
-            userRandomNumber,
+            userContribution,
             EntropyStructConverter.toV1Request(req)
         );
         emit EntropyEventsV2.Requested(
             provider,
             req.requester,
             req.sequenceNumber,
-            userRandomNumber,
+            userContribution,
             uint32(req.gasLimit10k) * TEN_THOUSAND,
             bytes("")
         );
@@ -406,14 +394,14 @@ abstract contract Entropy is IEntropy, EntropyState {
     // current commitment and returns the generated random number.
     function revealHelper(
         EntropyStructsV2.Request storage req,
-        bytes32 userRevelation,
-        bytes32 providerRevelation
+        bytes32 userContribution,
+        bytes32 providerContribution
     ) internal returns (bytes32 randomNumber, bytes32 blockHash) {
         bytes32 providerCommitment = constructProviderCommitment(
             req.numHashes,
-            providerRevelation
+            providerContribution
         );
-        bytes32 userCommitment = constructUserCommitment(userRevelation);
+        bytes32 userCommitment = constructUserCommitment(userContribution);
         if (
             keccak256(bytes.concat(userCommitment, providerCommitment)) !=
             req.commitment
@@ -436,8 +424,8 @@ abstract contract Entropy is IEntropy, EntropyState {
         }
 
         randomNumber = combineRandomValues(
-            userRevelation,
-            providerRevelation,
+            userContribution,
+            providerContribution,
             blockHash
         );
 
@@ -446,7 +434,7 @@ abstract contract Entropy is IEntropy, EntropyState {
         ];
         if (providerInfo.currentCommitmentSequenceNumber < req.sequenceNumber) {
             providerInfo.currentCommitmentSequenceNumber = req.sequenceNumber;
-            providerInfo.currentCommitment = providerRevelation;
+            providerInfo.currentCommitment = providerContribution;
         }
     }
 
@@ -455,7 +443,7 @@ abstract contract Entropy is IEntropy, EntropyState {
     function advanceProviderCommitment(
         address provider,
         uint64 advancedSequenceNumber,
-        bytes32 providerRevelation
+        bytes32 providerContribution
     ) public override {
         EntropyStructsV2.ProviderInfo storage providerInfo = _state.providers[
             provider
@@ -473,14 +461,14 @@ abstract contract Entropy is IEntropy, EntropyState {
         );
         bytes32 providerCommitment = constructProviderCommitment(
             numHashes,
-            providerRevelation
+            providerContribution
         );
 
         if (providerCommitment != providerInfo.currentCommitment)
             revert EntropyErrors.IncorrectRevelation();
 
         providerInfo.currentCommitmentSequenceNumber = advancedSequenceNumber;
-        providerInfo.currentCommitment = providerRevelation;
+        providerInfo.currentCommitment = providerContribution;
         if (
             providerInfo.currentCommitmentSequenceNumber >=
             providerInfo.sequenceNumber
@@ -508,8 +496,8 @@ abstract contract Entropy is IEntropy, EntropyState {
     function reveal(
         address provider,
         uint64 sequenceNumber,
-        bytes32 userRevelation,
-        bytes32 providerRevelation
+        bytes32 userContribution,
+        bytes32 providerContribution
     ) public override returns (bytes32 randomNumber) {
         EntropyStructsV2.Request storage req = findActiveRequest(
             provider,
@@ -528,13 +516,13 @@ abstract contract Entropy is IEntropy, EntropyState {
         bytes32 blockHash;
         (randomNumber, blockHash) = revealHelper(
             req,
-            userRevelation,
-            providerRevelation
+            userContribution,
+            providerContribution
         );
         emit Revealed(
             EntropyStructConverter.toV1Request(req),
-            userRevelation,
-            providerRevelation,
+            userContribution,
+            providerContribution,
             blockHash,
             randomNumber
         );
@@ -554,8 +542,8 @@ abstract contract Entropy is IEntropy, EntropyState {
     function revealWithCallback(
         address provider,
         uint64 sequenceNumber,
-        bytes32 userRandomNumber,
-        bytes32 providerRevelation
+        bytes32 userContribution,
+        bytes32 providerContribution
     ) public override {
         EntropyStructsV2.Request storage req = findActiveRequest(
             provider,
@@ -573,8 +561,8 @@ abstract contract Entropy is IEntropy, EntropyState {
         bytes32 randomNumber;
         (randomNumber, ) = revealHelper(
             req,
-            userRandomNumber,
-            providerRevelation
+            userContribution,
+            providerContribution
         );
 
         // If the request has an explicit gas limit, then run the new callback failure state flow.
@@ -613,8 +601,8 @@ abstract contract Entropy is IEntropy, EntropyState {
             if (success) {
                 emit RevealedWithCallback(
                     EntropyStructConverter.toV1Request(req),
-                    userRandomNumber,
-                    providerRevelation,
+                    userContribution,
+                    providerContribution,
                     randomNumber
                 );
                 emit EntropyEventsV2.Revealed(
@@ -622,6 +610,8 @@ abstract contract Entropy is IEntropy, EntropyState {
                     req.requester,
                     req.sequenceNumber,
                     randomNumber,
+                    userContribution,
+                    providerContribution,
                     false,
                     ret,
                     SafeCast.toUint32(gasUsed),
@@ -642,8 +632,8 @@ abstract contract Entropy is IEntropy, EntropyState {
                     provider,
                     req.requester,
                     sequenceNumber,
-                    userRandomNumber,
-                    providerRevelation,
+                    userContribution,
+                    providerContribution,
                     randomNumber,
                     ret
                 );
@@ -652,6 +642,8 @@ abstract contract Entropy is IEntropy, EntropyState {
                     req.requester,
                     sequenceNumber,
                     randomNumber,
+                    userContribution,
+                    providerContribution,
                     true,
                     ret,
                     SafeCast.toUint32(gasUsed),
@@ -692,8 +684,8 @@ abstract contract Entropy is IEntropy, EntropyState {
 
             emit RevealedWithCallback(
                 reqV1,
-                userRandomNumber,
-                providerRevelation,
+                userContribution,
+                providerContribution,
                 randomNumber
             );
             emit EntropyEventsV2.Revealed(
@@ -701,6 +693,8 @@ abstract contract Entropy is IEntropy, EntropyState {
                 callAddress,
                 sequenceNumber,
                 randomNumber,
+                userContribution,
+                providerContribution,
                 false,
                 bytes(""),
                 gasUsed,

+ 81 - 98
target_chains/ethereum/contracts/forge-test/Entropy.t.sol

@@ -888,6 +888,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             false,
             bytes(""),
             0,
@@ -956,6 +958,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             false,
             bytes(""),
             0,
@@ -1063,6 +1067,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             false,
             bytes(""),
             0,
@@ -1136,6 +1142,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             true,
             revertReason,
             0,
@@ -1202,6 +1210,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             false,
             bytes(""),
             0,
@@ -1283,6 +1293,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             true,
             "",
             0,
@@ -1348,6 +1360,8 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
                 provider1Proofs[assignedSequenceNumber],
                 0
             ),
+            userRandomNumber,
+            provider1Proofs[assignedSequenceNumber],
             false,
             "",
             0,
@@ -1822,57 +1836,14 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
 
             assertEq(entries.length, 2);
             // first entry is CallbackFailed which we aren't going to check.
-            // Unfortunately event.selector was added in Solidity 0.8.15 and we're on 0.8.4 so we have to copy this spec here.
-            assertEq(
-                entries[1].topics[0],
-                keccak256(
-                    "Revealed(address,address,uint64,bytes32,bool,bytes,uint32,bytes)"
-                )
-            );
-            // Verify the topics match the expected values
-            assertEq(
-                entries[1].topics[1],
-                bytes32(uint256(uint160(provider1)))
-            );
-            assertEq(
-                entries[1].topics[2],
-                bytes32(uint256(uint160(address(consumer))))
-            );
-            assertEq(entries[1].topics[3], bytes32(uint256(sequenceNumber)));
-
-            // Verify the data field contains the expected values (per event ABI)
-            (
-                bytes32 randomNumber,
-                bool callbackFailed,
-                bytes memory callbackErrorCode,
-                uint32 callbackGasUsed,
-                bytes memory extraArgs
-            ) = abi.decode(
-                    entries[1].data,
-                    (bytes32, bool, bytes, uint32, bytes)
-                );
-
-            assertEq(
-                randomNumber,
-                random.combineRandomValues(
-                    userRandomNumber,
-                    provider1Proofs[sequenceNumber],
-                    0
-                )
-            );
-            assertEq(callbackFailed, true);
-            assertEq(callbackErrorCode, bytes(""));
-
-            // callback gas usage is approximate
-            assertTrue(
-                random.getProviderInfoV2(provider1).defaultGasLimit == 0 ||
-                    ((callbackGasUsage * 90) / 100 < callbackGasUsed)
-            );
-            assertTrue(
-                random.getProviderInfoV2(provider1).defaultGasLimit == 0 ||
-                    (callbackGasUsed < (callbackGasUsage * 110) / 100)
+            assertRevealedEvent(
+                entries[1],
+                address(consumer),
+                sequenceNumber,
+                userRandomNumber,
+                true,
+                callbackGasUsage
             );
-            assertEq(extraArgs, bytes(""));
 
             // Verify request is still active after failure
             EntropyStructsV2.Request memory reqAfterFailure = random
@@ -1894,55 +1865,14 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
             Vm.Log[] memory entries = vm.getRecordedLogs();
 
             assertEq(entries.length, 2);
-            // first entry is CallbackFailed which we aren't going to check.
-            // Unfortunately event.selector was added in Solidity 0.8.15 and we're on 0.8.4 so we have to copy this spec here.
-            assertEq(
-                entries[1].topics[0],
-                keccak256(
-                    "Revealed(address,address,uint64,bytes32,bool,bytes,uint32,bytes)"
-                )
-            );
-
-            // Verify the topics match the expected values
-            assertEq(
-                entries[1].topics[1],
-                bytes32(uint256(uint160(provider1)))
-            );
-            assertEq(
-                entries[1].topics[2],
-                bytes32(uint256(uint160(req.requester)))
-            );
-            assertEq(
-                entries[1].topics[3],
-                bytes32(uint256(req.sequenceNumber))
-            );
-
-            // Verify the data field contains the expected values (per event ABI)
-            (
-                bytes32 randomNumber,
-                bool callbackFailed,
-                bytes memory callbackErrorCode,
-                uint32 callbackGasUsed,
-                bytes memory extraArgs
-            ) = abi.decode(
-                    entries[1].data,
-                    (bytes32, bool, bytes, uint32, bytes)
-                );
-
-            assertEq(
-                randomNumber,
-                random.combineRandomValues(
-                    userRandomNumber,
-                    provider1Proofs[sequenceNumber],
-                    0
-                )
+            assertRevealedEvent(
+                entries[1],
+                req.requester,
+                req.sequenceNumber,
+                userRandomNumber,
+                false,
+                callbackGasUsage
             );
-            assertEq(callbackFailed, false);
-            assertEq(callbackErrorCode, bytes(""));
-            // callback gas usage is approximate
-            assertTrue((callbackGasUsage * 90) / 100 < callbackGasUsed);
-            assertTrue(callbackGasUsed < (callbackGasUsage * 110) / 100);
-            assertEq(extraArgs, bytes(""));
 
             // Verify request is cleared after successful callback
             EntropyStructsV2.Request memory reqAfterSuccess = random
@@ -1950,6 +1880,59 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents, EntropyEventsV2 {
             assertEq(reqAfterSuccess.sequenceNumber, 0);
         }
     }
+
+    // Helper method to check the Revealed event
+    function assertRevealedEvent(
+        Vm.Log memory entry,
+        address expectedRequester,
+        uint64 expectedSequenceNumber,
+        bytes32 expectedUserContribution,
+        bool expectedCallbackFailed,
+        uint32 expectedCallbackGasUsage
+    ) internal {
+        // Check event topic
+        assertEq(
+            entry.topics[0],
+            keccak256(
+                "Revealed(address,address,uint64,bytes32,bytes32,bytes32,bool,bytes,uint32,bytes)"
+            )
+        );
+
+        // Check event topics
+        assertEq(entry.topics[1], bytes32(uint256(uint160(provider1))));
+        assertEq(entry.topics[2], bytes32(uint256(uint160(expectedRequester))));
+        assertEq(entry.topics[3], bytes32(uint256(expectedSequenceNumber)));
+
+        bytes32 expectedRandomNumber = random.combineRandomValues(
+            expectedUserContribution,
+            provider1Proofs[expectedSequenceNumber],
+            0
+        );
+
+        // Decode and check event data
+        (
+            bytes32 randomNumber,
+            bytes32 userContribution,
+            bytes32 providerContribution,
+            bool callbackFailed,
+            bytes memory callbackErrorCode,
+            uint32 callbackGasUsed,
+            bytes memory extraArgs
+        ) = abi.decode(
+                entry.data,
+                (bytes32, bytes32, bytes32, bool, bytes, uint32, bytes)
+            );
+
+        assertEq(randomNumber, expectedRandomNumber);
+        assertEq(userContribution, expectedUserContribution);
+        assertEq(providerContribution, provider1Proofs[expectedSequenceNumber]);
+        assertEq(callbackFailed, expectedCallbackFailed);
+        assertEq(callbackErrorCode, bytes(""));
+        // callback gas usage is approximate
+        assertTrue((expectedCallbackGasUsage * 90) / 100 < callbackGasUsed);
+        assertTrue(callbackGasUsed < (expectedCallbackGasUsage * 110) / 100);
+        assertEq(extraArgs, bytes(""));
+    }
 }
 
 contract EntropyConsumer is IEntropyConsumer {

+ 6 - 2
target_chains/ethereum/entropy_sdk/solidity/EntropyEventsV2.sol

@@ -23,7 +23,7 @@ interface EntropyEventsV2 {
      * @param provider The address of the provider handling the request
      * @param caller The address of the user requesting the random number
      * @param sequenceNumber A unique identifier for this request
-     * @param userRandomNumber A random number provided by the user for additional entropy
+     * @param userContribution The user's contribution to the random number
      * @param gasLimit The gas limit for the callback.
      * @param extraArgs A field for extra data for forward compatibility.
      */
@@ -31,7 +31,7 @@ interface EntropyEventsV2 {
         address indexed provider,
         address indexed caller,
         uint64 indexed sequenceNumber,
-        bytes32 userRandomNumber,
+        bytes32 userContribution,
         uint32 gasLimit,
         bytes extraArgs
     );
@@ -42,6 +42,8 @@ interface EntropyEventsV2 {
      * @param caller The address of the user who requested the random number (and who receives a callback)
      * @param sequenceNumber The unique identifier of the request
      * @param randomNumber The generated random number
+     * @param userContribution The user's contribution to the random number
+     * @param providerContribution The provider's contribution to the random number
      * @param callbackFailed Whether the callback to the caller failed
      * @param callbackReturnValue Return value from the callback. If the callback failed, this field contains
      * the error code and any additional returned data. Note that "" often indicates an out-of-gas error.
@@ -54,6 +56,8 @@ interface EntropyEventsV2 {
         address indexed caller,
         uint64 indexed sequenceNumber,
         bytes32 randomNumber,
+        bytes32 userContribution,
+        bytes32 providerContribution,
         bool callbackFailed,
         bytes callbackReturnValue,
         uint32 callbackGasUsed,

+ 12 - 6
target_chains/ethereum/entropy_sdk/solidity/IEntropyV2.sol

@@ -20,8 +20,10 @@ interface IEntropyV2 is EntropyEventsV2 {
     /// Note that the fee can change over time. Callers of this method should explicitly compute `getFeeV2()`
     /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
     ///
-    /// Note that this method uses an in-contract PRNG to generate the user's portion of the random number.
-    /// Users must trust this PRNG in order to prove the result is random. If you wish to avoid this trust assumption,
+    /// Note that this method uses an in-contract PRNG to generate the user's contribution to the random number.
+    /// This approach modifies the security guarantees such that a dishonest validator and provider can
+    /// collude to manipulate the result (as opposed to a malicious user and provider). That is, the user
+    /// now trusts the validator honestly draw a random number. If you wish to avoid this trust assumption,
     /// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
     function requestV2()
         external
@@ -43,8 +45,10 @@ interface IEntropyV2 is EntropyEventsV2 {
     /// Note that the fee can change over time. Callers of this method should explicitly compute `getFeeV2(gasLimit)`
     /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
     ///
-    /// Note that this method uses an in-contract PRNG to generate the user's portion of the random number.
-    /// Users must trust this PRNG in order to prove the result is random. If you wish to avoid this trust assumption,
+    /// Note that this method uses an in-contract PRNG to generate the user's contribution to the random number.
+    /// This approach modifies the security guarantees such that a dishonest validator and provider can
+    /// collude to manipulate the result (as opposed to a malicious user and provider). That is, the user
+    /// now trusts the validator honestly draw a random number. If you wish to avoid this trust assumption,
     /// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
     function requestV2(
         uint32 gasLimit
@@ -66,8 +70,10 @@ interface IEntropyV2 is EntropyEventsV2 {
     /// Note that provider fees can change over time. Callers of this method should explicitly compute `getFeeV2(provider, gasLimit)`
     /// prior to each invocation (as opposed to hardcoding a value). Further note that excess value is *not* refunded to the caller.
     ///
-    /// Note that this method uses an in-contract PRNG to generate the user's portion of the random number.
-    /// Users must trust this PRNG in order to prove the result is random. If you wish to avoid this trust assumption,
+    /// Note that this method uses an in-contract PRNG to generate the user's contribution to the random number.
+    /// This approach modifies the security guarantees such that a dishonest validator and provider can
+    /// collude to manipulate the result (as opposed to a malicious user and provider). That is, the user
+    /// now trusts the validator honestly draw a random number. If you wish to avoid this trust assumption,
     /// call a variant of `requestV2` that accepts a `userRandomNumber` parameter.
     function requestV2(
         address provider,

+ 13 - 1
target_chains/ethereum/entropy_sdk/solidity/abis/EntropyEventsV2.json

@@ -197,7 +197,7 @@
       {
         "indexed": false,
         "internalType": "bytes32",
-        "name": "userRandomNumber",
+        "name": "userContribution",
         "type": "bytes32"
       },
       {
@@ -243,6 +243,18 @@
         "name": "randomNumber",
         "type": "bytes32"
       },
+      {
+        "indexed": false,
+        "internalType": "bytes32",
+        "name": "userContribution",
+        "type": "bytes32"
+      },
+      {
+        "indexed": false,
+        "internalType": "bytes32",
+        "name": "providerContribution",
+        "type": "bytes32"
+      },
       {
         "indexed": false,
         "internalType": "bool",

+ 13 - 1
target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json

@@ -501,7 +501,7 @@
       {
         "indexed": false,
         "internalType": "bytes32",
-        "name": "userRandomNumber",
+        "name": "userContribution",
         "type": "bytes32"
       },
       {
@@ -705,6 +705,18 @@
         "name": "randomNumber",
         "type": "bytes32"
       },
+      {
+        "indexed": false,
+        "internalType": "bytes32",
+        "name": "userContribution",
+        "type": "bytes32"
+      },
+      {
+        "indexed": false,
+        "internalType": "bytes32",
+        "name": "providerContribution",
+        "type": "bytes32"
+      },
       {
         "indexed": false,
         "internalType": "bool",

+ 13 - 1
target_chains/ethereum/entropy_sdk/solidity/abis/IEntropyV2.json

@@ -197,7 +197,7 @@
       {
         "indexed": false,
         "internalType": "bytes32",
-        "name": "userRandomNumber",
+        "name": "userContribution",
         "type": "bytes32"
       },
       {
@@ -243,6 +243,18 @@
         "name": "randomNumber",
         "type": "bytes32"
       },
+      {
+        "indexed": false,
+        "internalType": "bytes32",
+        "name": "userContribution",
+        "type": "bytes32"
+      },
+      {
+        "indexed": false,
+        "internalType": "bytes32",
+        "name": "providerContribution",
+        "type": "bytes32"
+      },
       {
         "indexed": false,
         "internalType": "bool",