Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
34e7f7c
add read_scalar, point_add and point_mul into the wrapper
kevaundray Mar 20, 2025
d3aba76
modify bn128.rs to use new api methods
kevaundray Mar 20, 2025
ec1a3b4
preserve previous semantics
kevaundray Mar 20, 2025
1dc9404
initial commit to add matter-labs wrapper
kevaundray Mar 20, 2025
99edba1
feature gate matter-labs impl -- make substrate impl still default
kevaundray Mar 20, 2025
45e13e3
update revm and precompile cargo.toml file
kevaundray Mar 20, 2025
398910c
use cfg_if
kevaundray Mar 20, 2025
526103b
make bn an optional dependency
kevaundray Mar 20, 2025
8dfda37
cfg else -> else_if so that there is no silent fallback
kevaundray Mar 20, 2025
5b2fe79
follow same cfg_if pattern as other precompiles
kevaundray Mar 20, 2025
98b6488
fix optimism
kevaundray Mar 20, 2025
5becac4
add back `self` import
kevaundray Mar 20, 2025
f8be131
Push empty commit to trigger CI
kevaundray Mar 20, 2025
f4c8595
cargo fmt
kevaundray Mar 20, 2025
df64b70
clippy fix
kevaundray Mar 20, 2025
570d449
make `bn` the default with revm and revme
kevaundray Mar 20, 2025
e38b6e1
fix typo
kevaundray Mar 20, 2025
6b2a765
Merge branch 'main' into kw/add-matter-labs
kevaundray Mar 21, 2025
d672f23
Update crates/revm/Cargo.toml
kevaundray Mar 21, 2025
cfda7c4
Update crates/revm/Cargo.toml
kevaundray Mar 21, 2025
88ed53c
Update crates/precompile/src/lib.rs
kevaundray Mar 21, 2025
50f45cf
Update crates/optimism/Cargo.toml
kevaundray Mar 21, 2025
0fb0fdd
revert Cargo.toml formatting
kevaundray Mar 21, 2025
6d5348c
multi:
kevaundray Mar 21, 2025
b889f1c
revert crates/optimism/src/precompiles.rs
kevaundray Mar 21, 2025
7713162
revert crates/optimism/src/evm.rs
kevaundray Mar 21, 2025
6004b6c
revert unnecessary changes in crates/precompile/src/lib.rs
kevaundray Mar 21, 2025
a792687
revert Cargo.toml changes
kevaundray Mar 21, 2025
b840176
revert automatic Cargo.toml formatting
kevaundray Mar 21, 2025
a57920e
revert formatting on secp256k1 in Cargo.toml
kevaundray Mar 21, 2025
498502e
revert c-kzg formatting in Cargo.toml
kevaundray Mar 21, 2025
184151c
revert dev key in Cargo.toml
kevaundray Mar 21, 2025
f80171d
revert c-kzg feature in Cargo.toml
kevaundray Mar 21, 2025
b3e5bd1
Merge branch 'main' into kw/add-matter-labs
kevaundray Mar 21, 2025
f747766
Update crates/precompile/Cargo.toml
kevaundray Mar 21, 2025
1b20177
Apply suggestions from code review
kevaundray Mar 21, 2025
d56d192
Merge branch 'main' into kw/add-matter-labs
kevaundray Mar 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ aurora-engine-modexp = { version = "1.1", default-features = false }
blst = "0.3.13"
bn = { package = "substrate-bn", version = "0.6", default-features = false }
c-kzg = { version = "1.0.0", default-features = false }
eth_pairings = { git = "https://github.com/matter-labs/eip1962", rev = "17ba98bdbdd7bdf239c09cd88ca46a486124f5e7", default-features = false }
k256 = { version = "0.13.3", default-features = false }
libsecp256k1 = { version = "0.7", default-features = false }
kzg-rs = { version = "0.2.4", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions crates/optimism/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ c-kzg = ["revm/c-kzg"]
# `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible.
kzg-rs = ["revm/kzg-rs"]
blst = ["revm/blst"]
matter-labs-eip1962 = ["revm/matter-labs-eip1962"]
6 changes: 6 additions & 0 deletions crates/precompile/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ aurora-engine-modexp.workspace = true
# ecAdd, ecMul, ecPairing
bn.workspace = true

# Optionally use matter-labs implementation for eip1962
eth_pairings = { workspace = true, features = ["eip_196"], optional = true }

# KZG point evaluation precompile
c-kzg = { workspace = true, optional = true, features = [
"ethereum_kzg_settings",
Expand Down Expand Up @@ -118,6 +121,9 @@ libsecp256k1 = ["dep:libsecp256k1"]
# Enables the BLS12-381 precompiles.
blst = ["dep:blst"]

# Use the matter-labs implementation for BN128 operations (EIP1962)
matter-labs-eip1962 = ["dep:eth_pairings"]

[[bench]]
name = "bench"
path = "benches/bench.rs"
Expand Down
20 changes: 15 additions & 5 deletions crates/precompile/src/bn128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ use crate::{
};
use std::vec::Vec;

use substrate::{
encode_g1_point, g1_point_add, g1_point_mul, pairing_check, read_g1_point, read_g2_point,
read_scalar,
};
mod substrate;
cfg_if::cfg_if! {
if #[cfg(feature = "matter-labs-eip1962")]{
mod matter_labs;
use matter_labs::{
encode_g1_point, g1_point_add, g1_point_mul, pairing_check, read_g1_point, read_g2_point,
read_scalar,
};
} else {
mod substrate;
use substrate::{
encode_g1_point, g1_point_add, g1_point_mul, pairing_check, read_g1_point, read_g2_point,
read_scalar,
};
}
}

pub mod add {
use super::*;
Expand Down
180 changes: 180 additions & 0 deletions crates/precompile/src/bn128/matter_labs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use super::{PrecompileError, FQ_LEN, G1_LEN, G2_LEN, SCALAR_LEN};
use eth_pairings::{
engines::bn254::*,
extension_towers::fp12_as_2_over3_over_2::Fp12,
field::U256Repr,
integers::MaxGroupSizeUint,
pairings::PairingEngine,
public_interface::{decode_g1, decode_g2},
traits::{Group, ZeroAndOne},
};

/// G1Point is the concrete representation of a G1 element
pub(super) type G1Point = eth_pairings::weierstrass::curve::CurvePoint<
'static,
eth_pairings::weierstrass::CurveOverFpParameters<
'static,
U256Repr,
eth_pairings::field::PrimeField<U256Repr>,
>,
>;

/// G2Point is the concrete representation of a G2 element
pub(super) type G2Point = eth_pairings::weierstrass::curve::CurvePoint<
'static,
eth_pairings::weierstrass::CurveOverFp2Parameters<
'static,
U256Repr,
eth_pairings::field::PrimeField<U256Repr>,
>,
>;
/// Fr is the concrete representation of an element in the scalar field.
pub(super) type Fr = MaxGroupSizeUint;

/// Reads a G1 point from the input slice.
///
/// Parses a G1 point from a byte slice by reading two consecutive field elements
/// representing the x and y coordinates.
#[inline]
pub(super) fn read_g1_point(input: &[u8]) -> Result<G1Point, PrecompileError> {
let (point, _) = decode_g1::decode_g1_point_from_xy_oversized(input, FQ_LEN, &*BN254_G1_CURVE)
.map_err(|_| PrecompileError::Bn128AffineGFailedToCreate)?;

if !point.is_on_curve() {
return Err(PrecompileError::Bn128AffineGFailedToCreate);
}

// We can skip the subgroup check since G1 is prime ordered.

Ok(point)
}

/// Encodes a G1 point into a byte array.
///
/// Serializes a G1 point into its x and y coordinates as a byte array.
#[inline]
pub(super) fn encode_g1_point(point: G1Point) -> [u8; G1_LEN] {
let mut output = [0u8; G1_LEN];

if !point.is_zero() {
let as_vec = decode_g1::serialize_g1_point(FQ_LEN, &point).unwrap();
output.copy_from_slice(&as_vec[..]);
}

output
}

/// Reads a G2 point from the input slice.
///
/// Parses a G2 point from a byte slice by reading four consecutive field elements
/// representing the two coordinates (x and y) of the G2 point.
#[inline]
pub(super) fn read_g2_point(input: &[u8]) -> Result<G2Point, PrecompileError> {
// G2 encoding in EIP 196/197 is non-standard: Fp2 element c0 + v*c1 where v is non-residue is
// encoded as (c1, c0) instead of usual (c0, c1)
let mut swapped_encoding = [0u8; G2_LEN];

let x_0 = &input[0..FQ_LEN];
let x_1 = &input[FQ_LEN..(FQ_LEN * 2)];
let y_0 = &input[(FQ_LEN * 2)..(FQ_LEN * 3)];
let y_1 = &input[(FQ_LEN * 3)..(FQ_LEN * 4)];

// swap for x coordinate
swapped_encoding[0..FQ_LEN].copy_from_slice(x_1);
swapped_encoding[FQ_LEN..(FQ_LEN * 2)].copy_from_slice(x_0);

// swap for y coordinate
swapped_encoding[(FQ_LEN * 2)..(FQ_LEN * 3)].copy_from_slice(y_1);
swapped_encoding[(FQ_LEN * 3)..(FQ_LEN * 4)].copy_from_slice(y_0);

let (g2_point, _) = decode_g2::decode_g2_point_from_xy_in_fp2_oversized(
&swapped_encoding,
FQ_LEN,
&*BN254_G2_CURVE,
)
.map_err(|_| PrecompileError::Bn128AffineGFailedToCreate)?;

if !g2_point.is_on_curve() {
return Err(PrecompileError::Bn128FieldPointNotAMember);
}

// The zero point is on the curve and in the subgroup
if g2_point.is_zero() {
return Ok(g2_point);
}
// Check G2 point is in the correct subgroup
let is_in_subgroup = g2_point
.wnaf_mul_with_window_size(&BN254_SUBGROUP_ORDER[..], 5)
.is_zero();
if !is_in_subgroup {
return Err(PrecompileError::Bn128FieldPointNotAMember);
}

Ok(g2_point)
}

/// Reads a scalar from the input slice
///
/// Note: The scalar does not need to be canonical.
#[inline]
pub(super) fn read_scalar(input: &[u8]) -> Fr {
assert_eq!(
input.len(),
SCALAR_LEN,
"unexpected scalar length. got {}, expected {SCALAR_LEN}",
input.len()
);
let (scalar, _) = decode_g1::decode_scalar_representation(input, SCALAR_LEN).unwrap();

scalar
}

/// Performs point addition on two G1 points.
#[inline]
pub(super) fn g1_point_add(p1: G1Point, p2: G1Point) -> G1Point {
let mut result = p1.clone();
result.add_assign(&p2);
result
}

/// Performs point multiplication.
///
/// Takes a G1 point and a scalar representation, and returns the result of the multiplication.
#[inline]
pub(super) fn g1_point_mul(p: G1Point, scalar: Fr) -> G1Point {
p.mul(scalar)
}

/// pairing_check performs a pairing check on a list of G1 and G2 point pairs.
///
/// Returns true if the result of the pairing is equal to the identity element.
#[inline]
pub(super) fn pairing_check(pairs: &[(G1Point, G2Point)]) -> bool {
if pairs.is_empty() {
return true;
}

let engine = &*BN254_PAIRING_ENGINE;

// Convert to vectors as required by Matter Labs implementation
let g1_points: Vec<_> = pairs.iter().map(|(g1, _)| g1.clone()).collect();
let g2_points: Vec<_> = pairs.iter().map(|(_, g2)| g2.clone()).collect();

let pairing_result = engine.pair(&g1_points, &g2_points);

// This returns None under two conditions:
//
// - g1_points.len() != g2_points.len()
// - The final_exponentiation value is 0
//
// - The first case is not possible by construction
// - In the second case, we want to return false because the
// result is not 1
let pairing_result = match pairing_result {
Some(pr) => pr,
None => return false,
};

let one_fp12 = Fp12::one(&*BN254_EXT12_FIELD);
pairing_result == one_fp12
}
4 changes: 4 additions & 0 deletions crates/precompile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub mod secp256r1;
pub mod utilities;

pub use interface::*;

#[cfg(feature = "matter-labs-eip1962")]
// silence bn lint as matter-labs impl will be used as default if both are enabled.
use bn as _;
#[cfg(all(feature = "c-kzg", feature = "kzg-rs"))]
// silence kzg-rs lint as c-kzg will be used as default if both are enabled.
use kzg_rs as _;
Expand Down
1 change: 1 addition & 0 deletions crates/revm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ c-kzg = [
kzg-rs = ["precompile/kzg-rs"]
blst = ["precompile/blst"]
secp256r1 = ["precompile/secp256r1"]
matter-labs-eip1962 = ["precompile/matter-labs-eip1962"]

# Compile in portable mode, without ISA extensions.
# Binary can be executed on all systems.
Expand Down
Loading