From 5f79959eb9805259e04b3d6a23ca299ae90b234b Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 8 May 2024 14:51:13 +0100 Subject: [PATCH 01/10] feat(precompile): add Prague hardfork specification --- crates/precompile/src/lib.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 4dc6cae518..5c9ff613f6 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -63,6 +63,7 @@ impl Precompiles { PrecompileSpecId::ISTANBUL => Self::istanbul(), PrecompileSpecId::BERLIN => Self::berlin(), PrecompileSpecId::CANCUN => Self::cancun(), + PrecompileSpecId::PRAGUE => Self::prague(), PrecompileSpecId::LATEST => Self::latest(), } } @@ -154,9 +155,31 @@ impl Precompiles { }) } + /// Returns precompiles for Prague spec. + pub fn prague() -> &'static Self { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = Self::cancun().clone(); + precompiles.extend([ + // EIP-2537: Precompile for BLS12-381 curve operations + // TODO(alexey): add BLS12-381 precompiles + // bls12_381::G1ADD, + // bls12_381::G1MUL, + // bls12_381::G1MSM, + // bls12_381::G2ADD, + // bls12_381::G2MUL, + // bls12_381::G2MSM, + // bls12_381::PAIRING, + // bls12_381::MAP_FP_TO_G1, + // bls12_381::MAP_FP2_TO_G2, + ]); + Box::new(precompiles) + }) + } + /// Returns the precompiles for the latest spec. pub fn latest() -> &'static Self { - Self::cancun() + Self::prague() } /// Returns an iterator over the precompiles addresses. @@ -229,6 +252,7 @@ pub enum PrecompileSpecId { ISTANBUL, BERLIN, CANCUN, + PRAGUE, LATEST, } @@ -243,7 +267,8 @@ impl PrecompileSpecId { BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM, ISTANBUL | MUIR_GLACIER => Self::ISTANBUL, BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN, - CANCUN | PRAGUE => Self::CANCUN, + CANCUN => Self::CANCUN, + PRAGUE => Self::PRAGUE, LATEST => Self::LATEST, #[cfg(feature = "optimism")] BEDROCK | REGOLITH | CANYON => Self::BERLIN, From bcd6e4a88f73be7c565d8528e51b878b19369cd3 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 8 May 2024 14:51:13 +0100 Subject: [PATCH 02/10] feat(precompile): add Prague hardfork specification --- crates/precompile/src/lib.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 4dc6cae518..7903d38b27 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -63,6 +63,7 @@ impl Precompiles { PrecompileSpecId::ISTANBUL => Self::istanbul(), PrecompileSpecId::BERLIN => Self::berlin(), PrecompileSpecId::CANCUN => Self::cancun(), + PrecompileSpecId::PRAGUE => Self::prague(), PrecompileSpecId::LATEST => Self::latest(), } } @@ -154,9 +155,21 @@ impl Precompiles { }) } + /// Returns precompiles for Prague spec. + pub fn prague() -> &'static Self { + static INSTANCE: OnceBox = OnceBox::new(); + INSTANCE.get_or_init(|| { + let precompiles = Self::cancun().clone(); + // EIP-2537: Precompile for BLS12-381 curve operations + // TODO(alexey): add BLS12-381 precompiles + // precompiles.extend(bls12_381::precompiles()); + Box::new(precompiles) + }) + } + /// Returns the precompiles for the latest spec. pub fn latest() -> &'static Self { - Self::cancun() + Self::prague() } /// Returns an iterator over the precompiles addresses. @@ -229,6 +242,7 @@ pub enum PrecompileSpecId { ISTANBUL, BERLIN, CANCUN, + PRAGUE, LATEST, } @@ -243,7 +257,8 @@ impl PrecompileSpecId { BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM, ISTANBUL | MUIR_GLACIER => Self::ISTANBUL, BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN, - CANCUN | PRAGUE => Self::CANCUN, + CANCUN => Self::CANCUN, + PRAGUE => Self::PRAGUE, LATEST => Self::LATEST, #[cfg(feature = "optimism")] BEDROCK | REGOLITH | CANYON => Self::BERLIN, From 614d84a81d9947718939ba9f3556ae302429474e Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 8 May 2024 16:49:26 +0100 Subject: [PATCH 03/10] feat(precompile): BLS12-381 --- Cargo.lock | 1 + crates/precompile/Cargo.toml | 3 + crates/precompile/src/bls12_381/g1.rs | 53 ++++++++++ crates/precompile/src/bls12_381/g1_add.rs | 66 +++++++++++++ crates/precompile/src/bls12_381/g1_msm.rs | 81 ++++++++++++++++ crates/precompile/src/bls12_381/g1_mul.rs | 64 +++++++++++++ crates/precompile/src/bls12_381/g2.rs | 66 +++++++++++++ crates/precompile/src/bls12_381/g2_add.rs | 67 +++++++++++++ crates/precompile/src/bls12_381/g2_msm.rs | 81 ++++++++++++++++ crates/precompile/src/bls12_381/g2_mul.rs | 64 +++++++++++++ .../precompile/src/bls12_381/map_fp2_to_g2.rs | 78 +++++++++++++++ .../precompile/src/bls12_381/map_fp_to_g1.rs | 65 +++++++++++++ crates/precompile/src/bls12_381/mod.rs | 31 ++++++ crates/precompile/src/bls12_381/msm.rs | 28 ++++++ crates/precompile/src/bls12_381/pairing.rs | 96 +++++++++++++++++++ crates/precompile/src/bls12_381/utils.rs | 65 +++++++++++++ crates/precompile/src/lib.rs | 6 +- 17 files changed, 912 insertions(+), 3 deletions(-) create mode 100644 crates/precompile/src/bls12_381/g1.rs create mode 100644 crates/precompile/src/bls12_381/g1_add.rs create mode 100644 crates/precompile/src/bls12_381/g1_msm.rs create mode 100644 crates/precompile/src/bls12_381/g1_mul.rs create mode 100644 crates/precompile/src/bls12_381/g2.rs create mode 100644 crates/precompile/src/bls12_381/g2_add.rs create mode 100644 crates/precompile/src/bls12_381/g2_msm.rs create mode 100644 crates/precompile/src/bls12_381/g2_mul.rs create mode 100644 crates/precompile/src/bls12_381/map_fp2_to_g2.rs create mode 100644 crates/precompile/src/bls12_381/map_fp_to_g1.rs create mode 100644 crates/precompile/src/bls12_381/mod.rs create mode 100644 crates/precompile/src/bls12_381/msm.rs create mode 100644 crates/precompile/src/bls12_381/pairing.rs create mode 100644 crates/precompile/src/bls12_381/utils.rs diff --git a/Cargo.lock b/Cargo.lock index b10795368b..61700cc0ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2963,6 +2963,7 @@ name = "revm-precompile" version = "6.0.0" dependencies = [ "aurora-engine-modexp", + "blst", "c-kzg", "criterion", "k256", diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 8c7c7e6fcb..1f4bee6a15 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -41,6 +41,9 @@ secp256k1 = { version = "0.29.0", default-features = false, features = [ "global-context", ], optional = true } +# BLS12-381 precompiles +blst = "0.3.11" + [dev-dependencies] criterion = { version = "0.5" } rand = { version = "0.8", features = ["std"] } diff --git a/crates/precompile/src/bls12_381/g1.rs b/crates/precompile/src/bls12_381/g1.rs new file mode 100644 index 0000000000..1cc2683084 --- /dev/null +++ b/crates/precompile/src/bls12_381/g1.rs @@ -0,0 +1,53 @@ +use blst::{blst_fp_from_bendian, blst_p1_affine, blst_p1_affine_in_g1}; +use revm_primitives::PrecompileError; + +use super::utils::{fp_to_bytes, remove_padding, PADDED_FP_LENGTH}; + +/// Length of each of the elements in a g1 operation input. +pub(super) const G1_INPUT_ITEM_LENGTH: usize = 128; +/// Output length of a g1 operation. +pub(super) const G1_OUTPUT_LENGTH: usize = 128; + +/// Encodes a G1 point in affine format into a byte slice with padded elements. +pub(super) fn encode_g1_point(out: &mut [u8], input: *const blst_p1_affine) { + // SAFETY: out comes from fixed length array, x and y are blst values. + unsafe { + fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &(*input).x); + fp_to_bytes(&mut out[PADDED_FP_LENGTH..], &(*input).y); + } +} + +/// Extracts a G1 point in Affine format from a 128 byte slice representation. +pub(super) fn extract_g1_input( + out: *mut blst_p1_affine, + input: &[u8], +) -> Result<*mut blst_p1_affine, PrecompileError> { + if input.len() != G1_INPUT_ITEM_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {G1_INPUT_ITEM_LENGTH} bits, was {}", + input.len() + ))); + } + + let input_p0_x = match remove_padding(&input[..PADDED_FP_LENGTH]) { + Ok(input_p0_x) => input_p0_x, + Err(e) => return Err(e), + }; + let input_p0_y = match remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH]) { + Ok(input_p0_y) => input_p0_y, + Err(e) => return Err(e), + }; + + // SAFETY: input_p0_x and input_p0_y have fixed length, x and y are blst values. + unsafe { + blst_fp_from_bendian(&mut (*out).x, input_p0_x.as_ptr()); + blst_fp_from_bendian(&mut (*out).y, input_p0_y.as_ptr()); + } + // SAFETY: out is a blst value. + unsafe { + if !blst_p1_affine_in_g1(out) { + return Err(PrecompileError::Other("Element not in G1".to_string())); + } + } + Ok(out) +} diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs new file mode 100644 index 0000000000..f2c0ec5a78 --- /dev/null +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -0,0 +1,66 @@ +use blst::{ + blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, +}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1ADD precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_add)); +// BLS12_G1ADD precompile address. +pub const ADDRESS: u64 = 0x0b; +/// Base gas fee for BLS12-381 g1_add operation. +const BASE_GAS_FEE: u64 = 500; + +/// Input length of g1_add operation. +const INPUT_LENGTH: usize = 256; + +/// G1 addition call expects `256` bytes as an input that is interpreted as byte +/// concatenation of two G1 points (`128` bytes each). +/// Output is an encoding of addition operation result - single G1 point (`128` +/// bytes). +/// See also: +fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != INPUT_LENGTH { + return Err(PrecompileError::Other(format!( + "G1ADD Input should be {INPUT_LENGTH} bits, was {}", + input.len() + ))); + } + + let mut a_aff: blst_p1_affine = Default::default(); + let a_aff = extract_g1_input(&mut a_aff, &input[..G1_INPUT_ITEM_LENGTH])?; + + let mut b_aff: blst_p1_affine = Default::default(); + let b_aff = extract_g1_input(&mut b_aff, &input[G1_INPUT_ITEM_LENGTH..])?; + + let mut b: blst_p1 = Default::default(); + // SAFETY: b and b_aff are blst values. + unsafe { + blst_p1_from_affine(&mut b, b_aff); + } + + let mut p: blst_p1 = Default::default(); + // SAFETY: p, b and a_aff are blst values. + unsafe { + blst_p1_add_or_double_affine(&mut p, &b, a_aff); + } + + let mut p_aff: blst_p1_affine = Default::default(); + // SAFETY: p_aff and p are blst values. + unsafe { + blst_p1_to_affine(&mut p_aff, &p); + } + + let mut out = [0u8; G1_OUTPUT_LENGTH]; + encode_g1_point(&mut out, &p_aff); + + Ok((BASE_GAS_FEE, out.into())) +} diff --git a/crates/precompile/src/bls12_381/g1_msm.rs b/crates/precompile/src/bls12_381/g1_msm.rs new file mode 100644 index 0000000000..ffc03c5260 --- /dev/null +++ b/crates/precompile/src/bls12_381/g1_msm.rs @@ -0,0 +1,81 @@ +use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, p1_affines}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH}, + g1_mul, + msm::msm_required_gas, + utils::{extract_scalar_input, NBITS, SCALAR_LENGTH}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MSM precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_msm)); +/// BLS12_G1MSM precompile address. +pub const ADDRESS: u64 = 0x0d; + +/// Implements EIP-2537 G1MSM precompile. +/// G1 multi-scalar-multiplication call expects `160*k` bytes as an input that is interpreted +/// as byte concatenation of `k` slices each of them being a byte concatenation +/// of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` +/// bytes). +/// Output is an encoding of multi-scalar-multiplication operation result - single G1 +/// point (`128` bytes). +/// See also: +fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { + let input_len = input.len(); + if input_len == 0 || input_len % g1_mul::INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(format!( + "G1MSM input length should be multiple of {}, was {}", + g1_mul::INPUT_LENGTH, + input_len + ))); + } + + let k = input_len / g1_mul::INPUT_LENGTH; + let required_gas = msm_required_gas(k, g1_mul::BASE_GAS_FEE); + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let mut g1_points: Vec = Vec::with_capacity(k); + let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); + for i in 0..k { + let mut p0_aff: blst_p1_affine = Default::default(); + let p0_aff = extract_g1_input( + &mut p0_aff, + &input[i * g1_mul::INPUT_LENGTH..i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], + )?; + let mut p0: blst_p1 = Default::default(); + // SAFETY: p0 and p0_aff are blst values. + unsafe { + blst_p1_from_affine(&mut p0, p0_aff); + } + + g1_points.push(p0); + + scalars.extend_from_slice( + &extract_scalar_input( + &input[i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + ..i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + SCALAR_LENGTH], + )? + .b, + ); + } + + let points = p1_affines::from(&g1_points); + let multiexp = points.mult(&scalars, NBITS); + + let mut multiexp_aff: blst_p1_affine = Default::default(); + // SAFETY: multiexp_aff and multiexp are blst values. + unsafe { + blst_p1_to_affine(&mut multiexp_aff, &multiexp); + } + + let mut out = [0u8; G1_OUTPUT_LENGTH]; + encode_g1_point(&mut out, &multiexp_aff); + + Ok((required_gas, out.into())) +} diff --git a/crates/precompile/src/bls12_381/g1_mul.rs b/crates/precompile/src/bls12_381/g1_mul.rs new file mode 100644 index 0000000000..ef7c836a3c --- /dev/null +++ b/crates/precompile/src/bls12_381/g1_mul.rs @@ -0,0 +1,64 @@ +use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_mult, blst_p1_to_affine}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH}, + utils::{extract_scalar_input, NBITS}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MUL precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_mul)); +/// BLS12_G1MUL precompile address. +pub const ADDRESS: u64 = 0x0c; +/// Base gas fee for BLS12-381 g1_mul operation. +pub(super) const BASE_GAS_FEE: u64 = 12000; + +/// Input length of g1_mul operation. +pub(super) const INPUT_LENGTH: usize = 160; + +/// G1 multiplication call expects `160` bytes as an input that is interpreted as +/// byte concatenation of encoding of G1 point (`128` bytes) and encoding of a +/// scalar value (`32` bytes). +/// Output is an encoding of multiplication operation result - single G1 point +/// (`128` bytes). +/// See also: +pub fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + if input.len() != INPUT_LENGTH { + return Err(PrecompileError::Other(format!( + "G1MUL Input should be {INPUT_LENGTH} bits, was {}", + input.len() + ))); + } + + let mut p0_aff: blst_p1_affine = Default::default(); + let p0_aff = extract_g1_input(&mut p0_aff, &input[..G1_INPUT_ITEM_LENGTH])?; + let mut p0: blst_p1 = Default::default(); + // SAFETY: p0 and p0_aff are blst values. + unsafe { + blst_p1_from_affine(&mut p0, p0_aff); + } + + let input_scalar0 = extract_scalar_input(&input[G1_INPUT_ITEM_LENGTH..])?; + + let mut p: blst_p1 = Default::default(); + // SAFETY: input_scalar0.b has fixed size, p and p0 are blst values. + unsafe { + blst_p1_mult(&mut p, &p0, input_scalar0.b.as_ptr(), NBITS); + } + let mut p_aff: blst_p1_affine = Default::default(); + // SAFETY: p_aff and p are blst values. + unsafe { + blst_p1_to_affine(&mut p_aff, &p); + } + + let mut out = [0u8; G1_OUTPUT_LENGTH]; + encode_g1_point(&mut out, &p_aff); + + Ok((BASE_GAS_FEE, out.into())) +} diff --git a/crates/precompile/src/bls12_381/g2.rs b/crates/precompile/src/bls12_381/g2.rs new file mode 100644 index 0000000000..39f99df59f --- /dev/null +++ b/crates/precompile/src/bls12_381/g2.rs @@ -0,0 +1,66 @@ +use blst::{blst_fp_from_bendian, blst_p2_affine, blst_p2_affine_in_g2}; +use revm_primitives::PrecompileError; + +use super::utils::{fp_to_bytes, remove_padding, FP_LENGTH, PADDED_FP_LENGTH}; + +/// Length of each of the elements in a g2 operation input. +pub(super) const G2_INPUT_ITEM_LENGTH: usize = 256; +/// Output length of a g2 operation. +pub(super) const G2_OUTPUT_LENGTH: usize = 256; + +/// Encodes a G2 point in affine format into a byte slice with padded elements. +pub(super) fn encode_g2_point(out: &mut [u8], input: *const blst_p2_affine) { + // SAFETY: out comes from fixed length array, input is a blst value. + unsafe { + fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &(*input).x.fp[0]); + fp_to_bytes( + &mut out[PADDED_FP_LENGTH..2 * PADDED_FP_LENGTH], + &(*input).x.fp[1], + ); + fp_to_bytes( + &mut out[2 * PADDED_FP_LENGTH..3 * PADDED_FP_LENGTH], + &(*input).y.fp[0], + ); + fp_to_bytes( + &mut out[3 * PADDED_FP_LENGTH..4 * PADDED_FP_LENGTH], + &(*input).y.fp[1], + ); + } +} + +/// Extracts a G2 point in Affine format from a 256 byte slice representation. +pub(super) fn extract_g2_input( + out: *mut blst_p2_affine, + input: &[u8], +) -> Result<*mut blst_p2_affine, PrecompileError> { + if input.len() != G2_INPUT_ITEM_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {G2_INPUT_ITEM_LENGTH} bits, was {}", + input.len() + ))); + } + + let mut input_fps: [[u8; FP_LENGTH]; 4] = [[0; FP_LENGTH]; 4]; + for i in 0..4 { + input_fps[i] = + match remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH]) { + Ok(fp_0) => fp_0, + Err(e) => return Err(e), + }; + } + + // SAFETY: items in fps have fixed length, out is a blst value. + unsafe { + blst_fp_from_bendian(&mut (*out).x.fp[0], input_fps[0].as_ptr()); + blst_fp_from_bendian(&mut (*out).x.fp[1], input_fps[1].as_ptr()); + blst_fp_from_bendian(&mut (*out).y.fp[0], input_fps[2].as_ptr()); + blst_fp_from_bendian(&mut (*out).y.fp[1], input_fps[3].as_ptr()); + } + // SAFETY: out is a blst value. + unsafe { + if !blst_p2_affine_in_g2(out) { + return Err(PrecompileError::Other("Element not in G2".to_string())); + } + } + Ok(out) +} diff --git a/crates/precompile/src/bls12_381/g2_add.rs b/crates/precompile/src/bls12_381/g2_add.rs new file mode 100644 index 0000000000..4a159239fb --- /dev/null +++ b/crates/precompile/src/bls12_381/g2_add.rs @@ -0,0 +1,67 @@ +use blst::{ + blst_p2, blst_p2_add_or_double_affine, blst_p2_affine, blst_p2_from_affine, blst_p2_to_affine, +}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_add)); +/// BLS12_G2ADD precompile address. +pub const ADDRESS: u64 = 0x0e; +/// Base gas fee for BLS12-381 g2_add operation. +const BASE_GAS_FEE: u64 = 800; + +/// Input length of g2_add operation. +const INPUT_LENGTH: usize = 512; + +/// G2 addition call expects `512` bytes as an input that is interpreted as byte +/// concatenation of two G2 points (`256` bytes each). +/// +/// Output is an encoding of addition operation result - single G2 point (`256` +/// bytes). +/// See also +fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != INPUT_LENGTH { + return Err(PrecompileError::Other(format!( + "G2ADD Input should be {INPUT_LENGTH} bits, was {}", + input.len() + ))); + } + + let mut a_aff: blst_p2_affine = Default::default(); + let a_aff = extract_g2_input(&mut a_aff, &input[..G2_INPUT_ITEM_LENGTH])?; + + let mut b_aff: blst_p2_affine = Default::default(); + let b_aff = extract_g2_input(&mut b_aff, &input[G2_INPUT_ITEM_LENGTH..])?; + + let mut b: blst_p2 = Default::default(); + // SAFETY: b and b_aff are blst values. + unsafe { + blst_p2_from_affine(&mut b, b_aff); + } + + let mut p: blst_p2 = Default::default(); + // SAFETY: p, b and a_aff are blst values. + unsafe { + blst_p2_add_or_double_affine(&mut p, &b, a_aff); + } + + let mut p_aff: blst_p2_affine = Default::default(); + // SAFETY: p_aff and p are blst values. + unsafe { + blst_p2_to_affine(&mut p_aff, &p); + } + + let mut out = [0u8; G2_OUTPUT_LENGTH]; + encode_g2_point(&mut out, &p_aff); + + Ok((BASE_GAS_FEE, out.into())) +} diff --git a/crates/precompile/src/bls12_381/g2_msm.rs b/crates/precompile/src/bls12_381/g2_msm.rs new file mode 100644 index 0000000000..85f7488485 --- /dev/null +++ b/crates/precompile/src/bls12_381/g2_msm.rs @@ -0,0 +1,81 @@ +use blst::{blst_p2, blst_p2_affine, blst_p2_from_affine, blst_p2_to_affine, p2_affines}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH}, + g2_mul, + msm::msm_required_gas, + utils::{extract_scalar_input, NBITS, SCALAR_LENGTH}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MSM precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_msm)); +/// BLS12_G2MSM precompile address. +pub const ADDRESS: u64 = 0x10; + +/// Implements EIP-2537 G2MSM precompile. +/// G2 multi-scalar-multiplication call expects `288*k` bytes as an input that is interpreted +/// as byte concatenation of `k` slices each of them being a byte concatenation +/// of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` +/// bytes). +/// Output is an encoding of multi-scalar-multiplication operation result - single G2 +/// point (`256` bytes). +/// See also: +fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { + let input_len = input.len(); + if input_len == 0 || input_len % g2_mul::INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(format!( + "G2MSM input length should be multiple of {}, was {}", + g2_mul::INPUT_LENGTH, + input_len + ))); + } + + let k = input_len / g2_mul::INPUT_LENGTH; + let required_gas = msm_required_gas(k, g2_mul::BASE_GAS_FEE); + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let mut g2_points: Vec = Vec::with_capacity(k); + let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); + for i in 0..k { + let mut p0_aff: blst_p2_affine = Default::default(); + let p0_aff = extract_g2_input( + &mut p0_aff, + &input[i * g2_mul::INPUT_LENGTH..i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH], + )?; + let mut p0: blst_p2 = Default::default(); + // SAFETY: p0 and p0_aff are blst values. + unsafe { + blst_p2_from_affine(&mut p0, p0_aff); + } + + g2_points.push(p0); + + scalars.extend_from_slice( + &extract_scalar_input( + &input[i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH + ..i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH + SCALAR_LENGTH], + )? + .b, + ); + } + + let points = p2_affines::from(&g2_points); + let multiexp = points.mult(&scalars, NBITS); + + let mut multiexp_aff: blst_p2_affine = Default::default(); + // SAFETY: multiexp_aff and multiexp are blst values. + unsafe { + blst_p2_to_affine(&mut multiexp_aff, &multiexp); + } + + let mut out = [0u8; G2_OUTPUT_LENGTH]; + encode_g2_point(&mut out, &multiexp_aff); + + Ok((required_gas, out.into())) +} diff --git a/crates/precompile/src/bls12_381/g2_mul.rs b/crates/precompile/src/bls12_381/g2_mul.rs new file mode 100644 index 0000000000..707426d30b --- /dev/null +++ b/crates/precompile/src/bls12_381/g2_mul.rs @@ -0,0 +1,64 @@ +use blst::{blst_p2, blst_p2_affine, blst_p2_from_affine, blst_p2_mult, blst_p2_to_affine}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH}, + utils::{extract_scalar_input, NBITS}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MUL precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_mul)); +/// BLS12_G2MUL precompile address. +pub const ADDRESS: u64 = 0x0f; +/// Base gas fee for BLS12-381 g2_mul operation. +pub(super) const BASE_GAS_FEE: u64 = 45000; + +/// Input length of g2_mul operation. +pub(super) const INPUT_LENGTH: usize = 288; + +/// G2 multiplication call expects `288` bytes as an input that is interpreted as +/// byte concatenation of encoding of G2 point (`256` bytes) and encoding of a +/// scalar value (`32` bytes). +/// Output is an encoding of multiplication operation result - single G2 point +/// (`256` bytes). +/// See also: +fn g2_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + if input.len() != INPUT_LENGTH { + return Err(PrecompileError::Other(format!( + "G2MUL Input should be {INPUT_LENGTH} bits, was {}", + input.len() + ))); + } + + let mut p0_aff: blst_p2_affine = Default::default(); + let p0_aff = extract_g2_input(&mut p0_aff, &input[..G2_INPUT_ITEM_LENGTH])?; + let mut p0: blst_p2 = Default::default(); + // SAFETY: p0 and p0_aff are blst values. + unsafe { + blst_p2_from_affine(&mut p0, p0_aff); + } + + let input_scalar0 = extract_scalar_input(&input[G2_INPUT_ITEM_LENGTH..])?; + + let mut p: blst_p2 = Default::default(); + // SAFETY: input_scalar0.b has fixed size, p and p0 are blst values. + unsafe { + blst_p2_mult(&mut p, &p0, input_scalar0.b.as_ptr(), NBITS); + } + let mut p_aff: blst_p2_affine = Default::default(); + // SAFETY: p_aff and p are blst values. + unsafe { + blst_p2_to_affine(&mut p_aff, &p); + } + + let mut out = [0u8; G2_OUTPUT_LENGTH]; + encode_g2_point(&mut out, &p_aff); + + Ok((BASE_GAS_FEE, out.into())) +} diff --git a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs new file mode 100644 index 0000000000..0eb5a7d6f3 --- /dev/null +++ b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs @@ -0,0 +1,78 @@ +use blst::{ + blst_fp, blst_fp2, blst_fp_from_bendian, blst_map_to_g2, blst_p2, blst_p2_affine, + blst_p2_to_affine, +}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g2::{encode_g2_point, G2_OUTPUT_LENGTH}, + utils::{remove_padding, PADDED_FP2_LENGTH, PADDED_FP_LENGTH}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP2_TO_G2 precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(map_fp2_to_g2)); +/// BLS12_MAP_FP2_TO_G2 precompile address. +pub const ADDRESS: u64 = 0x13; +/// Base gas fee for BLS12-381 map_fp2_to_g2 operation. +const BASE_GAS_FEE: u64 = 75000; + +/// Field-to-curve call expects 128 bytes as an input that is interpreted as a +/// an element of Fp2. Output of this call is 256 bytes and is an encoded G2 +/// point. +/// See also: +fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if BASE_GAS_FEE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != PADDED_FP2_LENGTH { + return Err(PrecompileError::Other(format!( + "MAP_FP2_TO_G2 Input should be {PADDED_FP2_LENGTH} bits, was {}", + input.len() + ))); + } + + let input_p0_x = match remove_padding(&input[..PADDED_FP_LENGTH]) { + Ok(input_p0_x) => input_p0_x, + Err(e) => return Err(e), + }; + let input_p0_y = match remove_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH]) { + Ok(input_p0_y) => input_p0_y, + Err(e) => return Err(e), + }; + + let mut fp2: blst_fp2 = Default::default(); + let mut fp_x: blst_fp = Default::default(); + let mut fp_y: blst_fp = Default::default(); + // SAFETY: input_p0_x has fixed length, fp_x is a blst value. + unsafe { + blst_fp_from_bendian(&mut fp_x, input_p0_x.as_ptr()); + } + // SAFETY: input_p0_y has fixed length, fp_y is a blst value. + unsafe { + blst_fp_from_bendian(&mut fp_y, input_p0_y.as_ptr()); + } + fp2.fp[0] = fp_x; + fp2.fp[1] = fp_y; + + let mut p: blst_p2 = Default::default(); + // SAFETY: p and fp2 are blst values. + unsafe { + // third argument is unused if null. + blst_map_to_g2(&mut p, &fp2, std::ptr::null()); + } + + let mut p_aff: blst_p2_affine = Default::default(); + // SAFETY: p_aff and p are blst values. + unsafe { + blst_p2_to_affine(&mut p_aff, &p); + } + + let mut out = [0u8; G2_OUTPUT_LENGTH]; + encode_g2_point(&mut out, &p_aff); + + Ok((BASE_GAS_FEE, out.into())) +} diff --git a/crates/precompile/src/bls12_381/map_fp_to_g1.rs b/crates/precompile/src/bls12_381/map_fp_to_g1.rs new file mode 100644 index 0000000000..dc9c5c1cec --- /dev/null +++ b/crates/precompile/src/bls12_381/map_fp_to_g1.rs @@ -0,0 +1,65 @@ +use blst::{ + blst_fp, blst_fp_from_bendian, blst_map_to_g1, blst_p1, blst_p1_affine, blst_p1_to_affine, +}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g1::{encode_g1_point, G1_OUTPUT_LENGTH}, + utils::{remove_padding, PADDED_FP_LENGTH}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP_TO_G1 precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(map_fp_to_g1)); +/// BLS12_MAP_FP_TO_G1 precompile address. +pub const ADDRESS: u64 = 0x12; +/// Base gas fee for BLS12-381 map_fp_to_g1 operation. +const MAP_FP_TO_G1_BASE: u64 = 5500; + +/// Field-to-curve call expects 64 bytes as an input that is interpreted as an +/// element of Fp. Output of this call is 128 bytes and is an encoded G1 point. +/// See also: +fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if MAP_FP_TO_G1_BASE > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + if input.len() != PADDED_FP_LENGTH { + return Err(PrecompileError::Other(format!( + "MAP_FP_TO_G1 Input should be {PADDED_FP_LENGTH} bits, was {}", + input.len() + ))); + } + + let input_p0 = match remove_padding(input) { + Ok(input_p0) => input_p0, + Err(e) => return Err(e), + }; + + let mut fp: blst_fp = Default::default(); + + // SAFETY: input_p0 has fixed length, fp is a blst value. + unsafe { + blst_fp_from_bendian(&mut fp, input_p0.as_ptr()); + } + + let mut p: blst_p1 = Default::default(); + // SAFETY: p and fp are blst values. + unsafe { + // third argument is unused if null. + blst_map_to_g1(&mut p, &fp, std::ptr::null()); + } + + let mut p_aff: blst_p1_affine = Default::default(); + // SAFETY: p_aff and p are blst values. + unsafe { + blst_p1_to_affine(&mut p_aff, &p); + } + + let mut out = [0u8; G1_OUTPUT_LENGTH]; + encode_g1_point(&mut out, &p_aff); + + Ok((MAP_FP_TO_G1_BASE, out.into())) +} diff --git a/crates/precompile/src/bls12_381/mod.rs b/crates/precompile/src/bls12_381/mod.rs new file mode 100644 index 0000000000..764c4a50a1 --- /dev/null +++ b/crates/precompile/src/bls12_381/mod.rs @@ -0,0 +1,31 @@ +use crate::PrecompileWithAddress; + +mod g1; +pub mod g1_add; +pub mod g1_msm; +pub mod g1_mul; +mod g2; +pub mod g2_add; +pub mod g2_msm; +pub mod g2_mul; +pub mod map_fp2_to_g2; +pub mod map_fp_to_g1; +mod msm; +pub mod pairing; +mod utils; + +/// Returns the BLS12-381 precompiles with their addresses. +pub fn precompiles() -> impl Iterator { + [ + g1_add::PRECOMPILE, + g1_mul::PRECOMPILE, + g1_msm::PRECOMPILE, + g2_add::PRECOMPILE, + g2_mul::PRECOMPILE, + g2_msm::PRECOMPILE, + pairing::PRECOMPILE, + map_fp_to_g1::PRECOMPILE, + map_fp2_to_g2::PRECOMPILE, + ] + .into_iter() +} diff --git a/crates/precompile/src/bls12_381/msm.rs b/crates/precompile/src/bls12_381/msm.rs new file mode 100644 index 0000000000..e26ea3ebb2 --- /dev/null +++ b/crates/precompile/src/bls12_381/msm.rs @@ -0,0 +1,28 @@ +/// Amount used to calculate the multi-scalar-multiplication discount. +const MSM_MULTIPLIER: u64 = 1000; +/// Table of gas discounts for multi-scalar-multiplication operations. +const MSM_DISCOUNT_TABLE: [u64; 128] = [ + 1200, 888, 764, 641, 594, 547, 500, 453, 438, 423, 408, 394, 379, 364, 349, 334, 330, 326, 322, + 318, 314, 310, 306, 302, 298, 294, 289, 285, 281, 277, 273, 269, 268, 266, 265, 263, 262, 260, + 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 241, 239, 238, 236, 235, 233, 232, + 231, 229, 228, 226, 225, 223, 222, 221, 220, 219, 219, 218, 217, 216, 216, 215, 214, 213, 213, + 212, 211, 211, 210, 209, 208, 208, 207, 206, 205, 205, 204, 203, 202, 202, 201, 200, 199, 199, + 198, 197, 196, 196, 195, 194, 193, 193, 192, 191, 191, 190, 189, 188, 188, 187, 186, 185, 185, + 184, 183, 182, 182, 181, 180, 179, 179, 178, 177, 176, 176, 175, 174, +]; + +/// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30 +/// MGas/second, see also: +pub(super) fn msm_required_gas(k: usize, multiplication_cost: u64) -> u64 { + if k == 0 { + return 0; + } + + let discount = if k < MSM_DISCOUNT_TABLE.len() { + MSM_DISCOUNT_TABLE[k - 1] + } else { + MSM_DISCOUNT_TABLE[MSM_DISCOUNT_TABLE.len() - 1] + }; + + (k as u64 * discount * multiplication_cost) / MSM_MULTIPLIER +} diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs new file mode 100644 index 0000000000..b49d30c232 --- /dev/null +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -0,0 +1,96 @@ +use blst::{ + blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop, blst_p1_affine, + blst_p2_affine, +}; +use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult, B256}; + +use crate::{u64_to_address, PrecompileWithAddress}; + +use super::{ + g1::{extract_g1_input, G1_INPUT_ITEM_LENGTH}, + g2::{extract_g2_input, G2_INPUT_ITEM_LENGTH}, +}; + +/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_PAIRING precompile. +pub const PRECOMPILE: PrecompileWithAddress = + PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(pairing)); +/// BLS12_PAIRING precompile address. +pub const ADDRESS: u64 = 0x11; + +/// Multiplier gas fee for BLS12-381 pairing operation. +const PAIRING_MULTIPLIER_BASE: u64 = 43000; +/// Offset gas fee for BLS12-381 pairing operation. +const PAIRING_OFFSET_BASE: u64 = 65000; +/// Input length of paitring operation. +const INPUT_LENGTH: usize = 384; + +/// Pairing call expects 384*k (k being a positive integer) bytes as an inputs +/// that is interpreted as byte concatenation of k slices. Each slice has the +/// following structure: +/// * 128 bytes of G1 point encoding +/// * 256 bytes of G2 point encoding +/// Each point is expected to be in the subgroup of order q. +/// Output is a 32 bytes where first 31 bytes are equal to 0x00 and the last byte +/// is 0x01 if pairing result is equal to the multiplicative identity in a pairing +/// target field and 0x00 otherwise. +/// See also: +fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { + let input_len = input.len(); + if input_len == 0 || input_len % INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(format!( + "Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}" + ))); + } + + let k = input_len / INPUT_LENGTH; + let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE; + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas); + } + + let mut ret: blst_fp12 = Default::default(); + for i in 0..k { + let mut p1_aff: blst_p1_affine = Default::default(); + let p1_aff = extract_g1_input( + &mut p1_aff, + &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], + )? as *const blst_p1_affine; + let mut p2_aff: blst_p2_affine = Default::default(); + let p2_aff = extract_g2_input( + &mut p2_aff, + &input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + ..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + G2_INPUT_ITEM_LENGTH], + )? as *const blst_p2_affine; + if i > 0 { + // after the first slice (i>0) we use cur_ml to store the current + // miller loop and accumulate with the previous results using a fp12 + // multiplication. + let mut cur_ml: blst_fp12 = Default::default(); + // SAFETY: ret, cur_ml, p1_aff and p2_aff are blst values. + unsafe { + blst_miller_loop(&mut cur_ml, p2_aff, p1_aff); + blst_fp12_mul(&mut ret, &ret, &cur_ml); + } + } else { + // on the first slice (i==0) there is no previous results and no need + // to accumulate. + // SAFETY: ret, p1_aff and p2_aff are blst values. + unsafe { + blst_miller_loop(&mut ret, p2_aff, p1_aff); + } + } + } + // SAFETY: ret is blst value. + unsafe { + blst_final_exp(&mut ret, &ret); + } + + let mut result: u8 = 0; + // SAFETY: ret is a blst value. + unsafe { + if blst_fp12_is_one(&ret) { + result = 1; + } + } + Ok((required_gas, B256::with_last_byte(result).into())) +} diff --git a/crates/precompile/src/bls12_381/utils.rs b/crates/precompile/src/bls12_381/utils.rs new file mode 100644 index 0000000000..3c02968625 --- /dev/null +++ b/crates/precompile/src/bls12_381/utils.rs @@ -0,0 +1,65 @@ +use blst::{blst_bendian_from_fp, blst_fp, blst_scalar, blst_scalar_from_bendian}; +use revm_primitives::PrecompileError; + +/// Number of bits used in the BLS12-381 curve finite field elements. +pub(super) const NBITS: usize = 256; +/// Finite field element input length. +pub(super) const FP_LENGTH: usize = 48; +/// Finite field element padded input length. +pub(super) const PADDED_FP_LENGTH: usize = 64; +/// Quadratic extension of finite field element input length. +pub(super) const PADDED_FP2_LENGTH: usize = 128; +/// Input elements padding length. +pub(super) const PADDING_LENGTH: usize = 16; +/// Scalar length. +pub(super) const SCALAR_LENGTH: usize = 32; + +/// Encodes a single finite field element into a byte slice with padding. +pub(super) fn fp_to_bytes(out: &mut [u8], input: *const blst_fp) { + if out.len() != PADDED_FP_LENGTH { + return; + } + for item in out.iter_mut().take(PADDING_LENGTH) { + *item = 0; + } + // SAFETY: out length is checked previously, input is a blst value. + unsafe { + blst_bendian_from_fp(out[PADDING_LENGTH..].as_mut_ptr(), input); + } +} + +/// Removes zeros with which the precompile inputs are left padded to 64 bytes. +pub(super) fn remove_padding(input: &[u8]) -> Result<[u8; FP_LENGTH], PrecompileError> { + if input.len() != PADDED_FP_LENGTH { + return Err(PrecompileError::Other(format!( + "Padded Input should be {PADDED_FP_LENGTH} bits, was {}", + input.len() + ))); + } + if !input.iter().take(PADDING_LENGTH).all(|&x| x == 0) { + return Err(PrecompileError::Other(format!( + "{PADDING_LENGTH} top bytes of input are not zero", + ))); + } + + let sliced = &input[PADDING_LENGTH..PADDED_FP_LENGTH]; + <[u8; FP_LENGTH]>::try_from(sliced).map_err(|e| PrecompileError::Other(format!("{e}"))) +} + +/// Extracts an Scalar from a 32 byte slice representation. +pub(super) fn extract_scalar_input(input: &[u8]) -> Result { + if input.len() != SCALAR_LENGTH { + return Err(PrecompileError::Other(format!( + "Input should be {SCALAR_LENGTH} bits, was {}", + input.len() + ))); + } + + let mut out: blst_scalar = Default::default(); + // SAFETY: input length is checked previously, out is a blst value. + unsafe { + blst_scalar_from_bendian(&mut out, input.as_ptr()); + } + + Ok(out) +} diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 7903d38b27..37456f2a02 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -9,6 +9,7 @@ extern crate alloc as std; pub mod blake2; +pub mod bls12_381; pub mod bn128; pub mod hash; pub mod identity; @@ -159,10 +160,9 @@ impl Precompiles { pub fn prague() -> &'static Self { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { - let precompiles = Self::cancun().clone(); + let mut precompiles = Self::cancun().clone(); // EIP-2537: Precompile for BLS12-381 curve operations - // TODO(alexey): add BLS12-381 precompiles - // precompiles.extend(bls12_381::precompiles()); + precompiles.extend(bls12_381::precompiles()); Box::new(precompiles) }) } From cb5886f4bdc2a5b5174ab5af6f22354de831961c Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 8 May 2024 16:59:27 +0100 Subject: [PATCH 04/10] feature-gate blst --- bins/revme/Cargo.toml | 1 + crates/precompile/Cargo.toml | 7 +++++-- crates/precompile/src/lib.rs | 14 +++++++++++--- crates/revm/Cargo.toml | 3 ++- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index 95290714c3..84a695d7ca 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -20,6 +20,7 @@ revm = { path = "../../crates/revm", version = "8.0.0", default-features = false "std", "serde-json", "c-kzg", + "blst" ] } alloy-rlp = { version = "0.3", default-features = false, features = [ "arrayvec", diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 1f4bee6a15..6ff092d8a0 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -42,14 +42,14 @@ secp256k1 = { version = "0.29.0", default-features = false, features = [ ], optional = true } # BLS12-381 precompiles -blst = "0.3.11" +blst = { version = "0.3.11", optional = true } [dev-dependencies] criterion = { version = "0.5" } rand = { version = "0.8", features = ["std"] } [features] -default = ["std", "c-kzg", "secp256k1", "portable"] +default = ["std", "c-kzg", "secp256k1", "portable", "blst"] std = [ "revm-primitives/std", "k256/std", @@ -83,6 +83,9 @@ portable = ["revm-primitives/portable", "c-kzg?/portable"] # In Linux it passes. If you don't require to build wasm on win/mac, it is safe to use it and it is enabled by default. secp256k1 = ["dep:secp256k1"] +# Enables the BLS12-381 precompiles. +blst = ["dep:blst"] + [[bench]] name = "bench" path = "benches/bench.rs" diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 37456f2a02..82c56ca7d2 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -9,6 +9,7 @@ extern crate alloc as std; pub mod blake2; +#[cfg(feature = "blst")] pub mod bls12_381; pub mod bn128; pub mod hash; @@ -160,9 +161,16 @@ impl Precompiles { pub fn prague() -> &'static Self { static INSTANCE: OnceBox = OnceBox::new(); INSTANCE.get_or_init(|| { - let mut precompiles = Self::cancun().clone(); - // EIP-2537: Precompile for BLS12-381 curve operations - precompiles.extend(bls12_381::precompiles()); + let precompiles = Self::berlin().clone(); + + // Don't include KZG point evaluation precompile in no_std builds. + #[cfg(feature = "blst")] + let precompiles = { + let mut precompiles = precompiles; + precompiles.extend(bls12_381::precompiles()); + precompiles + }; + Box::new(precompiles) }) } diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 7ddb717591..9b8446ad26 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -70,7 +70,7 @@ alloy-provider = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d alloy-transport-http = { git = "https://github.com/alloy-rs/alloy.git", rev = "44b8a6d" } [features] -default = ["std", "c-kzg", "secp256k1", "portable"] +default = ["std", "c-kzg", "secp256k1", "portable", "blst"] std = [ "serde?/std", "serde_json?/std", @@ -134,6 +134,7 @@ optional_beneficiary_reward = ["revm-interpreter/optional_beneficiary_reward"] # See comments in `revm-precompile` secp256k1 = ["revm-precompile/secp256k1"] c-kzg = ["revm-precompile/c-kzg"] +blst = ["revm-precompile/blst"] [[example]] name = "fork_ref_transact" From 12382fb466ae48eeb3fe94385fb0b146e8567536 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 8 May 2024 17:21:04 +0100 Subject: [PATCH 05/10] run EIP-2537 tests in CI --- .github/workflows/ethereum-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ethereum-tests.yml b/.github/workflows/ethereum-tests.yml index 3b972f7721..c4c1c8dfbc 100644 --- a/.github/workflows/ethereum-tests.yml +++ b/.github/workflows/ethereum-tests.yml @@ -47,3 +47,5 @@ jobs: ethtests/LegacyTests/Constantinople/GeneralStateTests/ \ ethtests/EIPTests/StateTests/stEIP1153-transientStorage/ \ ethtests/EIPTests/StateTests/stEIP4844-blobtransactions/ \ + ethtests/EIPTests/StateTests/stEIP2537/ \ + From fe82460e62be2088a99bb918709520231b12614c Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Wed, 8 May 2024 17:38:37 +0100 Subject: [PATCH 06/10] fix doc comment --- crates/precompile/src/bls12_381/g1_add.rs | 2 +- crates/precompile/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs index f2c0ec5a78..4ba6b2b0f2 100644 --- a/crates/precompile/src/bls12_381/g1_add.rs +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -10,7 +10,7 @@ use super::g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTP /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1ADD precompile. pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g1_add)); -// BLS12_G1ADD precompile address. +/// BLS12_G1ADD precompile address. pub const ADDRESS: u64 = 0x0b; /// Base gas fee for BLS12-381 g1_add operation. const BASE_GAS_FEE: u64 = 500; diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 82c56ca7d2..97c4282daa 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -163,7 +163,7 @@ impl Precompiles { INSTANCE.get_or_init(|| { let precompiles = Self::berlin().clone(); - // Don't include KZG point evaluation precompile in no_std builds. + // Don't include BLS12-381 precompiles in no_std builds. #[cfg(feature = "blst")] let precompiles = { let mut precompiles = precompiles; From 17a97ecd1ca08bf611ca65433d4c8a087a7e9879 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 9 May 2024 12:34:57 +0100 Subject: [PATCH 07/10] fixes after review (arrays to vecs, question mark operators, default inits) --- crates/precompile/src/bls12_381/g1.rs | 10 ++------- crates/precompile/src/bls12_381/g1_add.rs | 12 +++++----- crates/precompile/src/bls12_381/g1_msm.rs | 8 +++---- crates/precompile/src/bls12_381/g1_mul.rs | 10 ++++----- crates/precompile/src/bls12_381/g2.rs | 6 +---- crates/precompile/src/bls12_381/g2_add.rs | 12 +++++----- crates/precompile/src/bls12_381/g2_msm.rs | 8 +++---- crates/precompile/src/bls12_381/g2_mul.rs | 10 ++++----- .../precompile/src/bls12_381/map_fp2_to_g2.rs | 22 +++++++------------ .../precompile/src/bls12_381/map_fp_to_g1.rs | 13 +++++------ crates/precompile/src/bls12_381/pairing.rs | 10 ++++----- crates/precompile/src/bls12_381/utils.rs | 2 +- 12 files changed, 52 insertions(+), 71 deletions(-) diff --git a/crates/precompile/src/bls12_381/g1.rs b/crates/precompile/src/bls12_381/g1.rs index 1cc2683084..89d133ad1c 100644 --- a/crates/precompile/src/bls12_381/g1.rs +++ b/crates/precompile/src/bls12_381/g1.rs @@ -29,14 +29,8 @@ pub(super) fn extract_g1_input( ))); } - let input_p0_x = match remove_padding(&input[..PADDED_FP_LENGTH]) { - Ok(input_p0_x) => input_p0_x, - Err(e) => return Err(e), - }; - let input_p0_y = match remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH]) { - Ok(input_p0_y) => input_p0_y, - Err(e) => return Err(e), - }; + let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; + let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH])?; // SAFETY: input_p0_x and input_p0_y have fixed length, x and y are blst values. unsafe { diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs index 4ba6b2b0f2..2c4234138e 100644 --- a/crates/precompile/src/bls12_381/g1_add.rs +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -35,31 +35,31 @@ fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut a_aff: blst_p1_affine = Default::default(); + let mut a_aff = blst_p1_affine::default(); let a_aff = extract_g1_input(&mut a_aff, &input[..G1_INPUT_ITEM_LENGTH])?; - let mut b_aff: blst_p1_affine = Default::default(); + let mut b_aff = blst_p1_affine::default(); let b_aff = extract_g1_input(&mut b_aff, &input[G1_INPUT_ITEM_LENGTH..])?; - let mut b: blst_p1 = Default::default(); + let mut b = blst_p1::default(); // SAFETY: b and b_aff are blst values. unsafe { blst_p1_from_affine(&mut b, b_aff); } - let mut p: blst_p1 = Default::default(); + let mut p = blst_p1::default(); // SAFETY: p, b and a_aff are blst values. unsafe { blst_p1_add_or_double_affine(&mut p, &b, a_aff); } - let mut p_aff: blst_p1_affine = Default::default(); + let mut p_aff = blst_p1_affine::default(); // SAFETY: p_aff and p are blst values. unsafe { blst_p1_to_affine(&mut p_aff, &p); } - let mut out = [0u8; G1_OUTPUT_LENGTH]; + let mut out = vec![0u8; G1_OUTPUT_LENGTH]; encode_g1_point(&mut out, &p_aff); Ok((BASE_GAS_FEE, out.into())) diff --git a/crates/precompile/src/bls12_381/g1_msm.rs b/crates/precompile/src/bls12_381/g1_msm.rs index ffc03c5260..120aaf6437 100644 --- a/crates/precompile/src/bls12_381/g1_msm.rs +++ b/crates/precompile/src/bls12_381/g1_msm.rs @@ -43,12 +43,12 @@ fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { let mut g1_points: Vec = Vec::with_capacity(k); let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); for i in 0..k { - let mut p0_aff: blst_p1_affine = Default::default(); + let mut p0_aff = blst_p1_affine::default(); let p0_aff = extract_g1_input( &mut p0_aff, &input[i * g1_mul::INPUT_LENGTH..i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], )?; - let mut p0: blst_p1 = Default::default(); + let mut p0 = blst_p1::default(); // SAFETY: p0 and p0_aff are blst values. unsafe { blst_p1_from_affine(&mut p0, p0_aff); @@ -68,13 +68,13 @@ fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { let points = p1_affines::from(&g1_points); let multiexp = points.mult(&scalars, NBITS); - let mut multiexp_aff: blst_p1_affine = Default::default(); + let mut multiexp_aff = blst_p1_affine::default(); // SAFETY: multiexp_aff and multiexp are blst values. unsafe { blst_p1_to_affine(&mut multiexp_aff, &multiexp); } - let mut out = [0u8; G1_OUTPUT_LENGTH]; + let mut out = vec![0u8; G1_OUTPUT_LENGTH]; encode_g1_point(&mut out, &multiexp_aff); Ok((required_gas, out.into())) diff --git a/crates/precompile/src/bls12_381/g1_mul.rs b/crates/precompile/src/bls12_381/g1_mul.rs index ef7c836a3c..a6c3037f30 100644 --- a/crates/precompile/src/bls12_381/g1_mul.rs +++ b/crates/precompile/src/bls12_381/g1_mul.rs @@ -36,9 +36,9 @@ pub fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut p0_aff: blst_p1_affine = Default::default(); + let mut p0_aff = blst_p1_affine::default(); let p0_aff = extract_g1_input(&mut p0_aff, &input[..G1_INPUT_ITEM_LENGTH])?; - let mut p0: blst_p1 = Default::default(); + let mut p0 = blst_p1::default(); // SAFETY: p0 and p0_aff are blst values. unsafe { blst_p1_from_affine(&mut p0, p0_aff); @@ -46,18 +46,18 @@ pub fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { let input_scalar0 = extract_scalar_input(&input[G1_INPUT_ITEM_LENGTH..])?; - let mut p: blst_p1 = Default::default(); + let mut p = blst_p1::default(); // SAFETY: input_scalar0.b has fixed size, p and p0 are blst values. unsafe { blst_p1_mult(&mut p, &p0, input_scalar0.b.as_ptr(), NBITS); } - let mut p_aff: blst_p1_affine = Default::default(); + let mut p_aff = blst_p1_affine::default(); // SAFETY: p_aff and p are blst values. unsafe { blst_p1_to_affine(&mut p_aff, &p); } - let mut out = [0u8; G1_OUTPUT_LENGTH]; + let mut out = vec![0u8; G1_OUTPUT_LENGTH]; encode_g1_point(&mut out, &p_aff); Ok((BASE_GAS_FEE, out.into())) diff --git a/crates/precompile/src/bls12_381/g2.rs b/crates/precompile/src/bls12_381/g2.rs index 39f99df59f..03e1d728db 100644 --- a/crates/precompile/src/bls12_381/g2.rs +++ b/crates/precompile/src/bls12_381/g2.rs @@ -42,11 +42,7 @@ pub(super) fn extract_g2_input( let mut input_fps: [[u8; FP_LENGTH]; 4] = [[0; FP_LENGTH]; 4]; for i in 0..4 { - input_fps[i] = - match remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH]) { - Ok(fp_0) => fp_0, - Err(e) => return Err(e), - }; + input_fps[i] = remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH])?; } // SAFETY: items in fps have fixed length, out is a blst value. diff --git a/crates/precompile/src/bls12_381/g2_add.rs b/crates/precompile/src/bls12_381/g2_add.rs index 4a159239fb..fa4265ac3d 100644 --- a/crates/precompile/src/bls12_381/g2_add.rs +++ b/crates/precompile/src/bls12_381/g2_add.rs @@ -36,31 +36,31 @@ fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut a_aff: blst_p2_affine = Default::default(); + let mut a_aff = blst_p2_affine::default(); let a_aff = extract_g2_input(&mut a_aff, &input[..G2_INPUT_ITEM_LENGTH])?; - let mut b_aff: blst_p2_affine = Default::default(); + let mut b_aff = blst_p2_affine::default(); let b_aff = extract_g2_input(&mut b_aff, &input[G2_INPUT_ITEM_LENGTH..])?; - let mut b: blst_p2 = Default::default(); + let mut b = blst_p2::default(); // SAFETY: b and b_aff are blst values. unsafe { blst_p2_from_affine(&mut b, b_aff); } - let mut p: blst_p2 = Default::default(); + let mut p = blst_p2::default(); // SAFETY: p, b and a_aff are blst values. unsafe { blst_p2_add_or_double_affine(&mut p, &b, a_aff); } - let mut p_aff: blst_p2_affine = Default::default(); + let mut p_aff = blst_p2_affine::default(); // SAFETY: p_aff and p are blst values. unsafe { blst_p2_to_affine(&mut p_aff, &p); } - let mut out = [0u8; G2_OUTPUT_LENGTH]; + let mut out = vec![0u8; G2_OUTPUT_LENGTH]; encode_g2_point(&mut out, &p_aff); Ok((BASE_GAS_FEE, out.into())) diff --git a/crates/precompile/src/bls12_381/g2_msm.rs b/crates/precompile/src/bls12_381/g2_msm.rs index 85f7488485..ee3522e5d1 100644 --- a/crates/precompile/src/bls12_381/g2_msm.rs +++ b/crates/precompile/src/bls12_381/g2_msm.rs @@ -43,12 +43,12 @@ fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { let mut g2_points: Vec = Vec::with_capacity(k); let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); for i in 0..k { - let mut p0_aff: blst_p2_affine = Default::default(); + let mut p0_aff = blst_p2_affine::default(); let p0_aff = extract_g2_input( &mut p0_aff, &input[i * g2_mul::INPUT_LENGTH..i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH], )?; - let mut p0: blst_p2 = Default::default(); + let mut p0 = blst_p2::default(); // SAFETY: p0 and p0_aff are blst values. unsafe { blst_p2_from_affine(&mut p0, p0_aff); @@ -68,13 +68,13 @@ fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { let points = p2_affines::from(&g2_points); let multiexp = points.mult(&scalars, NBITS); - let mut multiexp_aff: blst_p2_affine = Default::default(); + let mut multiexp_aff = blst_p2_affine::default(); // SAFETY: multiexp_aff and multiexp are blst values. unsafe { blst_p2_to_affine(&mut multiexp_aff, &multiexp); } - let mut out = [0u8; G2_OUTPUT_LENGTH]; + let mut out = vec![0u8; G2_OUTPUT_LENGTH]; encode_g2_point(&mut out, &multiexp_aff); Ok((required_gas, out.into())) diff --git a/crates/precompile/src/bls12_381/g2_mul.rs b/crates/precompile/src/bls12_381/g2_mul.rs index 707426d30b..701af8776c 100644 --- a/crates/precompile/src/bls12_381/g2_mul.rs +++ b/crates/precompile/src/bls12_381/g2_mul.rs @@ -36,9 +36,9 @@ fn g2_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut p0_aff: blst_p2_affine = Default::default(); + let mut p0_aff = blst_p2_affine::default(); let p0_aff = extract_g2_input(&mut p0_aff, &input[..G2_INPUT_ITEM_LENGTH])?; - let mut p0: blst_p2 = Default::default(); + let mut p0 = blst_p2::default(); // SAFETY: p0 and p0_aff are blst values. unsafe { blst_p2_from_affine(&mut p0, p0_aff); @@ -46,18 +46,18 @@ fn g2_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { let input_scalar0 = extract_scalar_input(&input[G2_INPUT_ITEM_LENGTH..])?; - let mut p: blst_p2 = Default::default(); + let mut p = blst_p2::default(); // SAFETY: input_scalar0.b has fixed size, p and p0 are blst values. unsafe { blst_p2_mult(&mut p, &p0, input_scalar0.b.as_ptr(), NBITS); } - let mut p_aff: blst_p2_affine = Default::default(); + let mut p_aff = blst_p2_affine::default(); // SAFETY: p_aff and p are blst values. unsafe { blst_p2_to_affine(&mut p_aff, &p); } - let mut out = [0u8; G2_OUTPUT_LENGTH]; + let mut out = vec![0u8; G2_OUTPUT_LENGTH]; encode_g2_point(&mut out, &p_aff); Ok((BASE_GAS_FEE, out.into())) 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 0eb5a7d6f3..e813d9855f 100644 --- a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs +++ b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs @@ -35,18 +35,12 @@ fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let input_p0_x = match remove_padding(&input[..PADDED_FP_LENGTH]) { - Ok(input_p0_x) => input_p0_x, - Err(e) => return Err(e), - }; - let input_p0_y = match remove_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH]) { - Ok(input_p0_y) => input_p0_y, - Err(e) => return Err(e), - }; + let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; + let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?; - let mut fp2: blst_fp2 = Default::default(); - let mut fp_x: blst_fp = Default::default(); - let mut fp_y: blst_fp = Default::default(); + let mut fp2 = blst_fp2::default(); + let mut fp_x = blst_fp::default(); + let mut fp_y = blst_fp::default(); // SAFETY: input_p0_x has fixed length, fp_x is a blst value. unsafe { blst_fp_from_bendian(&mut fp_x, input_p0_x.as_ptr()); @@ -58,20 +52,20 @@ fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult { fp2.fp[0] = fp_x; fp2.fp[1] = fp_y; - let mut p: blst_p2 = Default::default(); + let mut p = blst_p2::default(); // SAFETY: p and fp2 are blst values. unsafe { // third argument is unused if null. blst_map_to_g2(&mut p, &fp2, std::ptr::null()); } - let mut p_aff: blst_p2_affine = Default::default(); + let mut p_aff = blst_p2_affine::default(); // SAFETY: p_aff and p are blst values. unsafe { blst_p2_to_affine(&mut p_aff, &p); } - let mut out = [0u8; G2_OUTPUT_LENGTH]; + let mut out = vec![0u8; G2_OUTPUT_LENGTH]; encode_g2_point(&mut out, &p_aff); Ok((BASE_GAS_FEE, out.into())) 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 dc9c5c1cec..1ff98098df 100644 --- a/crates/precompile/src/bls12_381/map_fp_to_g1.rs +++ b/crates/precompile/src/bls12_381/map_fp_to_g1.rs @@ -33,32 +33,29 @@ fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let input_p0 = match remove_padding(input) { - Ok(input_p0) => input_p0, - Err(e) => return Err(e), - }; + let input_p0 = remove_padding(input)?; - let mut fp: blst_fp = Default::default(); + let mut fp = blst_fp::default(); // SAFETY: input_p0 has fixed length, fp is a blst value. unsafe { blst_fp_from_bendian(&mut fp, input_p0.as_ptr()); } - let mut p: blst_p1 = Default::default(); + let mut p = blst_p1::default(); // SAFETY: p and fp are blst values. unsafe { // third argument is unused if null. blst_map_to_g1(&mut p, &fp, std::ptr::null()); } - let mut p_aff: blst_p1_affine = Default::default(); + let mut p_aff = blst_p1_affine::default(); // SAFETY: p_aff and p are blst values. unsafe { blst_p1_to_affine(&mut p_aff, &p); } - let mut out = [0u8; G1_OUTPUT_LENGTH]; + let mut out = vec![0u8; G1_OUTPUT_LENGTH]; encode_g1_point(&mut out, &p_aff); Ok((MAP_FP_TO_G1_BASE, out.into())) diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index b49d30c232..4c7a189fb5 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -48,14 +48,14 @@ fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::OutOfGas); } - let mut ret: blst_fp12 = Default::default(); + let mut ret = blst_fp12::default(); for i in 0..k { - let mut p1_aff: blst_p1_affine = Default::default(); + let mut p1_aff = blst_p1_affine::default(); let p1_aff = extract_g1_input( &mut p1_aff, &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], )? as *const blst_p1_affine; - let mut p2_aff: blst_p2_affine = Default::default(); + let mut p2_aff = blst_p2_affine::default(); let p2_aff = extract_g2_input( &mut p2_aff, &input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH @@ -65,7 +65,7 @@ fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { // after the first slice (i>0) we use cur_ml to store the current // miller loop and accumulate with the previous results using a fp12 // multiplication. - let mut cur_ml: blst_fp12 = Default::default(); + let mut cur_ml = blst_fp12::default(); // SAFETY: ret, cur_ml, p1_aff and p2_aff are blst values. unsafe { blst_miller_loop(&mut cur_ml, p2_aff, p1_aff); @@ -80,7 +80,7 @@ fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { } } } - // SAFETY: ret is blst value. + // SAFETY: ret is a blst value. unsafe { blst_final_exp(&mut ret, &ret); } diff --git a/crates/precompile/src/bls12_381/utils.rs b/crates/precompile/src/bls12_381/utils.rs index 3c02968625..38673d66b7 100644 --- a/crates/precompile/src/bls12_381/utils.rs +++ b/crates/precompile/src/bls12_381/utils.rs @@ -55,7 +55,7 @@ pub(super) fn extract_scalar_input(input: &[u8]) -> Result Date: Thu, 9 May 2024 13:01:43 +0100 Subject: [PATCH 08/10] introduce separate variables for mutable blst calls --- crates/precompile/src/bls12_381/pairing.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index 4c7a189fb5..dca802103a 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -48,41 +48,48 @@ fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::OutOfGas); } - let mut ret = blst_fp12::default(); + // accumulator for the fp12 multiplications of the miller loops. + let mut acc = blst_fp12::default(); for i in 0..k { let mut p1_aff = blst_p1_affine::default(); let p1_aff = extract_g1_input( &mut p1_aff, &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], )? as *const blst_p1_affine; + let mut p2_aff = blst_p2_affine::default(); let p2_aff = extract_g2_input( &mut p2_aff, &input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH ..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + G2_INPUT_ITEM_LENGTH], )? as *const blst_p2_affine; + if i > 0 { // after the first slice (i>0) we use cur_ml to store the current // miller loop and accumulate with the previous results using a fp12 // multiplication. let mut cur_ml = blst_fp12::default(); - // SAFETY: ret, cur_ml, p1_aff and p2_aff are blst values. + let mut res = blst_fp12::default(); + // SAFETY: res, acc, cur_ml, p1_aff and p2_aff are blst values. unsafe { blst_miller_loop(&mut cur_ml, p2_aff, p1_aff); - blst_fp12_mul(&mut ret, &ret, &cur_ml); + blst_fp12_mul(&mut res, &acc, &cur_ml); } + acc = res; } else { // on the first slice (i==0) there is no previous results and no need // to accumulate. - // SAFETY: ret, p1_aff and p2_aff are blst values. + // SAFETY: acc, p1_aff and p2_aff are blst values. unsafe { - blst_miller_loop(&mut ret, p2_aff, p1_aff); + blst_miller_loop(&mut acc, p2_aff, p1_aff); } } } - // SAFETY: ret is a blst value. + + // SAFETY: ret and acc are blst values. + let mut ret = blst_fp12::default(); unsafe { - blst_final_exp(&mut ret, &ret); + blst_final_exp(&mut ret, &acc); } let mut result: u8 = 0; From 26184bd4569701c8bb5b600657fb659c0c48e65c Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 9 May 2024 13:24:16 +0100 Subject: [PATCH 09/10] return value instead of mutating the input argument where possible --- crates/precompile/src/bls12_381/g1.rs | 19 ++++++++++--------- crates/precompile/src/bls12_381/g1_add.rs | 15 +++++---------- crates/precompile/src/bls12_381/g1_msm.rs | 10 +++------- crates/precompile/src/bls12_381/g1_mul.rs | 11 ++++------- crates/precompile/src/bls12_381/g2.rs | 16 +++++++++------- crates/precompile/src/bls12_381/g2_add.rs | 15 +++++---------- crates/precompile/src/bls12_381/g2_msm.rs | 10 +++------- crates/precompile/src/bls12_381/g2_mul.rs | 11 ++++------- .../precompile/src/bls12_381/map_fp2_to_g2.rs | 8 +++----- .../precompile/src/bls12_381/map_fp_to_g1.rs | 8 +++----- crates/precompile/src/bls12_381/pairing.rs | 11 +++-------- 11 files changed, 52 insertions(+), 82 deletions(-) diff --git a/crates/precompile/src/bls12_381/g1.rs b/crates/precompile/src/bls12_381/g1.rs index 89d133ad1c..f40f39587d 100644 --- a/crates/precompile/src/bls12_381/g1.rs +++ b/crates/precompile/src/bls12_381/g1.rs @@ -1,27 +1,26 @@ use blst::{blst_fp_from_bendian, blst_p1_affine, blst_p1_affine_in_g1}; -use revm_primitives::PrecompileError; +use revm_primitives::{Bytes, PrecompileError}; use super::utils::{fp_to_bytes, remove_padding, PADDED_FP_LENGTH}; /// Length of each of the elements in a g1 operation input. pub(super) const G1_INPUT_ITEM_LENGTH: usize = 128; /// Output length of a g1 operation. -pub(super) const G1_OUTPUT_LENGTH: usize = 128; +const G1_OUTPUT_LENGTH: usize = 128; /// Encodes a G1 point in affine format into a byte slice with padded elements. -pub(super) fn encode_g1_point(out: &mut [u8], input: *const blst_p1_affine) { - // SAFETY: out comes from fixed length array, x and y are blst values. +pub(super) fn encode_g1_point(input: *const blst_p1_affine) -> Bytes { + let mut out = vec![0u8; G1_OUTPUT_LENGTH]; + // SAFETY: out comes from fixed length array, input is a blst value. unsafe { fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &(*input).x); fp_to_bytes(&mut out[PADDED_FP_LENGTH..], &(*input).y); } + out.into() } /// Extracts a G1 point in Affine format from a 128 byte slice representation. -pub(super) fn extract_g1_input( - out: *mut blst_p1_affine, - input: &[u8], -) -> Result<*mut blst_p1_affine, PrecompileError> { +pub(super) fn extract_g1_input(input: &[u8]) -> Result<*mut blst_p1_affine, PrecompileError> { if input.len() != G1_INPUT_ITEM_LENGTH { return Err(PrecompileError::Other(format!( "Input should be {G1_INPUT_ITEM_LENGTH} bits, was {}", @@ -32,11 +31,13 @@ pub(super) fn extract_g1_input( let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH])?; - // SAFETY: input_p0_x and input_p0_y have fixed length, x and y are blst values. + let out = &mut blst_p1_affine::default() as *mut blst_p1_affine; + // SAFETY: input_p0_x and input_p0_y have fixed length, out is a blst value. unsafe { blst_fp_from_bendian(&mut (*out).x, input_p0_x.as_ptr()); blst_fp_from_bendian(&mut (*out).y, input_p0_y.as_ptr()); } + // SAFETY: out is a blst value. unsafe { if !blst_p1_affine_in_g1(out) { diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs index 2c4234138e..e3adba016a 100644 --- a/crates/precompile/src/bls12_381/g1_add.rs +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -5,7 +5,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; -use super::g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH}; +use super::g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1ADD precompile. pub const PRECOMPILE: PrecompileWithAddress = @@ -35,11 +35,8 @@ fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut a_aff = blst_p1_affine::default(); - let a_aff = extract_g1_input(&mut a_aff, &input[..G1_INPUT_ITEM_LENGTH])?; - - let mut b_aff = blst_p1_affine::default(); - let b_aff = extract_g1_input(&mut b_aff, &input[G1_INPUT_ITEM_LENGTH..])?; + let a_aff = extract_g1_input(&input[..G1_INPUT_ITEM_LENGTH])?; + let b_aff = extract_g1_input(&input[G1_INPUT_ITEM_LENGTH..])?; let mut b = blst_p1::default(); // SAFETY: b and b_aff are blst values. @@ -59,8 +56,6 @@ fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p1_to_affine(&mut p_aff, &p); } - let mut out = vec![0u8; G1_OUTPUT_LENGTH]; - encode_g1_point(&mut out, &p_aff); - - Ok((BASE_GAS_FEE, out.into())) + let out = encode_g1_point(&p_aff); + Ok((BASE_GAS_FEE, out)) } diff --git a/crates/precompile/src/bls12_381/g1_msm.rs b/crates/precompile/src/bls12_381/g1_msm.rs index 120aaf6437..a339d86039 100644 --- a/crates/precompile/src/bls12_381/g1_msm.rs +++ b/crates/precompile/src/bls12_381/g1_msm.rs @@ -4,7 +4,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; use super::{ - g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH}, + g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH}, g1_mul, msm::msm_required_gas, utils::{extract_scalar_input, NBITS, SCALAR_LENGTH}, @@ -43,9 +43,7 @@ fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { let mut g1_points: Vec = Vec::with_capacity(k); let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); for i in 0..k { - let mut p0_aff = blst_p1_affine::default(); let p0_aff = extract_g1_input( - &mut p0_aff, &input[i * g1_mul::INPUT_LENGTH..i * g1_mul::INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], )?; let mut p0 = blst_p1::default(); @@ -74,8 +72,6 @@ fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p1_to_affine(&mut multiexp_aff, &multiexp); } - let mut out = vec![0u8; G1_OUTPUT_LENGTH]; - encode_g1_point(&mut out, &multiexp_aff); - - Ok((required_gas, out.into())) + let out = encode_g1_point(&multiexp_aff); + Ok((required_gas, out)) } diff --git a/crates/precompile/src/bls12_381/g1_mul.rs b/crates/precompile/src/bls12_381/g1_mul.rs index a6c3037f30..171de875c8 100644 --- a/crates/precompile/src/bls12_381/g1_mul.rs +++ b/crates/precompile/src/bls12_381/g1_mul.rs @@ -4,7 +4,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; use super::{ - g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH}, + g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH}, utils::{extract_scalar_input, NBITS}, }; @@ -36,8 +36,7 @@ pub fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut p0_aff = blst_p1_affine::default(); - let p0_aff = extract_g1_input(&mut p0_aff, &input[..G1_INPUT_ITEM_LENGTH])?; + let p0_aff = extract_g1_input(&input[..G1_INPUT_ITEM_LENGTH])?; let mut p0 = blst_p1::default(); // SAFETY: p0 and p0_aff are blst values. unsafe { @@ -57,8 +56,6 @@ pub fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p1_to_affine(&mut p_aff, &p); } - let mut out = vec![0u8; G1_OUTPUT_LENGTH]; - encode_g1_point(&mut out, &p_aff); - - Ok((BASE_GAS_FEE, out.into())) + let out = encode_g1_point(&p_aff); + Ok((BASE_GAS_FEE, out)) } diff --git a/crates/precompile/src/bls12_381/g2.rs b/crates/precompile/src/bls12_381/g2.rs index 03e1d728db..17d6243802 100644 --- a/crates/precompile/src/bls12_381/g2.rs +++ b/crates/precompile/src/bls12_381/g2.rs @@ -1,15 +1,16 @@ use blst::{blst_fp_from_bendian, blst_p2_affine, blst_p2_affine_in_g2}; -use revm_primitives::PrecompileError; +use revm_primitives::{Bytes, PrecompileError}; use super::utils::{fp_to_bytes, remove_padding, FP_LENGTH, PADDED_FP_LENGTH}; /// Length of each of the elements in a g2 operation input. pub(super) const G2_INPUT_ITEM_LENGTH: usize = 256; /// Output length of a g2 operation. -pub(super) const G2_OUTPUT_LENGTH: usize = 256; +const G2_OUTPUT_LENGTH: usize = 256; /// Encodes a G2 point in affine format into a byte slice with padded elements. -pub(super) fn encode_g2_point(out: &mut [u8], input: *const blst_p2_affine) { +pub(super) fn encode_g2_point(input: *const blst_p2_affine) -> Bytes { + let mut out = vec![0u8; G2_OUTPUT_LENGTH]; // SAFETY: out comes from fixed length array, input is a blst value. unsafe { fp_to_bytes(&mut out[..PADDED_FP_LENGTH], &(*input).x.fp[0]); @@ -26,13 +27,11 @@ pub(super) fn encode_g2_point(out: &mut [u8], input: *const blst_p2_affine) { &(*input).y.fp[1], ); } + out.into() } /// Extracts a G2 point in Affine format from a 256 byte slice representation. -pub(super) fn extract_g2_input( - out: *mut blst_p2_affine, - input: &[u8], -) -> Result<*mut blst_p2_affine, PrecompileError> { +pub(super) fn extract_g2_input(input: &[u8]) -> Result<*mut blst_p2_affine, PrecompileError> { if input.len() != G2_INPUT_ITEM_LENGTH { return Err(PrecompileError::Other(format!( "Input should be {G2_INPUT_ITEM_LENGTH} bits, was {}", @@ -45,6 +44,7 @@ pub(super) fn extract_g2_input( input_fps[i] = remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH])?; } + let out = &mut blst_p2_affine::default() as *mut blst_p2_affine; // SAFETY: items in fps have fixed length, out is a blst value. unsafe { blst_fp_from_bendian(&mut (*out).x.fp[0], input_fps[0].as_ptr()); @@ -52,11 +52,13 @@ pub(super) fn extract_g2_input( blst_fp_from_bendian(&mut (*out).y.fp[0], input_fps[2].as_ptr()); blst_fp_from_bendian(&mut (*out).y.fp[1], input_fps[3].as_ptr()); } + // SAFETY: out is a blst value. unsafe { if !blst_p2_affine_in_g2(out) { return Err(PrecompileError::Other("Element not in G2".to_string())); } } + Ok(out) } diff --git a/crates/precompile/src/bls12_381/g2_add.rs b/crates/precompile/src/bls12_381/g2_add.rs index fa4265ac3d..2d7e95edf6 100644 --- a/crates/precompile/src/bls12_381/g2_add.rs +++ b/crates/precompile/src/bls12_381/g2_add.rs @@ -5,7 +5,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; -use super::g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH}; +use super::g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile. pub const PRECOMPILE: PrecompileWithAddress = @@ -36,11 +36,8 @@ fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut a_aff = blst_p2_affine::default(); - let a_aff = extract_g2_input(&mut a_aff, &input[..G2_INPUT_ITEM_LENGTH])?; - - let mut b_aff = blst_p2_affine::default(); - let b_aff = extract_g2_input(&mut b_aff, &input[G2_INPUT_ITEM_LENGTH..])?; + let a_aff = extract_g2_input(&input[..G2_INPUT_ITEM_LENGTH])?; + let b_aff = extract_g2_input(&input[G2_INPUT_ITEM_LENGTH..])?; let mut b = blst_p2::default(); // SAFETY: b and b_aff are blst values. @@ -60,8 +57,6 @@ fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p2_to_affine(&mut p_aff, &p); } - let mut out = vec![0u8; G2_OUTPUT_LENGTH]; - encode_g2_point(&mut out, &p_aff); - - Ok((BASE_GAS_FEE, out.into())) + let out = encode_g2_point(&p_aff); + Ok((BASE_GAS_FEE, out)) } diff --git a/crates/precompile/src/bls12_381/g2_msm.rs b/crates/precompile/src/bls12_381/g2_msm.rs index ee3522e5d1..8ea82c2024 100644 --- a/crates/precompile/src/bls12_381/g2_msm.rs +++ b/crates/precompile/src/bls12_381/g2_msm.rs @@ -4,7 +4,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; use super::{ - g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH}, + g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH}, g2_mul, msm::msm_required_gas, utils::{extract_scalar_input, NBITS, SCALAR_LENGTH}, @@ -43,9 +43,7 @@ fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { let mut g2_points: Vec = Vec::with_capacity(k); let mut scalars: Vec = Vec::with_capacity(k * SCALAR_LENGTH); for i in 0..k { - let mut p0_aff = blst_p2_affine::default(); let p0_aff = extract_g2_input( - &mut p0_aff, &input[i * g2_mul::INPUT_LENGTH..i * g2_mul::INPUT_LENGTH + G2_INPUT_ITEM_LENGTH], )?; let mut p0 = blst_p2::default(); @@ -74,8 +72,6 @@ fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p2_to_affine(&mut multiexp_aff, &multiexp); } - let mut out = vec![0u8; G2_OUTPUT_LENGTH]; - encode_g2_point(&mut out, &multiexp_aff); - - Ok((required_gas, out.into())) + let out = encode_g2_point(&multiexp_aff); + Ok((required_gas, out)) } diff --git a/crates/precompile/src/bls12_381/g2_mul.rs b/crates/precompile/src/bls12_381/g2_mul.rs index 701af8776c..be3f4f9f14 100644 --- a/crates/precompile/src/bls12_381/g2_mul.rs +++ b/crates/precompile/src/bls12_381/g2_mul.rs @@ -4,7 +4,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; use super::{ - g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH}, + g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH}, utils::{extract_scalar_input, NBITS}, }; @@ -36,8 +36,7 @@ fn g2_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { ))); } - let mut p0_aff = blst_p2_affine::default(); - let p0_aff = extract_g2_input(&mut p0_aff, &input[..G2_INPUT_ITEM_LENGTH])?; + let p0_aff = extract_g2_input(&input[..G2_INPUT_ITEM_LENGTH])?; let mut p0 = blst_p2::default(); // SAFETY: p0 and p0_aff are blst values. unsafe { @@ -57,8 +56,6 @@ fn g2_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p2_to_affine(&mut p_aff, &p); } - let mut out = vec![0u8; G2_OUTPUT_LENGTH]; - encode_g2_point(&mut out, &p_aff); - - Ok((BASE_GAS_FEE, out.into())) + let out = encode_g2_point(&p_aff); + Ok((BASE_GAS_FEE, out)) } 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 e813d9855f..6448dda6f6 100644 --- a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs +++ b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs @@ -7,7 +7,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; use super::{ - g2::{encode_g2_point, G2_OUTPUT_LENGTH}, + g2::encode_g2_point, utils::{remove_padding, PADDED_FP2_LENGTH, PADDED_FP_LENGTH}, }; @@ -65,8 +65,6 @@ fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p2_to_affine(&mut p_aff, &p); } - let mut out = vec![0u8; G2_OUTPUT_LENGTH]; - encode_g2_point(&mut out, &p_aff); - - Ok((BASE_GAS_FEE, out.into())) + let out = encode_g2_point(&p_aff); + Ok((BASE_GAS_FEE, out)) } 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 1ff98098df..f0d273f3bf 100644 --- a/crates/precompile/src/bls12_381/map_fp_to_g1.rs +++ b/crates/precompile/src/bls12_381/map_fp_to_g1.rs @@ -6,7 +6,7 @@ use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult}; use crate::{u64_to_address, PrecompileWithAddress}; use super::{ - g1::{encode_g1_point, G1_OUTPUT_LENGTH}, + g1::encode_g1_point, utils::{remove_padding, PADDED_FP_LENGTH}, }; @@ -55,8 +55,6 @@ fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult { blst_p1_to_affine(&mut p_aff, &p); } - let mut out = vec![0u8; G1_OUTPUT_LENGTH]; - encode_g1_point(&mut out, &p_aff); - - Ok((MAP_FP_TO_G1_BASE, out.into())) + let out = encode_g1_point(&p_aff); + Ok((MAP_FP_TO_G1_BASE, out)) } diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index dca802103a..64dd2d44d1 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -51,18 +51,13 @@ fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { // accumulator for the fp12 multiplications of the miller loops. let mut acc = blst_fp12::default(); for i in 0..k { - let mut p1_aff = blst_p1_affine::default(); - let p1_aff = extract_g1_input( - &mut p1_aff, - &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH], - )? as *const blst_p1_affine; + let p1_aff = + extract_g1_input(&input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH])?; - let mut p2_aff = blst_p2_affine::default(); let p2_aff = extract_g2_input( - &mut p2_aff, &input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH ..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + G2_INPUT_ITEM_LENGTH], - )? as *const blst_p2_affine; + )?; if i > 0 { // after the first slice (i>0) we use cur_ml to store the current From 84156f88cce872734e1a94de7f007400ff55acdc Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 9 May 2024 13:30:29 +0100 Subject: [PATCH 10/10] replace *mut with *const where mut is not needed --- crates/precompile/src/bls12_381/g1.rs | 12 ++++++------ crates/precompile/src/bls12_381/g2.rs | 16 ++++++++-------- crates/precompile/src/bls12_381/pairing.rs | 5 +---- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/crates/precompile/src/bls12_381/g1.rs b/crates/precompile/src/bls12_381/g1.rs index f40f39587d..28e5a845d4 100644 --- a/crates/precompile/src/bls12_381/g1.rs +++ b/crates/precompile/src/bls12_381/g1.rs @@ -20,7 +20,7 @@ pub(super) fn encode_g1_point(input: *const blst_p1_affine) -> Bytes { } /// Extracts a G1 point in Affine format from a 128 byte slice representation. -pub(super) fn extract_g1_input(input: &[u8]) -> Result<*mut blst_p1_affine, PrecompileError> { +pub(super) fn extract_g1_input(input: &[u8]) -> Result<*const blst_p1_affine, PrecompileError> { if input.len() != G1_INPUT_ITEM_LENGTH { return Err(PrecompileError::Other(format!( "Input should be {G1_INPUT_ITEM_LENGTH} bits, was {}", @@ -31,18 +31,18 @@ pub(super) fn extract_g1_input(input: &[u8]) -> Result<*mut blst_p1_affine, Prec let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..G1_INPUT_ITEM_LENGTH])?; - let out = &mut blst_p1_affine::default() as *mut blst_p1_affine; + let mut out = blst_p1_affine::default(); // SAFETY: input_p0_x and input_p0_y have fixed length, out is a blst value. unsafe { - blst_fp_from_bendian(&mut (*out).x, input_p0_x.as_ptr()); - blst_fp_from_bendian(&mut (*out).y, input_p0_y.as_ptr()); + blst_fp_from_bendian(&mut out.x, input_p0_x.as_ptr()); + blst_fp_from_bendian(&mut out.y, input_p0_y.as_ptr()); } // SAFETY: out is a blst value. unsafe { - if !blst_p1_affine_in_g1(out) { + if !blst_p1_affine_in_g1(&out) { return Err(PrecompileError::Other("Element not in G1".to_string())); } } - Ok(out) + Ok(&mut out as *const _) } diff --git a/crates/precompile/src/bls12_381/g2.rs b/crates/precompile/src/bls12_381/g2.rs index 17d6243802..0c861e7f7d 100644 --- a/crates/precompile/src/bls12_381/g2.rs +++ b/crates/precompile/src/bls12_381/g2.rs @@ -31,7 +31,7 @@ pub(super) fn encode_g2_point(input: *const blst_p2_affine) -> Bytes { } /// Extracts a G2 point in Affine format from a 256 byte slice representation. -pub(super) fn extract_g2_input(input: &[u8]) -> Result<*mut blst_p2_affine, PrecompileError> { +pub(super) fn extract_g2_input(input: &[u8]) -> Result<*const blst_p2_affine, PrecompileError> { if input.len() != G2_INPUT_ITEM_LENGTH { return Err(PrecompileError::Other(format!( "Input should be {G2_INPUT_ITEM_LENGTH} bits, was {}", @@ -44,21 +44,21 @@ pub(super) fn extract_g2_input(input: &[u8]) -> Result<*mut blst_p2_affine, Prec input_fps[i] = remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH])?; } - let out = &mut blst_p2_affine::default() as *mut blst_p2_affine; + let mut out = blst_p2_affine::default(); // SAFETY: items in fps have fixed length, out is a blst value. unsafe { - blst_fp_from_bendian(&mut (*out).x.fp[0], input_fps[0].as_ptr()); - blst_fp_from_bendian(&mut (*out).x.fp[1], input_fps[1].as_ptr()); - blst_fp_from_bendian(&mut (*out).y.fp[0], input_fps[2].as_ptr()); - blst_fp_from_bendian(&mut (*out).y.fp[1], input_fps[3].as_ptr()); + blst_fp_from_bendian(&mut out.x.fp[0], input_fps[0].as_ptr()); + blst_fp_from_bendian(&mut out.x.fp[1], input_fps[1].as_ptr()); + blst_fp_from_bendian(&mut out.y.fp[0], input_fps[2].as_ptr()); + blst_fp_from_bendian(&mut out.y.fp[1], input_fps[3].as_ptr()); } // SAFETY: out is a blst value. unsafe { - if !blst_p2_affine_in_g2(out) { + if !blst_p2_affine_in_g2(&out) { return Err(PrecompileError::Other("Element not in G2".to_string())); } } - Ok(out) + Ok(&mut out as *const _) } diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index 64dd2d44d1..2cd5cf9a6d 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -1,7 +1,4 @@ -use blst::{ - blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop, blst_p1_affine, - blst_p2_affine, -}; +use blst::{blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop}; use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileResult, B256}; use crate::{u64_to_address, PrecompileWithAddress};