diff --git a/Cargo.lock b/Cargo.lock index 601f0c337e..ece8043aa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -621,6 +621,18 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-bn254" version = "0.5.0" @@ -3815,6 +3827,7 @@ dependencies = [ name = "revm-precompile" version = "17.0.0" dependencies = [ + "ark-bls12-381", "ark-bn254", "ark-ec", "ark-ff 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index 6361236891..99fc80b548 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ alloy-transport = { version = "0.12.4", default-features = false } # precompiles ark-bn254 = { version = "0.5", default-features = false } +ark-bls12-381 = { version = "0.5", default-features = false } ark-ec = { version = "0.5", default-features = false } ark-ff = { version = "0.5", default-features = false } ark-serialize = { version = "0.5", default-features = false } diff --git a/crates/optimism/src/evm.rs b/crates/optimism/src/evm.rs index ad1cdb993f..1ac56fc2d7 100644 --- a/crates/optimism/src/evm.rs +++ b/crates/optimism/src/evm.rs @@ -283,7 +283,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g1_add_out_of_gas() { let ctx = Context::op() .modify_tx_chained(|tx| { @@ -311,7 +310,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g1_add_input_wrong_size() { let ctx = Context::op() .modify_tx_chained(|tx| { @@ -370,7 +368,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g1_msm_input_wrong_size() { let ctx = g1_msm_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..)); @@ -388,7 +385,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g1_msm_out_of_gas() { let ctx = g1_msm_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1); @@ -406,7 +402,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout() { let ctx = g1_msm_test_tx(); @@ -424,7 +419,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g2_add_out_of_gas() { let ctx = Context::op() .modify_tx_chained(|tx| { @@ -452,7 +446,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g2_add_input_wrong_size() { let ctx = Context::op() .modify_tx_chained(|tx| { @@ -512,7 +505,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g2_msm_input_wrong_size() { let ctx = g2_msm_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..)); @@ -530,7 +522,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g2_msm_out_of_gas() { let ctx = g2_msm_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1); @@ -548,7 +539,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout() { let ctx = g2_msm_test_tx(); @@ -596,7 +586,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_pairing_input_wrong_size() { let ctx = bl12_381_pairing_test_tx() .modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..)); @@ -615,7 +604,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_pairing_out_of_gas() { let ctx = bl12_381_pairing_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1); @@ -633,7 +621,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_tx_call_bls12_381_pairing_wrong_input_layout() { let ctx = bl12_381_pairing_test_tx(); @@ -678,7 +665,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas() { let ctx = fp_to_g1_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1); @@ -696,7 +682,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size() { let ctx = fp_to_g1_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..)); @@ -741,7 +726,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas() { let ctx = fp2_to_g2_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1); @@ -759,7 +743,6 @@ mod tests { } #[test] - #[cfg(feature = "blst")] fn test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size() { let ctx = fp2_to_g2_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..)); diff --git a/crates/optimism/src/precompiles.rs b/crates/optimism/src/precompiles.rs index f5c7b1d7f6..cbd15ec478 100644 --- a/crates/optimism/src/precompiles.rs +++ b/crates/optimism/src/precompiles.rs @@ -70,21 +70,9 @@ pub fn granite() -> &'static Precompiles { pub fn isthmus() -> &'static Precompiles { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { - let precompiles = granite().clone(); + let mut precompiles = granite().clone(); // Prague bls12 precompiles - // Don't include BLS12-381 precompiles in no_std builds. - #[cfg(feature = "blst")] - let precompiles = { - let mut precompiles = precompiles; - precompiles.extend(precompile::bls12_381::precompiles()); - precompiles - }; - #[cfg(not(feature = "blst"))] - let precompiles = { - let mut precompiles = precompiles; - precompiles.extend(precompile::bls12_381_utils::bls12_381_precompiles_not_supported()); - precompiles - }; + precompiles.extend(precompile::bls12_381::precompiles()); Box::new(precompiles) }) } diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 937a6a1998..e39b83f667 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -64,9 +64,12 @@ c-kzg = { workspace = true, optional = true, features = [ # Optionally use `kzg-rs` for a pure Rust implementation of KZG point evaluation. kzg-rs = { workspace = true, optional = true } -# BLS12-381 precompiles +# Use the BLS12-381 implementation of blst for EIP2537 blst = { workspace = true, optional = true } +# Use the BLS12-381 implementation of arkworks for EIP2537 +ark-bls12-381 = { workspace = true, features = ["curve"] } + # p256verify precompile p256 = { workspace = true, optional = true, features = ["ecdsa"] } @@ -98,6 +101,7 @@ std = [ "serde/std", "serde_json/std", "ark-bn254/std", + "ark-bls12-381/std", "ark-ec/std", "ark-ff/std", "ark-serialize/std", @@ -125,7 +129,7 @@ portable = ["c-kzg?/portable", "blst?/portable"] secp256k1 = ["dep:secp256k1"] libsecp256k1 = ["dep:libsecp256k1"] -# Enables the BLS12-381 precompiles. +# Enables the blst implementation of the BLS12-381 precompile. blst = ["dep:blst"] # Enables the substrate implementation of eip1962 diff --git a/crates/precompile/src/bls12_381.rs b/crates/precompile/src/bls12_381.rs index 3a29f2a903..c8ead30c39 100644 --- a/crates/precompile/src/bls12_381.rs +++ b/crates/precompile/src/bls12_381.rs @@ -1,6 +1,14 @@ use crate::PrecompileWithAddress; -mod blst; +cfg_if::cfg_if! { + if #[cfg(feature = "blst")]{ + mod blst; + use blst as crypto_backend; + } else { + mod arkworks; + use arkworks as crypto_backend; + } +} pub mod g1_add; pub mod g1_msm; diff --git a/crates/precompile/src/bls12_381/arkworks.rs b/crates/precompile/src/bls12_381/arkworks.rs new file mode 100644 index 0000000000..a00b4f9112 --- /dev/null +++ b/crates/precompile/src/bls12_381/arkworks.rs @@ -0,0 +1,379 @@ +use crate::{ + bls12_381_const::{ + FP_LENGTH, FP_PAD_BY, PADDED_FP_LENGTH, PADDED_G1_LENGTH, PADDED_G2_LENGTH, SCALAR_LENGTH, + }, + PrecompileError, +}; +use ark_bls12_381::{Bls12_381, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_ec::{ + hashing::{curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurve}, + pairing::Pairing, + AffineRepr, CurveGroup, VariableBaseMSM, +}; +use ark_ff::{One, PrimeField, Zero}; + +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use std::{string::ToString, vec::Vec}; + +/// Reads a single `Fp` field element from the input slice. +/// +/// Takes a byte slice in Big Endian format and attempts to interpret it as an +/// elliptic curve field element. Returns an error if the bytes do not form +/// a valid field element. +/// +/// # Panics +/// +/// Panics if the input is not exactly 48 bytes long. +#[inline] +pub(super) fn read_fp(input_be: &[u8]) -> Result { + assert_eq!(input_be.len(), FP_LENGTH, "input must be {FP_LENGTH} bytes"); + + let mut input_le = [0u8; FP_LENGTH]; + input_le.copy_from_slice(input_be); + + // Reverse in-place to convert from big-endian to little-endian. + input_le.reverse(); + + Fq::deserialize_uncompressed(&input_le[..]) + .map_err(|_| PrecompileError::Other("non-canonical fp value".to_string())) +} + +/// Reads a Fp2 (quadratic extension field element) from the input slices. +/// +/// Parses two Fp field elements in Big Endian format for the Fp2 element. +/// +/// # Panics +/// +/// Panics if either input is not exactly 48 bytes long. +#[inline] +pub(super) fn read_fp2( + input_1: &[u8; FP_LENGTH], + input_2: &[u8; FP_LENGTH], +) -> Result { + let fp_1 = read_fp(input_1)?; + let fp_2 = read_fp(input_2)?; + + Ok(Fq2::new(fp_1, fp_2)) +} + +/// Creates a new `G1` point from the given `x` and `y` coordinates. +/// +/// Constructs a point on the G1 curve from its affine coordinates. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically. +#[inline] +fn new_g1_point_no_subgroup_check(px: Fq, py: Fq) -> Result { + if px.is_zero() && py.is_zero() { + Ok(G1Affine::zero()) + } else { + // We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve. + let point = G1Affine::new_unchecked(px, py); + if !point.is_on_curve() { + return Err(PrecompileError::Other( + "Element not on G1 curve".to_string(), + )); + } + Ok(point) + } +} + +/// Creates a new `G2` point from the given Fq2 coordinates. +/// +/// G2 points in BLS12_381 are defined over a quadratic extension field Fq2. +/// This function takes two Fq2 elements representing the x and y coordinates +/// and creates a G2 point. +/// +/// Note: The point at infinity which is represented as (0,0) is +/// handled specifically. +#[inline] +fn new_g2_point_no_subgroup_check(x: Fq2, y: Fq2) -> Result { + let point = if x.is_zero() && y.is_zero() { + G2Affine::zero() + } else { + // We cannot use `G2Affine::new` because that triggers an assert if the point is not on the curve. + let point = G2Affine::new_unchecked(x, y); + if !point.is_on_curve() { + return Err(PrecompileError::Other( + "Element not on G2 curve".to_string(), + )); + } + point + }; + + Ok(point) +} + +/// Reads a G1 point from the input slices. +/// +/// Parses a G1 point from byte slices by reading two field elements +/// representing the x and y coordinates in Big Endian format. +/// Also performs a subgroup check to ensure the point is in the correct subgroup. +/// +/// # Panics +/// +/// Panics if the inputs are not exactly 48 bytes long. +#[inline] +pub(super) fn read_g1( + x: &[u8; FP_LENGTH], + y: &[u8; FP_LENGTH], +) -> Result { + let point = read_g1_no_subgroup_check(x, y)?; + if !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(PrecompileError::Other( + "Element not in the correct subgroup".to_string(), + )); + } + Ok(point) +} + +/// Reads a G1 point without performing a subgroup check. +/// +/// Note: Skipping subgroup checks can introduce security issues. +/// This method should only be called if: +/// - The EIP specifies that no subgroup check should be performed +/// - One can be certain that the point is in the correct subgroup. +#[inline] +pub(super) fn read_g1_no_subgroup_check( + x: &[u8; FP_LENGTH], + y: &[u8; FP_LENGTH], +) -> Result { + let px = read_fp(x)?; + let py = read_fp(y)?; + new_g1_point_no_subgroup_check(px, py) +} + +/// Encodes a G1 point into a byte array with padded elements. +/// +/// Converts a G1 point to affine coordinates and serializes the x and y coordinates +/// as big-endian byte arrays with padding to match the expected format. +#[inline] +pub(super) fn encode_g1_point(input: &G1Affine) -> [u8; PADDED_G1_LENGTH] { + let mut output = [0u8; PADDED_G1_LENGTH]; + + let Some((x, y)) = input.xy() else { + return output; // Point at infinity, return all zeros + }; + + let mut x_bytes = [0u8; FP_LENGTH]; + x.serialize_uncompressed(&mut x_bytes[..]) + .expect("Failed to serialize x coordinate"); + + let mut y_bytes = [0u8; FP_LENGTH]; + y.serialize_uncompressed(&mut y_bytes[..]) + .expect("Failed to serialize y coordinate"); + + // Convert to big endian by reversing the bytes. + x_bytes.reverse(); + y_bytes.reverse(); + + // Add padding and place x in the first half, y in the second half. + output[FP_PAD_BY..PADDED_FP_LENGTH].copy_from_slice(&x_bytes); + output[PADDED_FP_LENGTH + FP_PAD_BY..].copy_from_slice(&y_bytes); + + output +} + +/// Reads a G2 point from the input slices. +/// +/// Parses a G2 point from byte slices by reading four field elements +/// representing the x and y coordinates in Big Endian format. +/// Also performs a subgroup check to ensure the point is in the correct subgroup. +#[inline] +pub(super) fn read_g2( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], +) -> Result { + let point = read_g2_no_subgroup_check(a_x_0, a_x_1, a_y_0, a_y_1)?; + if !point.is_in_correct_subgroup_assuming_on_curve() { + return Err(PrecompileError::Other( + "Element not in the correct subgroup".to_string(), + )); + } + Ok(point) +} + +/// Reads a G2 point without performing a subgroup check. +/// +/// Note: Skipping subgroup checks can introduce security issues. +/// This method should only be called if: +/// - The EIP specifies that no subgroup check should be performed +/// - One can be certain that the point is in the correct subgroup. +#[inline] +pub(super) fn read_g2_no_subgroup_check( + a_x_0: &[u8; FP_LENGTH], + a_x_1: &[u8; FP_LENGTH], + a_y_0: &[u8; FP_LENGTH], + a_y_1: &[u8; FP_LENGTH], +) -> Result { + let x = read_fp2(a_x_0, a_x_1)?; + let y = read_fp2(a_y_0, a_y_1)?; + new_g2_point_no_subgroup_check(x, y) +} + +/// Encodes a G2 point into a byte array with padded elements. +/// +/// Converts a G2 point to affine coordinates and serializes the coordinates +/// as big-endian byte arrays with padding to match the expected format. +#[inline] +pub(super) fn encode_g2_point(input: &G2Affine) -> [u8; PADDED_G2_LENGTH] { + let mut output = [0u8; PADDED_G2_LENGTH]; + + let Some((x, y)) = input.xy() else { + return output; // Point at infinity, return all zeros + }; + + // Serialize coordinates + let mut x_c0_bytes = [0u8; FP_LENGTH]; + let mut x_c1_bytes = [0u8; FP_LENGTH]; + let mut y_c0_bytes = [0u8; FP_LENGTH]; + let mut y_c1_bytes = [0u8; FP_LENGTH]; + + x.c0.serialize_uncompressed(&mut x_c0_bytes[..]) + .expect("Failed to serialize x.c0 coordinate"); + x.c1.serialize_uncompressed(&mut x_c1_bytes[..]) + .expect("Failed to serialize x.c1 coordinate"); + y.c0.serialize_uncompressed(&mut y_c0_bytes[..]) + .expect("Failed to serialize y.c0 coordinate"); + y.c1.serialize_uncompressed(&mut y_c1_bytes[..]) + .expect("Failed to serialize y.c1 coordinate"); + + // Convert to big endian by reversing the bytes + x_c0_bytes.reverse(); + x_c1_bytes.reverse(); + y_c0_bytes.reverse(); + y_c1_bytes.reverse(); + + // Add padding and copy to output + output[FP_PAD_BY..PADDED_FP_LENGTH].copy_from_slice(&x_c0_bytes); + output[PADDED_FP_LENGTH + FP_PAD_BY..2 * PADDED_FP_LENGTH].copy_from_slice(&x_c1_bytes); + output[2 * PADDED_FP_LENGTH + FP_PAD_BY..3 * PADDED_FP_LENGTH].copy_from_slice(&y_c0_bytes); + output[3 * PADDED_FP_LENGTH + FP_PAD_BY..4 * PADDED_FP_LENGTH].copy_from_slice(&y_c1_bytes); + + output +} + +/// Extracts a scalar from a byte slice representation, decoding the input as a Big Endian +/// unsigned integer. +/// +/// Note: We do not check that the scalar is a canonical Fr element, because the EIP specifies: +/// * The corresponding integer is not required to be less than or equal than main subgroup order. +#[inline] +pub(super) fn read_scalar(input: &[u8]) -> Result { + if input.len() != SCALAR_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {SCALAR_LENGTH} bytes, was {}", + input.len() + ))); + } + + Ok(Fr::from_be_bytes_mod_order(input)) +} + +/// Performs point addition on two G1 points. +#[inline] +pub(super) fn p1_add_affine(p1: &G1Affine, p2: &G1Affine) -> G1Affine { + let p1_proj: G1Projective = (*p1).into(); + let p3 = p1_proj + p2; + p3.into_affine() +} + +/// Performs point addition on two G2 points. +#[inline] +pub(super) fn p2_add_affine(p1: &G2Affine, p2: &G2Affine) -> G2Affine { + let p1_proj: G2Projective = (*p1).into(); + let p3 = p1_proj + p2; + p3.into_affine() +} + +/// Performs multi-scalar multiplication (MSM) for G1 points +/// +/// Takes a vector of G1 points and corresponding scalars, and returns their weighted sum +/// +/// Note: This method assumes that `g1_points` does not contain any points at infinity. +#[inline] +pub(super) fn p1_msm(g1_points: Vec, scalars: Vec, _nbits: usize) -> G1Affine { + assert_eq!( + g1_points.len(), + scalars.len(), + "number of scalars should equal the number of g1 points" + ); + + if g1_points.is_empty() { + return G1Affine::zero(); + } + + if g1_points.len() == 1 { + let big_int = scalars[0].into_bigint(); + return g1_points[0].mul_bigint(big_int).into_affine(); + } + + // Perform multi-scalar multiplication + G1Projective::msm(&g1_points, &scalars) + .expect("MSM should succeed") + .into_affine() +} + +/// Performs multi-scalar multiplication (MSM) for G2 points +/// +/// Takes a vector of G2 points and corresponding scalars, and returns their weighted sum +/// +/// Note: This method assumes that `g2_points` does not contain any points at infinity. +#[inline] +pub(super) fn p2_msm(g2_points: Vec, scalars: Vec, _nbits: usize) -> G2Affine { + assert_eq!( + g2_points.len(), + scalars.len(), + "number of scalars should equal the number of g2 points" + ); + + if g2_points.is_empty() { + return G2Affine::zero(); + } + + if g2_points.len() == 1 { + let big_int = scalars[0].into_bigint(); + return g2_points[0].mul_bigint(big_int).into_affine(); + } + + // Perform multi-scalar multiplication + G2Projective::msm(&g2_points, &scalars) + .expect("MSM should succeed") + .into_affine() +} + +/// Maps a field element to a G1 point +/// +/// Takes a field element (Fq) and returns the corresponding G1 point in affine form +#[inline] +pub(super) fn map_fp_to_g1(fp: &Fq) -> G1Affine { + WBMap::map_to_curve(*fp) + .expect("map_to_curve is infallible") + .clear_cofactor() +} + +/// Maps a field element to a G2 point +/// +/// Takes a field element (Fq2) and returns the corresponding G2 point in affine form +#[inline] +pub(super) fn map_fp2_to_g2(fp2: &Fq2) -> G2Affine { + WBMap::map_to_curve(*fp2) + .expect("map_to_curve is infallible") + .clear_cofactor() +} + +/// pairing_check performs a pairing check on a list of G1 and G2 point pairs and +/// returns true if the result is equal to the identity element. +#[inline] +pub(super) fn pairing_check(pairs: &[(G1Affine, G2Affine)]) -> bool { + if pairs.is_empty() { + return true; + } + + let (g1_points, g2_points): (Vec, Vec) = pairs.iter().copied().unzip(); + + let pairing_result = Bls12_381::multi_pairing(&g1_points, &g2_points); + pairing_result.0.is_one() +} diff --git a/crates/precompile/src/bls12_381/blst.rs b/crates/precompile/src/bls12_381/blst.rs index 8d998e2e02..d0193d5e2d 100644 --- a/crates/precompile/src/bls12_381/blst.rs +++ b/crates/precompile/src/bls12_381/blst.rs @@ -15,6 +15,8 @@ use blst::{ blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve, blst_p2_from_affine, blst_p2_mult, blst_p2_to_affine, blst_scalar, blst_scalar_from_bendian, MultiPoint, }; +use std::string::ToString; +use std::vec::Vec; #[inline] fn p1_to_affine(p: &blst_p1) -> blst_p1_affine { diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs index ab00cac035..19e62cd213 100644 --- a/crates/precompile/src/bls12_381/g1_add.rs +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -1,4 +1,4 @@ -use super::blst::{encode_g1_point, p1_add_affine, read_g1_no_subgroup_check}; +use super::crypto_backend::{encode_g1_point, p1_add_affine, read_g1_no_subgroup_check}; use super::utils::remove_g1_padding; use crate::bls12_381_const::{ G1_ADD_ADDRESS, G1_ADD_BASE_GAS_FEE, G1_ADD_INPUT_LENGTH, PADDED_G1_LENGTH, diff --git a/crates/precompile/src/bls12_381/g1_msm.rs b/crates/precompile/src/bls12_381/g1_msm.rs index a0d6435878..d4af8e8368 100644 --- a/crates/precompile/src/bls12_381/g1_msm.rs +++ b/crates/precompile/src/bls12_381/g1_msm.rs @@ -1,4 +1,4 @@ -use super::blst::{encode_g1_point, p1_msm, read_g1, read_scalar}; +use super::crypto_backend::{encode_g1_point, p1_msm, read_g1, read_scalar}; use crate::bls12_381::utils::remove_g1_padding; use crate::bls12_381_const::{ DISCOUNT_TABLE_G1_MSM, G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE, G1_MSM_INPUT_LENGTH, NBITS, @@ -7,6 +7,7 @@ use crate::bls12_381_const::{ use crate::bls12_381_utils::msm_required_gas; use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; use primitives::Bytes; +use std::vec::Vec; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MSM precompile. pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G1_MSM_ADDRESS, g1_msm); diff --git a/crates/precompile/src/bls12_381/g2_add.rs b/crates/precompile/src/bls12_381/g2_add.rs index 6edc1b57e7..ae96838443 100644 --- a/crates/precompile/src/bls12_381/g2_add.rs +++ b/crates/precompile/src/bls12_381/g2_add.rs @@ -1,4 +1,4 @@ -use super::blst::{encode_g2_point, p2_add_affine, read_g2_no_subgroup_check}; +use super::crypto_backend::{encode_g2_point, p2_add_affine, read_g2_no_subgroup_check}; use super::utils::remove_g2_padding; use crate::bls12_381_const::{ G2_ADD_ADDRESS, G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH, PADDED_G2_LENGTH, diff --git a/crates/precompile/src/bls12_381/g2_msm.rs b/crates/precompile/src/bls12_381/g2_msm.rs index 9bb437ac21..548fbeef60 100644 --- a/crates/precompile/src/bls12_381/g2_msm.rs +++ b/crates/precompile/src/bls12_381/g2_msm.rs @@ -1,4 +1,4 @@ -use super::blst::{encode_g2_point, p2_msm, read_g2, read_scalar}; +use super::crypto_backend::{encode_g2_point, p2_msm, read_g2, read_scalar}; use super::utils::remove_g2_padding; use crate::bls12_381_const::{ DISCOUNT_TABLE_G2_MSM, G2_MSM_ADDRESS, G2_MSM_BASE_GAS_FEE, G2_MSM_INPUT_LENGTH, NBITS, @@ -7,6 +7,7 @@ use crate::bls12_381_const::{ use crate::bls12_381_utils::msm_required_gas; use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; use primitives::Bytes; +use std::vec::Vec; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MSM precompile. pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_MSM_ADDRESS, g2_msm); diff --git a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs index fcd7c902a1..68332753d0 100644 --- a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs +++ b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs @@ -1,5 +1,5 @@ use super::{ - blst::{encode_g2_point, map_fp2_to_g2 as blst_map_fp2_to_g2, read_fp2}, + crypto_backend::{encode_g2_point, map_fp2_to_g2 as blst_map_fp2_to_g2, read_fp2}, utils::remove_fp_padding, }; use crate::bls12_381_const::{ diff --git a/crates/precompile/src/bls12_381/map_fp_to_g1.rs b/crates/precompile/src/bls12_381/map_fp_to_g1.rs index b9dc0fd537..5bbddebced 100644 --- a/crates/precompile/src/bls12_381/map_fp_to_g1.rs +++ b/crates/precompile/src/bls12_381/map_fp_to_g1.rs @@ -1,5 +1,5 @@ use super::{ - blst::{encode_g1_point, map_fp_to_g1 as blst_map_fp_to_g1, read_fp}, + crypto_backend::{encode_g1_point, map_fp_to_g1 as blst_map_fp_to_g1, read_fp}, utils::remove_fp_padding, }; use crate::bls12_381_const::{MAP_FP_TO_G1_ADDRESS, MAP_FP_TO_G1_BASE_GAS_FEE, PADDED_FP_LENGTH}; diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index 04a8a3dd96..118889e219 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -1,4 +1,4 @@ -use super::blst::{pairing_check, read_g1, read_g2}; +use super::crypto_backend::{pairing_check, read_g1, read_g2}; use super::utils::{remove_g1_padding, remove_g2_padding}; use crate::bls12_381_const::{ PADDED_G1_LENGTH, PADDED_G2_LENGTH, PAIRING_ADDRESS, PAIRING_INPUT_LENGTH, @@ -6,6 +6,7 @@ use crate::bls12_381_const::{ }; use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; use primitives::{Bytes, B256}; +use std::vec::Vec; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_PAIRING precompile. pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(PAIRING_ADDRESS, pairing); diff --git a/crates/precompile/src/bls12_381_utils.rs b/crates/precompile/src/bls12_381_utils.rs index dc6faa9024..dc1ef26088 100644 --- a/crates/precompile/src/bls12_381_utils.rs +++ b/crates/precompile/src/bls12_381_utils.rs @@ -1,9 +1,12 @@ -use crate::bls12_381_const::{ - G1_ADD_ADDRESS, G1_MSM_ADDRESS, G2_ADD_ADDRESS, G2_MSM_ADDRESS, MAP_FP2_TO_G2_ADDRESS, - MAP_FP_TO_G1_ADDRESS, MSM_MULTIPLIER, PAIRING_ADDRESS, +use crate::{ + bls12_381_const::{ + G1_ADD_ADDRESS, G1_MSM_ADDRESS, G2_ADD_ADDRESS, G2_MSM_ADDRESS, MAP_FP2_TO_G2_ADDRESS, + MAP_FP_TO_G1_ADDRESS, MSM_MULTIPLIER, PAIRING_ADDRESS, + }, + PrecompileError, PrecompileWithAddress, }; -use crate::Vec; -use crate::{PrecompileError, PrecompileWithAddress}; +use std::vec::Vec; + /// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30 /// MGas/second, see also: #[inline] diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 823affbf96..b5655109f7 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -9,7 +9,6 @@ extern crate alloc as std; pub mod blake2; -#[cfg(feature = "blst")] pub mod bls12_381; pub mod bls12_381_const; pub mod bls12_381_utils; @@ -41,6 +40,16 @@ cfg_if::cfg_if! { // silence kzg-rs lint as c-kzg will be used as default if both are enabled. use kzg_rs as _; +// silence arkworks-bls12-381 lint as blst will be used as default if both are enabled. +cfg_if::cfg_if! { + if #[cfg(feature = "blst")]{ + use ark_bls12_381 as _; + use ark_ff as _; + use ark_ec as _; + use ark_serialize as _; + } +} + use cfg_if::cfg_if; use core::hash::Hash; use once_cell::race::OnceBox; @@ -173,16 +182,7 @@ impl Precompiles { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::cancun().clone(); - - cfg_if! { - if #[cfg(feature = "blst")] { // if blst is enabled - let bls = bls12_381::precompiles(); - } else { - let bls = bls12_381_utils:: bls12_381_precompiles_not_supported(); - } - } - precompiles.extend(bls); - + precompiles.extend(bls12_381::precompiles()); Box::new(precompiles) }) }