Skip to content

Commit

Permalink
Update EIP-3026 and EIP-2539 (polkadot-evm#1173)
Browse files Browse the repository at this point in the history
* Update eip-3026 gas meter

* Add mappint operation

* Remove TODOs

* Fix compile
  • Loading branch information
hujw77 authored and boundless-forest committed Sep 12, 2023
1 parent 9fd5782 commit 5d7e02c
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 21 deletions.
121 changes: 116 additions & 5 deletions frame/evm/precompile/bls12377/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -124,6 +131,32 @@ fn extract_fq(bytes: [u8; 64]) -> Result<Fq, PrecompileFailure> {
}
}

fn read_fq(input: &[u8], offset: usize) -> Result<Fq, PrecompileFailure> {
let mut buf = [0u8; 64];
read_input(input, &mut buf, offset);
extract_fq(buf)
}

fn read_fq2(input: &[u8], offset: usize) -> Result<Fq2, PrecompileFailure> {
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<G1Affine, HashToCurveError> {
let m2c = WBMap::<G1Config>::new()?;
m2c.map_to_curve(fq)
}

fn map_to_curve_g2(fq2: Fq2) -> Result<G2Affine, HashToCurveError> {
let m2c = WBMap::<G2Config>::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<G1Projective, PrecompileFailure> {
let mut px_buf = [0u8; 64];
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
32 changes: 16 additions & 16 deletions frame/evm/precompile/bw6761/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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] {
Expand Down Expand Up @@ -178,8 +185,7 @@ fn decode_g2(input: &[u8], offset: usize) -> Result<G2Projective, PrecompileFail
pub struct Bw6761G1Add;

impl Bw6761G1Add {
// TODO::to be estimated
const GAS_COST: u64 = 0;
const GAS_COST: u64 = 180;
}

impl Precompile for Bw6761G1Add {
Expand Down Expand Up @@ -216,8 +222,7 @@ impl Precompile for Bw6761G1Add {
pub struct Bw6761G1Mul;

impl Bw6761G1Mul {
// TODO::to be estimated
const GAS_COST: u64 = 0;
const GAS_COST: u64 = 64_000;
}

impl Precompile for Bw6761G1Mul {
Expand Down Expand Up @@ -254,7 +259,6 @@ impl Precompile for Bw6761G1Mul {
pub struct Bw6761G1MultiExp;

impl Bw6761G1MultiExp {
// TODO::to be estimated
const MULTIPLIER: u64 = 1_000;

/// Returns the gas required to execute the pre-compiled contract.
Expand Down Expand Up @@ -326,8 +330,7 @@ impl Precompile for Bw6761G1MultiExp {
pub struct Bw6761G2Add;

impl Bw6761G2Add {
// TODO::to be estimated
const GAS_COST: u64 = 0;
const GAS_COST: u64 = 180;
}

impl Precompile for Bw6761G2Add {
Expand Down Expand Up @@ -364,8 +367,7 @@ impl Precompile for Bw6761G2Add {
pub struct Bw6761G2Mul;

impl Bw6761G2Mul {
// TODO::to be estimated
const GAS_COST: u64 = 0;
const GAS_COST: u64 = 64_000;
}

impl Precompile for Bw6761G2Mul {
Expand Down Expand Up @@ -402,7 +404,6 @@ impl Precompile for Bw6761G2Mul {
pub struct Bw6761G2MultiExp;

impl Bw6761G2MultiExp {
// TODO::to be estimated
const MULTIPLIER: u64 = 1_000;

/// Returns the gas required to execute the pre-compiled contract.
Expand Down Expand Up @@ -474,9 +475,8 @@ impl Precompile for Bw6761G2MultiExp {
pub struct Bw6761Pairing;

impl Bw6761Pairing {
// TODO::to be estimated
const BASE_GAS: u64 = 0;
const PER_PAIR_GAS: u64 = 0;
const BASE_GAS: u64 = 120_000;
const PER_PAIR_GAS: u64 = 320_000;
}

impl Precompile for Bw6761Pairing {
Expand Down

0 comments on commit 5d7e02c

Please sign in to comment.