Building with Enclave

Building with Enclave

The Enclave smart contract acts as the central coordinator for all E3 operations. It manages computation requests, input validation, Ciphernode Committees (CiCos), and result publication while maintaining the security and privacy guarantees of the protocol.

The Enclave Smart Contract

Core Responsibilities

  • Manage E3 computation requests
  • Coordinate Ciphernode Committees
  • Handle encrypted input submission
  • Manage Merkle trees for input verification
  • Publish computation results
  • Emit events for off-chain services

Key State Variables

contract Enclave {
    // address of the Ciphernode registry.
    CiphernodeRegistry public ciphernodeRegistry;
 
    // Mapping of allowed E3 Programs.
    mapping(IE3Program e3Program => bool allowed) public e3Programs;
 
    // Mapping of E3s.
    mapping(uint256 e3Id => E3 e3) public e3s;
 
    // Mapping of input merkle trees.
    mapping(uint256 e3Id => LeanIMTData imt) public inputs;
 
    // Mapping of enabled encryption schemes.
    mapping(bytes32 encryptionSchemeId => IDecryptionVerifier decryptionVerifier)
        public decryptionVerifiers;
}

Requesting Computation

Request Flow

  1. Users submits onchain request
function request(
    address filter,
    uint32[2] calldata threshold,
    uint256[2] calldata startWindow,
    uint256 duration,
    IE3Program e3Program,
    bytes memory e3ProgramParams,
    bytes memory computeProviderParams
) external payable
  1. Contract validates request parameters
  2. E3 Program contract is set and used to get the InputValidator contract & Encryption scheme.
  3. Request is submitted to the ciphernodeRegistry for committee selection.
  4. E3Requested event is emitted

Committee and Ciphernode Management

Committee Selection

  • An E3 request triggers a deterministic sortition process to select a Ciphernode Committee (CiCo) from the global pool of available Ciphernodes.
  • Selected nodes coordinate to produce a shared public key with the requested threshold.
  • The public key is published to the Ciphernode Registry smart contract.

E3 Activation

After the public key is published, anyone can activate the E3 by calling the activate() function in the Enclave contract:

function activate(
    uint256 e3Id,
    bytes memory publicKey
) external

Activating an E3 will allow valid Data Providers to submit inputs to the computation.

Input Publication

Inputs are published directly to the Enclave contract's publishInput() function.

function publishInput(
    uint256 e3Id,
    bytes memory data
) external

Inputs are accumulated incrementally into a Merkle tree. This allows you to:

  1. Use the published Merkle root as part of your E3 Program's Secure Process to ensure all published inputs are processed by the Compute Provider.
  2. Prevent input tampering or omission.
  3. Anchor proofs for correct execution.

Merkle Tree Construction

Enclave uses a Lean Merkle Tree implementation. Each input is hashed using the PosidenT3 Hash function, and the root is updated with each new input.

Your E3 program should:

  1. Reconstruct the Merkle tree from the given inputs
  2. Verify the resulting root matches on-chain root

Input Validation

As much as possible, you should aim to validate inputs via proofs generated by Data Prodivers, rather than in your Secure Process. This pushed computation to the edges and allows you to reduce the complexity of your FHE computation.

Your E3 Program must include a contract that implements IInputValidator. When publishing an input, the Enclave contracts will call the validate() function on your Input Validator contract.

function validate(
        address sender,
        bytes memory params
    ) external returns (bytes memory input, bool success);

At a minimum, this function should validate a proof that the given ciphertext is a valid encryption to the E3's public key. It is also recommended to bundle in proofs to validate:

  • The legitimacy of the Data Provider (e.g., ensuring they are listed in a registry of approved data providers).
  • Range checks, checksums, and/or other well-formedness criteria for the plaintext that was encrypted.

Result Publication and Events

Key Events

event E3Requested(
    uint256 indexed e3Id,
    address indexed requester,
    address e3ProgramAddress
);
 
event InputSubmitted(
    uint256 indexed e3Id,
    address indexed sender,
    bytes32 inputHash
);
 
event CiphertextOutputPublished(
    uint256 indexed e3Id,
    bytes32 ciphertextHash
);
 
event PlaintextOutputPublished(
    uint256 indexed e3Id,
    bytes plaintext
);

Result Publication Flow

  1. The Compute Provider submits a proof and ciphertext output.
  2. Enclave uses the E3 Program contract to verify the proof and emits CiphertextOutputPublished.
  3. Ciphernodes decrypt the ciphertext output.
  4. The plaintext result is published
  5. Events are emitted for off-chain services

Example Usage

Submitting a Request

const enclaveContract = new ethers.Contract(enclaveAddress, enclaveAbi, signer)
 
const tx = await enclaveContract.request(
  filterAddress,
  [thresholdMin, thresholdMax],
  [startWindowStart, startWindowEnd],
  duration,
  e3ProgramAddress,
  e3ProgramParams,
  computeProviderParams,
  { value: computationFee },
)
 
const receipt = await tx.wait()
const e3Id = receipt.events.find((e) => e.event === 'E3Requested').args.e3Id

Monitoring Results

enclaveContract.on('PlaintextOutputPublished', (e3Id, plaintext) => {
  console.log(`Computation ${e3Id} completed with result:`, plaintext)
})

Submitting Inputs

const tx = await enclaveContract.publishInput(e3Id, encryptedInput)
await tx.wait()

Security Considerations

  1. Committee Selection

The size and threshold of the Ciphernode Committee you select for your computation directly impacts both the cost and economic security of your E3. A higher threshold means more economic security (a higher cost to compromise the E3), but incurs a higher protocol fee.

  1. Input Validation

Your InputValidator contract is critical to ensuring that inputs come from approved parties, are sanitized for your computation, and truthfully correspond to any specific sources of truth. You can use your InputValidator contract to push computation to the edges, reducing the complexity of your FHE computation.

  1. Result Verification

The Enclave protocol will accept and decrypt whatever output is reported by your Compute Provider. In other words, your E3s inherit the trust assumptions of your Compute Provider. An incorrectly implemented Secure Process in your E3 Program or a dishonest or compromised Compute Provider could leak information.

  1. Event Handling

If you are consuming Enclave outputs offchain, allow for sufficient confirmations to be confident in the finality of the outcome and to appropriately handle re-orgs.

Best Practices

  1. Request Management

    • Set appropriate thresholds
    • Choose realistic time windows
  2. Input Handling

    • Encrypt inputs properly
    • Include necessary ZKPs
    • Submit within time windows
  3. Result Processing

    • Listen for all relevant events
    • Implement timeout handling
    • Verify result integrity
  4. Error Handling

    • Handle contract reverts
    • Implement retry logic
    • Log errors appropriately