Writing the E3 Program Contract

Writing an E3 Contract

The E3 contract defines your program on-chain. It verifies parameters during the creation of new E3 instances, validates inputs for your Secure Process, and publishes the computation output.

Smart Contract Components

Each E3 Program consists of two contract components:

  1. E3 Program contract
  2. Input Validator contract

E3 Program

The E3 program forms the core of each E3, implementing two functions: one to validate input parameters when a new E3 instance is created and another to verify the output of the computation.

validate

  function validate(
    uint256 e3Id,
    uint256 seed,
    bytes calldata e3ProgramParams,
    bytes calldata computeProviderParams
  )
    external
    returns (bytes32 encryptionSchemeId, IInputValidator inputValidator);

When a new instance of your E3 Program is requested, the validate function is called to validate and initialize the new E3. Some useful validations include:

  • Random Seed Initialization: Use the seed parameter to instantiate the E3 with a specific random seed
  • Custom Parameters: Utilize e3ProgramParams to pass in any additional arbitrary parameters, most commonly the address of your Input Validator contract.
  • Compute Provider Setup: Use computeProviderParams to validate the configuration of the Compute Provider chosen for your E3 Program.

For an example, see this mockup (opens in a new tab) or check out the demo implementation for the CRISP protocol (opens in a new tab).

verify

  function verify(
    uint256 e3Id,
    bytes32 ciphertextOutput,
    bytes memory proof
  ) external returns (bool success);

The verify function intakes the output of the E3 computation and the accompanying proof generated by your chosen Compute Provider to assess the validity of the proof and ciphertext. You can see an example of this using RISC Zero's Verifier in our CRISP E3 contract (opens in a new tab).

Input Validator

In order to ensure correct computation, we recommend creating or using an existing input verifier contract to check that the encrypted data submitted to your E3 is properly structured. This will most likely be used in tandem with a proof generated by your Data Provider.

Responsibilities:

  • Data Decoding: Decode encrypted input data to its intended format.
  • ZKP Verification: Verify any associated ZKPs to ensure input correctness.
  • Input Acceptance: Return validated input for inclusion in the computation.

Example:

pragma solidity >=0.8.27;
 
import {IInputValidator} from "@gnosis-guild/enclave/interfaces.sol";
 
contract MyInputValidator is IInputValidator {
    function validate(address sender, bytes memory data) external override returns (bytes memory, bool) {
        // Decode data
        // Verify ZKP
        // Return validated input
    }
}