Abstract

A simple commit interface to support commit-reveal scheme which provides only a commit method but no reveal method, allowing implementations to integrate this interface with arbitrary reveal methods such as vote or transfer.

Motivation

  1. support commit-reveal privacy for applications such as voting.
  2. make it harder for attackers for front-running, back-running or sandwich attacks.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Interfaces referenced in this specification are as follows:

pragma solidity >=0.7.0 <0.9.0;

// The EIP-165 identifier of this interface is 0xf14fcbc8
interface IERC_COMMIT_CORE {
    function commit(bytes32 _commitment) payable external;
}

pragma solidity >=0.7.0 <0.9.0;

// The EIP-165 identifier of this interface is 0x67b2ec2c
interface IERC_COMMIT_GENERAL {
    event Commit(
        uint256 indexed _timePoint,
        address indexed _from,
        bytes32 indexed _commitment,
        bytes _extraData);
    function commitFrom(
        address _from,
        bytes32 _commitment,
        bytes calldata _extraData)
    payable external returns(uint256 timePoint);
}
  1. A compliant contract MUST implement the IERC_COMMIT_CORE interface.
  2. A compliant contract SHOULD implement the IERC_COMMIT_GENERAL interface.
  3. A compliant contract that implements the IERC_COMMIT_GENERAL interface MUST accept commit(_commitment) as equivalent to commitFrom(msg.sender, _commitment, [/*empty array*/]).
  4. The timePoint return value of commitFrom is RECOMMENDED to use block.timestamp or block.number or a number that indicates the ordering of different commitments. When commitFrom is being called.
  5. A compliant contract that implements IERC_COMMIT_GENERAL MUST emit event Commit when a commitment is accepted and recorded. In the parameter of both Commit and the commitFrom method, the _timePoint is a time-point-representing value that represents ordering of commitments in which a latter commitment will always have a greater or equal value than a former commitment, such as block.timestamp or block.number or other time scale chosen by implementing contracts.

  6. The extraData is reserved for future behavior extension. If the _from is different from the TX signer, it is RECOMMENDED that compliant contract SHOULD validate signature for _from. For EOAs this will be validating its ECDSA signatures on chain. For smart contract accounts, it is RECOMMENDED to use EIP-1271 to validate the signatures.

  7. One or more methods of a compliant contract MAY be used for reveal.

But there MUST be a way to supply an extra field of secret_salt, so that committer can later open the secret_salt in the reveal TX that exposes the secret_salt. The size and location of secret_salt is intentionally unspecified in this EIP to maximize flexibility for integration.

  1. It is RECOMMENDED for compliant contracts to implement EIP-165.

Rationale

  1. One design options is that we can attach a Commit Interface to any individual ERCs such as voting standards or token standards. We choose to have a simple and generalize commit interface so all ERCs can be extended to support commit-reveal without changing their basic method signatures.

  2. The key derived design decision we made is we will have a standardized commit method without a standardized reveal method, making room for customized reveal method or using commit with existing standard.

  3. We chose to have a simple one parameter method of commit in our Core interface to make it fully backward compatible with a few prior-adoptions e.g. ENS

  4. We also add a commitFrom to easy commitment being generated off-chain and submitted by some account on behalf by another account.

Backwards Compatibility

This EIP is backward compatible with all existing ERCs method signature that has extraData. New EIPs can be designed with an extra field of “salt” to make it easier to support this EIP, but not required.

The IERC_COMMIT_CORE is backward compatible with ENS implementations and other existing prior-art.

Reference Implementation

Commit with ENS Register as Reveal

In ENS registering process, currently inside of ETHRegistrarController contract a commit function is being used to allow registerer fairly register a desire domain to avoid being front-run.

Here is how ENS uses commitment in its registration logic:

function commit(bytes32 commitment) public {
    require(commitments[commitment] + maxCommitmentAge < now);
    commitments[commitment] = now;
}

With this EIP it can be updated to

function commit(bytes32 commitment, bytes calldata data) public {
    require(commitments[commitment] + maxCommitmentAge < now);
    commitments[commitment] = now;
    emit Commit(...);
}

Security Considerations

  1. Do not use the reference implementation in production. It is just for demonstration purposes.
  2. The reveal transactions and parameters, especially secret_salt, MUST be kept secret before they are revealed.
  3. The length of secret_salt must be cryptographically long enough and the random values used to generate secret_salt must be cryptographically safe.
  4. Users must NEVER reuse a used secret_salt. It’s recommended for client applications to warn users who attempt to do so.
  5. Contract implementations should consider deleting the commitment of a given sender immediately to reduce the chances of a replay attack or re-entry attack.
  6. Contract implementations may consider including the ordering of commitment received to add restrictions on the order of reveal transactions.
  7. There is potential for replay attacks across different chainIds or chains resulting from forks. In these cases, the chainId must be included in the generation of commitment. For applications with a higher risk of replay attacks, implementors should consider battle-tested and cryptographically-secure solutions such as EIP-712 to compose commitments before creating their own new solution.
  8. Proper time gaps are suggested if the purpose is to avoid frontrunning attacks.
  9. For compliant contract that requires the _timePoint from the next transaction to be strictly greater than that of any previous transaction, block.timestamp and block.number are not reliable as two transactions could co-exist in the same block resulting in the same _timePoint value. In such case, extra measures to enforce this strict monotonicity are required, such as the use of a separate sate variable in the contract to keep track of number of commits it receives, or to reject any second/other TX that shares the same block.timestamp or block.number.

Copyright and related rights waived via CC0.