Skip to content

Commit

Permalink
Refactore BLS12-381 precompiles for NEP-488
Browse files Browse the repository at this point in the history
  • Loading branch information
mrLSD committed Feb 17, 2025
1 parent c243252 commit 85df760
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 175 deletions.
78 changes: 49 additions & 29 deletions engine-precompiles/src/bls12_381/g1_add.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use super::g1;
#[cfg(feature = "contract")]
use crate::bls12_381::{g1, FP_LENGTH};
use crate::prelude::types::{make_address, Address, EthGas};
use crate::prelude::Borrowed;
use crate::{EvmPrecompileResult, Precompile, PrecompileOutput};
use blst::{
blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine,
};
use crate::{EvmPrecompileResult, Precompile, PrecompileOutput, Vec};
use evm::{Context, ExitError};

/// Base gas fee for BLS12-381 `g1_add` operation.
Expand All @@ -18,6 +15,51 @@ pub struct BlsG1Add;

impl BlsG1Add {
pub const ADDRESS: Address = make_address(0, 0xB);

#[cfg(not(feature = "contract"))]
fn execute(input: &[u8]) -> Result<Vec<u8>, ExitError> {
use super::standalone::g1;
use crate::prelude::Borrowed;
use blst::{
blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine,
blst_p1_to_affine,
};

if input.len() != INPUT_LENGTH {
return Err(ExitError::Other(Borrowed("ERR_BLS_G1ADD_INPUT_LEN")));
}

// NB: There is no subgroup check for the G1 addition precompile.
//
// We set the subgroup checks here to `false`
let a_aff = &g1::extract_g1_input(&input[..g1::G1_INPUT_ITEM_LENGTH], false)?;
let b_aff = &g1::extract_g1_input(&input[g1::G1_INPUT_ITEM_LENGTH..], false)?;

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();
// 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();
// SAFETY: p_aff and p are blst values.
unsafe { blst_p1_to_affine(&mut p_aff, &p) };

Ok(g1::encode_g1_point(&p_aff))
}

#[cfg(feature = "contract")]
fn execute(input: &[u8]) -> Result<Vec<u8>, ExitError> {
let g1_input = super::transform_input(input)?;

let mut result = [0u8; 128];
let output = aurora_engine_sdk::bls12381_p1_sum(&g1_input[..]);
result[16..64].copy_from_slice(&output[..FP_LENGTH]);
result[16 + 64..128].copy_from_slice(&output[FP_LENGTH..]);
Ok(result.to_vec())
}
}

impl Precompile for BlsG1Add {
Expand Down Expand Up @@ -47,29 +89,7 @@ impl Precompile for BlsG1Add {
}
}

if input.len() != INPUT_LENGTH {
return Err(ExitError::Other(Borrowed("ERR_BLS_G1ADD_INPUT_LEN")));
}

// NB: There is no subgroup check for the G1 addition precompile.
//
// We set the subgroup checks here to `false`
let a_aff = &g1::extract_g1_input(&input[..g1::G1_INPUT_ITEM_LENGTH], false)?;
let b_aff = &g1::extract_g1_input(&input[g1::G1_INPUT_ITEM_LENGTH..], false)?;

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();
// 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();
// SAFETY: p_aff and p are blst values.
unsafe { blst_p1_to_affine(&mut p_aff, &p) };

let output = g1::encode_g1_point(&p_aff);
let output = Self::execute(input)?;
Ok(PrecompileOutput::without_logs(cost, output))
}
}
Expand Down
102 changes: 59 additions & 43 deletions engine-precompiles/src/bls12_381/g1_msm.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use super::{extract_scalar_input, g1, msm_required_gas, NBITS, SCALAR_LENGTH};
use super::{msm_required_gas, BlsG1Add, FP_LENGTH, SCALAR_LENGTH};
use crate::prelude::types::{make_address, Address, EthGas};
use crate::prelude::{Borrowed, Vec};
use crate::{EvmPrecompileResult, Precompile, PrecompileOutput};
use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, p1_affines};
use evm::{Context, ExitError};

/// Input length of `g1_mul` operation.
Expand All @@ -27,48 +26,16 @@ pub struct BlsG1Msm;

impl BlsG1Msm {
pub const ADDRESS: Address = make_address(0, 0xC);
}

impl Precompile for BlsG1Msm {
fn required_gas(input: &[u8]) -> Result<EthGas, ExitError>
where
Self: Sized,
{
let k = input.len() / INPUT_LENGTH;
Ok(EthGas::new(msm_required_gas(
k,
&DISCOUNT_TABLE,
BASE_GAS_FEE,
)?))
}

/// 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: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-multiexponentiation>
fn run(
&self,
input: &[u8],
target_gas: Option<EthGas>,
_context: &Context,
_is_static: bool,
) -> EvmPrecompileResult {
let input_len = input.len();
if input_len == 0 || input_len % INPUT_LENGTH != 0 {
return Err(ExitError::Other(Borrowed("ERR_BLS_G1MSM_INPUT_LEN")));
}
#[cfg(not(feature = "contract"))]
fn execute(input: &[u8]) -> Result<Vec<u8>, ExitError> {
use super::standalone::{extract_scalar_input, g1, NBITS};
use blst::{
blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine,
blst_p1_to_affine,
};

let k = input_len / INPUT_LENGTH;
let cost = Self::required_gas(input)?;
if let Some(target_gas) = target_gas {
if cost > target_gas {
return Err(ExitError::OutOfGas);
}
}
let k = input.len() / INPUT_LENGTH;
let mut g1_points: Vec<blst_p1> = Vec::with_capacity(k);
let mut scalars: Vec<u8> = Vec::with_capacity(k * SCALAR_LENGTH);
for i in 0..k {
Expand Down Expand Up @@ -111,7 +78,56 @@ impl Precompile for BlsG1Msm {
// SAFETY: multiexp_aff and multiexp are blst values.
unsafe { blst_p1_to_affine(&mut multiexp_aff, &multiexp) };

let output = g1::encode_g1_point(&multiexp_aff);
Ok(g1::encode_g1_point(&multiexp_aff))
}

#[cfg(feature = "contract")]
fn execute(input: &[u8]) -> Result<Vec<u8>, ExitError> {
todo!();
}
}

impl Precompile for BlsG1Msm {
fn required_gas(input: &[u8]) -> Result<EthGas, ExitError>
where
Self: Sized,
{
let k = input.len() / INPUT_LENGTH;
Ok(EthGas::new(msm_required_gas(
k,
&DISCOUNT_TABLE,
BASE_GAS_FEE,
)?))
}

/// 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: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-multiexponentiation>
fn run(
&self,
input: &[u8],
target_gas: Option<EthGas>,
_context: &Context,
_is_static: bool,
) -> EvmPrecompileResult {
let input_len = input.len();
if input_len == 0 || input_len % INPUT_LENGTH != 0 {
return Err(ExitError::Other(Borrowed("ERR_BLS_G1MSM_INPUT_LEN")));
}

let cost = Self::required_gas(input)?;
if let Some(target_gas) = target_gas {
if cost > target_gas {
return Err(ExitError::OutOfGas);
}
}

let output = Self::execute(input)?;
Ok(PrecompileOutput::without_logs(cost, output))
}
}
Expand Down
Loading

0 comments on commit 85df760

Please sign in to comment.