diff --git a/frame/evm/precompile/bls12377/src/lib.rs b/frame/evm/precompile/bls12377/src/lib.rs index d10bf6ab4f..ddc752e9a5 100644 --- a/frame/evm/precompile/bls12377/src/lib.rs +++ b/frame/evm/precompile/bls12377/src/lib.rs @@ -18,10 +18,17 @@ #![cfg_attr(not(feature = "std"), no_std)] // Arkworks -use ark_bls12_377::{Bls12_377, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; -use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup, VariableBaseMSM}; +use ark_bls12_377::{ + g1::Config as G1Config, g2::Config as G2Config, Bls12_377, Fq, Fq2, Fr, G1Affine, G1Projective, + G2Affine, G2Projective, +}; +use ark_ec::{ + hashing::{curve_maps::wb::WBMap, map_to_curve_hasher::MapToCurve, HashToCurveError}, + pairing::Pairing, + AffineRepr, CurveGroup, VariableBaseMSM, +}; use ark_ff::{BigInteger384, PrimeField, Zero}; -use ark_std::ops::Mul; +use ark_std::{ops::Mul, vec::Vec}; // Frontier use fp_evm::{ @@ -124,6 +131,32 @@ fn extract_fq(bytes: [u8; 64]) -> Result { } } +fn read_fq(input: &[u8], offset: usize) -> Result { + let mut buf = [0u8; 64]; + read_input(input, &mut buf, offset); + extract_fq(buf) +} + +fn read_fq2(input: &[u8], offset: usize) -> Result { + let mut x_buf = [0u8; 64]; + let mut y_buf = [0u8; 64]; + read_input(input, &mut x_buf, offset); + read_input(input, &mut y_buf, offset + 64); + let px = extract_fq(x_buf)?; + let py = extract_fq(y_buf)?; + Ok(Fq2::new(px, py)) +} + +fn map_to_curve_g1(fq: Fq) -> Result { + let m2c = WBMap::::new()?; + m2c.map_to_curve(fq) +} + +fn map_to_curve_g2(fq2: Fq2) -> Result { + let m2c = WBMap::::new()?; + m2c.map_to_curve(fq2) +} + /// Decode G1 given encoded (x, y) coordinates in 128 bytes returns a valid G1 Point. fn decode_g1(input: &[u8], offset: usize) -> Result { let mut px_buf = [0u8; 64]; @@ -483,8 +516,8 @@ pub struct Bls12377Pairing; impl Bls12377Pairing { /// https://eips.ethereum.org/EIPS/eip-2539#pairing-operation - const BASE_GAS: u64 = 65000; - const PER_PAIR_GAS: u64 = 55000; + const BASE_GAS: u64 = 65_000; + const PER_PAIR_GAS: u64 = 55_000; } impl Precompile for Bls12377Pairing { @@ -548,5 +581,83 @@ impl Precompile for Bls12377Pairing { } } +/// Bls12377MapG1 implements EIP-2539 MapG1 precompile. +pub struct Bls12377MapG1; + +impl Bls12377MapG1 { + const GAS_COST: u64 = 5_500; +} + +impl Precompile for Bls12377MapG1 { + /// Implements EIP-2539 Map_To_G1 precompile. + /// > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. + /// > Output of this call is `128` bytes and is G1 point following respective encoding rules. + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + handle.record_cost(Bls12377MapG1::GAS_COST)?; + + let input = handle.input(); + if input.len() != 64 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other("invalid input length".into()), + }); + } + + let fq = read_fq(input, 0)?; + let g1 = match map_to_curve_g1(fq) { + Ok(point) => point, + Err(_) => { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other("map to curve failed".into()), + }) + } + }; + + let output = encode_g1(g1); + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: output.to_vec(), + }) + } +} + +/// Bls12377MapG2 implements EIP-2539 MapG2 precompile. +pub struct Bls12377MapG2; + +impl Bls12377MapG2 { + const GAS_COST: u64 = 75_000; +} + +impl Precompile for Bls12377MapG2 { + /// Implements EIP-2539 Map_FP2_TO_G2 precompile logic. + /// > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. + /// > Output of this call is `256` bytes and is G2 point following respective encoding rules. + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + handle.record_cost(Bls12377MapG2::GAS_COST)?; + + let input = handle.input(); + if input.len() != 64 { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other("invalid input length".into()), + }); + } + + let fq2 = read_fq2(input, 0)?; + let g2 = match map_to_curve_g2(fq2) { + Ok(point) => point, + Err(_) => { + return Err(PrecompileFailure::Error { + exit_status: ExitError::Other("map to curve failed".into()), + }) + } + }; + + let output = encode_g2(g2); + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: output.to_vec(), + }) + } +} + #[cfg(test)] mod tests; diff --git a/frame/evm/precompile/bw6761/src/lib.rs b/frame/evm/precompile/bw6761/src/lib.rs index befd720ab5..3d20996e3b 100644 --- a/frame/evm/precompile/bw6761/src/lib.rs +++ b/frame/evm/precompile/bw6761/src/lib.rs @@ -21,7 +21,7 @@ use ark_bw6_761::{Fq, Fr, G1Affine, G1Projective, G2Affine, G2Projective, BW6_761}; use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup, VariableBaseMSM}; use ark_ff::{BigInteger768, PrimeField, Zero}; -use ark_std::ops::Mul; +use ark_std::{ops::Mul, vec::Vec}; // Frontier use fp_evm::{ @@ -30,8 +30,15 @@ use fp_evm::{ }; /// Gas discount table for BW6-761 G1 and G2 multi exponentiation operations. -// TODO::to be estimated -const BW6761_MULTIEXP_DISCOUNT_TABLE: [u16; 128] = [0u16; 128]; +const BW6761_MULTIEXP_DISCOUNT_TABLE: [u16; 128] = [ + 1266, 733, 561, 474, 422, 387, 362, 344, 329, 318, 308, 300, 296, 289, 283, 279, 275, 272, 269, + 266, 265, 260, 259, 256, 255, 254, 252, 251, 250, 249, 249, 220, 228, 225, 223, 219, 216, 214, + 212, 209, 209, 205, 203, 202, 200, 198, 196, 199, 195, 192, 192, 191, 190, 187, 186, 185, 184, + 184, 181, 181, 181, 180, 178, 179, 176, 177, 176, 175, 174, 173, 171, 171, 170, 170, 169, 168, + 168, 167, 167, 166, 165, 167, 166, 166, 165, 165, 164, 164, 163, 163, 162, 162, 160, 163, 159, + 162, 159, 160, 159, 159, 158, 158, 158, 158, 157, 157, 156, 155, 155, 156, 155, 155, 154, 155, + 154, 153, 153, 153, 152, 152, 152, 152, 151, 151, 151, 151, 151, 150, +]; /// Encode Fq as `96` bytes by performing Big-Endian encoding of the corresponding (unsigned) integer. fn encode_fq(field: Fq) -> [u8; 96] { @@ -178,8 +185,7 @@ fn decode_g2(input: &[u8], offset: usize) -> Result