Skip to content

EVM Protocol Adapter Primitive Interfaces

This section contains descriptions of the implementations of primitive interfaces in the EVM Protocol Adapter.

Set

The set implementation we use is the OpenZeppelin EnumerableSet v5.2.0 implementation.

Map

We use two representations of maps.

The first - used in the the core datatype implementation such as the logicVerifierInputs - is the representation of a map as a list of structs containing an explicit field for the key field, namely logicVerifierInputs contains field Instance which in turn contains a field tag which is seen as a key to the map.

We also use Solidity's mapping for the commitment accumilator functionality.

Fixed Size Type

We generally used bytes32/uint256 in the implementation, also using uint128 for quantity of resources.

Proving System

For the current implementation, for resource logics and the compliance proofs we use the Risc0 proving system, specifically v3.0.3 of Risc0 alongside the appropriate version of the EVM verifier. The delta values are computed as 2D points (uint256[2]) on the secp256k1 (K-256) elliptic curve and verified using ECDSA.

Compliance Circuit

Our compliance circuits are fixed size of exactly 2 resources: 1 created and 1 consumed. This allows us to also ensure that the nonce of the created resource contains the hash of the consumed resource. This grants uniqueness of comitments automatically given uniqueness of nullifiers.

The compliance verifying key is fixed and hardcoded as an internal constant:

bytes32 internal constant _VERIFYING_KEY = ...;

Other than the checks described in the Compliance Proof page, the compliance proof for the EVM protocol adapter constraints the created resource to use the nullifier of the consumed resource.

For details, consult the contrains in the arm-risc0 library.

Delta Proof

The delta proving system uses the ECDSA signature scheme over the K256 eliptic curve. The signature (delta proof) is the sum of the randomness across all compliance units, while the verification key comes from the keccak-256 hash over the list of all nullifier and commitments pairs obtained by iterating over the compliance units (see src/proving/Delta.sol). The instance for the proving system comes from the sum of unit deltas, where the latter are generated as the curve point representation of corresponding resources.

The verification tries to recover from the verifying key hash using the proof as the signature and check the correspondence with the instance.

We use OpenZeppelin's ECDSA library for recovery.

The elliptic curve addition and conversion methods are defined in proving/Delta.sol. The curve implementation is taken from Witnet's eliptic-curve-solidity library v0.2.1. This includes:

Commitment Accumilator

Our commitment accumulator is a modified version of OpenZeppelin's MerkleTree and MerkleProof implementations. The core difference is the fact that it is a dynamic sparse merkle tree which expands its depth when needed to fit enough leaves.

This keeps the gas costs of updating the commitment merkle tree to a minimum. For details, please consult the documentation).

Nullifier Accumulator

As our nullifier accumulator we use a set. As noted above, the implementation is provided by OpenZeppelin EnumerableSet v5.2.0 implementation.