Skip to content

Commit 79163b3

Browse files
committed
feat(client): bls12-381 curve precompile
1 parent c017eea commit 79163b3

File tree

4 files changed

+113
-5
lines changed

4 files changed

+113
-5
lines changed

Cargo.lock

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/client/src/precompiles/bls12.rs

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//! Contains the accelerated precompile for the BLS12-381 curve.
2+
//!
3+
//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537).
4+
//!
5+
//! For constants and logic, see the [revm implementation].
6+
//!
7+
//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/pairing.rs
8+
9+
use crate::{HINT_WRITER, ORACLE_READER};
10+
use alloc::{string::ToString, vec::Vec};
11+
use alloy_primitives::{address, keccak256, Address, Bytes};
12+
use kona_preimage::{
13+
errors::PreimageOracleError, HintWriterClient, PreimageKey, PreimageKeyType,
14+
PreimageOracleClient,
15+
};
16+
use kona_proof::{errors::OracleProviderError, HintType};
17+
use revm::{
18+
precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress},
19+
primitives::PrecompileOutput,
20+
};
21+
22+
/// The address of the BLS12-381 pairing check precompile.
23+
const BLS12_PAIRING_CHECK: Address = address!("0x000000000000000000000000000000000000000f");
24+
25+
/// Input length of pairing operation.
26+
const INPUT_LENGTH: usize = 384;
27+
28+
/// Multiplier gas fee for BLS12-381 pairing operation.
29+
const PAIRING_MULTIPLIER_BASE: u64 = 32600;
30+
31+
/// Offset gas fee for BLS12-381 pairing operation.
32+
const PAIRING_OFFSET_BASE: u64 = 37700;
33+
34+
/// The address of the BLS12-381 pairing precompile.
35+
pub(crate) const FPVM_BLS12_PAIRING: PrecompileWithAddress =
36+
PrecompileWithAddress(BLS12_PAIRING_CHECK, Precompile::Standard(fpvm_bls12_pairing));
37+
38+
/// Performs an FPVM-accelerated BLS12-381 pairing check.
39+
fn fpvm_bls12_pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult {
40+
let input_len = input.len();
41+
if input_len % INPUT_LENGTH != 0 {
42+
return Err(PrecompileError::Other(alloc::format!(
43+
"Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}"
44+
))
45+
.into());
46+
}
47+
48+
let k = input_len / INPUT_LENGTH;
49+
let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE;
50+
if required_gas > gas_limit {
51+
return Err(PrecompileError::OutOfGas.into());
52+
}
53+
54+
let result_data = kona_proof::block_on(async move {
55+
// Write the hint for the ecrecover precompile run.
56+
let hint_data = &[BLS12_PAIRING_CHECK.as_ref(), input.as_ref()];
57+
HINT_WRITER
58+
.write(&HintType::L1Precompile.encode_with(hint_data))
59+
.await
60+
.map_err(OracleProviderError::Preimage)?;
61+
62+
// Construct the key hash for the ecrecover precompile run.
63+
let raw_key_data = hint_data.iter().copied().flatten().copied().collect::<Vec<u8>>();
64+
let key_hash = keccak256(&raw_key_data);
65+
66+
// Fetch the result of the ecrecover precompile run from the host.
67+
let result_data = ORACLE_READER
68+
.get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile))
69+
.await
70+
.map_err(OracleProviderError::Preimage)?;
71+
72+
// Ensure we've received valid result data.
73+
if result_data.is_empty() {
74+
return Err(OracleProviderError::Preimage(PreimageOracleError::Other(
75+
"Invalid result data".to_string(),
76+
)));
77+
}
78+
79+
// Ensure we've not received an error from the host.
80+
if result_data[0] == 0 {
81+
return Err(OracleProviderError::Preimage(PreimageOracleError::Other(
82+
"Error executing ecrecover precompile in host".to_string(),
83+
)));
84+
}
85+
86+
// Return the result data.
87+
Ok(result_data[1..].to_vec())
88+
})
89+
.map_err(|e| PrecompileError::Other(e.to_string()))?;
90+
91+
Ok(PrecompileOutput::new(required_gas, result_data.into()))
92+
}
93+
94+
#[cfg(test)]
95+
mod tests {
96+
use super::*;
97+
use alloc::vec;
98+
99+
#[test]
100+
fn test_fpvm_bls12_out_of_gas() {
101+
let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]);
102+
let gas_limit = PAIRING_MULTIPLIER_BASE - 1;
103+
assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(PrecompileError::OutOfGas.into()));
104+
}
105+
}

bin/client/src/precompiles/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use revm::{
1111
State,
1212
};
1313

14+
mod bls12;
1415
mod bn128_pair;
1516
mod ecrecover;
1617
mod kzg_point_eval;
@@ -33,6 +34,7 @@ pub(crate) fn fpvm_handle_register<F, H>(
3334

3435
// Extend with FPVM-accelerated precompiles
3536
let override_precompiles = [
37+
bls12::FPVM_BLS12_PAIRING,
3638
ecrecover::FPVM_ECRECOVER,
3739
bn128_pair::FPVM_ECPAIRING,
3840
kzg_point_eval::FPVM_KZG_POINT_EVAL,

bin/host/src/eth/precompiles.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use revm::{
1111
pub(crate) const ACCELERATED_PRECOMPILES: &[PrecompileWithAddress] = &[
1212
precompile::secp256k1::ECRECOVER, // ecRecover
1313
precompile::bn128::pair::ISTANBUL, // ecPairing
14+
precompile::bls12_381::pairing::PRECOMPILE, // BLS12-381 pairing
1415
precompile::kzg_point_evaluation::POINT_EVALUATION, // KZG point evaluation
1516
];
1617

0 commit comments

Comments
 (0)