Skip to content

Commit

Permalink
feat(client): ecpairing accelerated precompile
Browse files Browse the repository at this point in the history
## Overview

Adds an `ecpairing` accelerated precompile for the FPVM backend.
  • Loading branch information
clabby committed Jun 28, 2024
1 parent e50bd40 commit 3f657e9
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
61 changes: 61 additions & 0 deletions bin/client/src/l2/precompiles/bn128_pair.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Contains the accelerated version of the `ecPairing` precompile.

use alloc::{string::ToString, vec::Vec};
use alloy_primitives::{keccak256, Address, Bytes};
use anyhow::ensure;
use kona_preimage::{HintWriterClient, PreimageKey, PreimageKeyType, PreimageOracleClient};
use revm::{
precompile::{
bn128::pair::{ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT},
u64_to_address, Error as PrecompileError, PrecompileWithAddress,
},
primitives::{Precompile, PrecompileOutput, PrecompileResult},
};

use crate::{HintType, HINT_WRITER, ORACLE_READER};

const ECPAIRING_ADDRESS: Address = u64_to_address(8);
const PAIR_ELEMENT_LEN: usize = 64 + 128;

pub(crate) const FPVM_ECPAIRING: PrecompileWithAddress =
PrecompileWithAddress(ECPAIRING_ADDRESS, Precompile::Standard(fpvm_ecpairing));

/// Performs an FPVM-accelerated `ecpairing` precompile call.
fn fpvm_ecpairing(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let gas_used =
(input.len() / PAIR_ELEMENT_LEN) as u64 * ISTANBUL_PAIR_PER_POINT + ISTANBUL_PAIR_BASE;

if gas_used > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

if input.len() % PAIR_ELEMENT_LEN != 0 {
return Err(PrecompileError::Bn128PairLength.into());
}

let result_data = kona_common::block_on(async move {
// Write the hint for the ecrecover precompile run.
let hint_data = &[ECPAIRING_ADDRESS.as_ref(), input.as_ref()];
HINT_WRITER.write(&HintType::L1Precompile.encode_with(hint_data)).await?;

// Construct the key hash for the ecrecover precompile run.
let raw_key_data = hint_data.iter().copied().flatten().copied().collect::<Vec<u8>>();
let key_hash = keccak256(&raw_key_data);

// Fetch the result of the ecrecover precompile run from the host.
let result_data =
ORACLE_READER.get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile)).await?;

// Ensure we've received valid result data.
ensure!(!result_data.is_empty(), "Invalid result data");

// Ensure we've not received an error from the host.
ensure!(result_data[0] != 0, "Error executing ecrecover precompile in host");

// Return the result data.
Ok(result_data[1..].to_vec())
})
.map_err(|e| PrecompileError::Other(e.to_string()))?;

Ok(PrecompileOutput::new(gas_used, result_data.into()))
}
3 changes: 2 additions & 1 deletion bin/client/src/l2/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use revm::{
handler::register::EvmHandler, precompile::PrecompileSpecId, ContextPrecompiles, State,
};

mod bn128_pair;
mod ecrecover;

/// The [PrecompileOverride] implementation for the FPVM-accelerated precompiles.
Expand Down Expand Up @@ -42,7 +43,7 @@ where
ContextPrecompiles::new(PrecompileSpecId::from_spec_id(spec_id)).clone();

// Extend with FPVM-accelerated precompiles
let override_precompiles = [ecrecover::FPVM_ECRECOVER];
let override_precompiles = [ecrecover::FPVM_ECRECOVER, bn128_pair::FPVM_ECPAIRING];
ctx_precompiles.extend(override_precompiles);

ctx_precompiles
Expand Down

0 comments on commit 3f657e9

Please sign in to comment.