From b9f0a266d47cf95104eefd2cabfd2f29f96f346e Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Thu, 16 Jan 2025 22:09:20 +0100 Subject: [PATCH 01/14] Update ethereum/execution-spec-tests to: pectra-devnet-5 v1.2.0 --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f005dc41..97f4d4a4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -86,7 +86,7 @@ jobs: - name: Download Ethereum spec tests fixtures run: | - wget https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-5%40v1.1.0/fixtures_pectra-devnet-5.tar.gz + wget https://github.com/ethereum/execution-spec-tests/releases/download/pectra-devnet-5%40v1.2.0/fixtures_pectra-devnet-5.tar.gz mkdir ethereum-spec-tests tar -xzf fixtures_pectra-devnet-5.tar.gz -C ethereum-spec-tests tree ethereum-spec-tests/fixtures/state_tests/prague/eip7702_set_code_tx From 0562cacf23fa54444ff78c48f71f3386e56ca6a5 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 22 Jan 2025 17:21:49 +0100 Subject: [PATCH 02/14] Added fp_to_bytes --- evm-tests/ethcore-builtin/Cargo.toml | 1 + evm-tests/ethcore-builtin/src/bls.rs | 31 ++++++++++++++++++++++++++++ evm-tests/ethcore-builtin/src/lib.rs | 1 + 3 files changed, 33 insertions(+) create mode 100644 evm-tests/ethcore-builtin/src/bls.rs diff --git a/evm-tests/ethcore-builtin/Cargo.toml b/evm-tests/ethcore-builtin/Cargo.toml index 0e573b61..58c1a8d2 100644 --- a/evm-tests/ethcore-builtin/Cargo.toml +++ b/evm-tests/ethcore-builtin/Cargo.toml @@ -23,6 +23,7 @@ hex-literal = "0.4" c-kzg = "1.0" derive_more = "0.99" hex = "0.4.3" +blst = "0.3.13" [dev-dependencies] maplit = "1.0.2" diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs new file mode 100644 index 00000000..91f7da2b --- /dev/null +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -0,0 +1,31 @@ +#![allow(dead_code)] +use blst::{blst_bendian_from_fp, blst_fp}; + +/// Number of bits used in the BLS12-381 curve finite field elements. +const NBITS: usize = 256; +/// Finite field element input length. +const FP_LENGTH: usize = 48; +/// Finite field element padded input length. +const PADDED_FP_LENGTH: usize = 64; +/// Quadratic extension of finite field element input length. +const PADDED_FP2_LENGTH: usize = 128; +/// Input elements padding length. +const PADDING_LENGTH: usize = 16; +/// Scalar length. +const SCALAR_LENGTH: usize = 32; +// Big-endian non-Montgomery form. +const MODULUS_REPR: [u8; 48] = [ + 0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac, 0xd7, + 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, + 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, +]; + +/// BLS Encodes a single finite field element into byte slice with padding. +pub fn x(out: &mut [u8], input: *const blst_fp) { + if out.len() != PADDED_FP_LENGTH { + return; + } + let (padding, rest) = out.split_at_mut(PADDING_LENGTH); + padding.fill(0); + unsafe { blst_bendian_from_fp(rest.as_mut_ptr(), input) }; +} diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index 388806cf..062b8026 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -18,6 +18,7 @@ #![warn(missing_docs)] +mod bls; mod kzg; use std::{ From a87dd22e4adf591cb4e999d0a1d324a61263f65e Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 22 Jan 2025 18:00:19 +0100 Subject: [PATCH 03/14] Added G1 point --- evm-tests/ethcore-builtin/src/bls.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index 91f7da2b..61519d04 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -use blst::{blst_bendian_from_fp, blst_fp}; +use blst::{blst_bendian_from_fp, blst_fp, blst_p1_affine}; /// Number of bits used in the BLS12-381 curve finite field elements. const NBITS: usize = 256; @@ -20,8 +20,14 @@ const MODULUS_REPR: [u8; 48] = [ 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, ]; +/// Length of each of the elements in a g1 operation input. +const G1_INPUT_ITEM_LENGTH: usize = 128; + +/// Output length of a g1 operation. +const G1_OUTPUT_LENGTH: usize = 128; + /// BLS Encodes a single finite field element into byte slice with padding. -pub fn x(out: &mut [u8], input: *const blst_fp) { +fn fp_to_bytes(out: &mut [u8], input: *const blst_fp) { if out.len() != PADDED_FP_LENGTH { return; } @@ -29,3 +35,14 @@ pub fn x(out: &mut [u8], input: *const blst_fp) { padding.fill(0); unsafe { blst_bendian_from_fp(rest.as_mut_ptr(), input) }; } + +/// Encodes a G1 point in affine format into byte slice with padded elements. +pub fn encode_g1_point(input: *const blst_p1_affine) -> Vec { + 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 +} From a6298acb086531b39fa704e2490aab70a0312bfe Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 22 Jan 2025 21:56:10 +0100 Subject: [PATCH 04/14] Added BLS G1 logic --- evm-tests/ethcore-builtin/src/bls.rs | 158 ++++++++++++++++++++++++--- 1 file changed, 144 insertions(+), 14 deletions(-) diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index 61519d04..a345c285 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -1,5 +1,12 @@ #![allow(dead_code)] -use blst::{blst_bendian_from_fp, blst_fp, blst_p1_affine}; + +use blst::{ + blst_bendian_from_fp, blst_fp, blst_fp_from_bendian, blst_p1_affine, blst_p1_affine_in_g1, + blst_p1_affine_on_curve, +}; +use std::borrow::Cow; +use std::cmp::Ordering; +use std::convert::TryInto; /// Number of bits used in the BLS12-381 curve finite field elements. const NBITS: usize = 256; @@ -20,12 +27,6 @@ const MODULUS_REPR: [u8; 48] = [ 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, ]; -/// Length of each of the elements in a g1 operation input. -const G1_INPUT_ITEM_LENGTH: usize = 128; - -/// Output length of a g1 operation. -const G1_OUTPUT_LENGTH: usize = 128; - /// BLS Encodes a single finite field element into byte slice with padding. fn fp_to_bytes(out: &mut [u8], input: *const blst_fp) { if out.len() != PADDED_FP_LENGTH { @@ -36,13 +37,142 @@ fn fp_to_bytes(out: &mut [u8], input: *const blst_fp) { unsafe { blst_bendian_from_fp(rest.as_mut_ptr(), input) }; } -/// Encodes a G1 point in affine format into byte slice with padded elements. -pub fn encode_g1_point(input: *const blst_p1_affine) -> Vec { - let mut out = vec![0u8; G1_OUTPUT_LENGTH]; - // SAFETY: out comes from fixed length array, input is a blst value. +/// Checks if the input is a valid big-endian representation of a field element. +fn is_valid_be(input: &[u8; 48]) -> bool { + for (i, modul) in input.iter().zip(MODULUS_REPR.iter()) { + match i.cmp(modul) { + Ordering::Greater => return false, + Ordering::Less => return true, + Ordering::Equal => continue, + } + } + // false if matching the modulus + false +} + +/// Checks whether or not the input represents a canonical field element, returning the field +/// element if successful. +fn fp_from_bendian(input: &[u8; 48]) -> Result> { + if !is_valid_be(input) { + return Err(Cow::from("non-canonical fp value")); + } + let mut fp = blst_fp::default(); + // SAFETY: input has fixed length, and fp 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); + // This performs the check for canonical field elements + blst_fp_from_bendian(&mut fp, input.as_ptr()); + } + + Ok(fp) +} + +/// Removes zeros with which the precompile inputs are left padded to 64 bytes. +fn remove_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], Cow<'static, str>> { + if input.len() != PADDED_FP_LENGTH { + return Err(Cow::from(format!( + "Padded input should be {PADDED_FP_LENGTH} bytes, was {}", + input.len() + ))); + } + let (padding, unpadded) = input.split_at(PADDING_LENGTH); + if !padding.iter().all(|&x| x == 0) { + return Err(Cow::from(format!( + "{PADDING_LENGTH} top bytes of input are not zero" + ))); + } + Ok(unpadded.try_into().unwrap()) +} + +pub mod g1 { + use super::*; + + /// Length of each of the elements in a g1 operation input. + const G1_INPUT_ITEM_LENGTH: usize = 128; + + /// Output length of a g1 operation. + const G1_OUTPUT_LENGTH: usize = 128; + + /// Encodes a G1 point in affine format into byte slice with padded elements. + pub fn encode_g1_point(input: *const blst_p1_affine) -> Vec { + 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 + } + + /// Returns a `blst_p1_affine` from the provided byte slices, which represent the x and y + /// affine coordinates of the point. + /// + /// If the x or y coordinate do not represent a canonical field element, an error is returned. + /// + /// See [fp_from_bendian] for more information. + pub fn decode_and_check_g1( + p0_x: &[u8; 48], + p0_y: &[u8; 48], + ) -> Result> { + let out = blst_p1_affine { + x: fp_from_bendian(p0_x)?, + y: fp_from_bendian(p0_y)?, + }; + + Ok(out) + } + + /// Extracts a G1 point in Affine format from a 128 byte slice representation. + /// + /// NOTE: This function will perform a G1 subgroup check if `subgroup_check` is set to `true`. + pub fn extract_g1_input( + input: &[u8], + subgroup_check: bool, + ) -> Result> { + if input.len() != G1_INPUT_ITEM_LENGTH { + return Err(Cow::from(format!( + "Input should be {G1_INPUT_ITEM_LENGTH} bytes, was {}", + input.len() + ))); + } + + 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 = decode_and_check_g1(input_p0_x, input_p0_y)?; + + if subgroup_check { + // NB: Subgroup checks + // + // Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // Implementations SHOULD use the optimized subgroup check method: + // + // https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks + // + // On any input that fail the subgroup check, the precompile MUST return an error. + // + // As endomorphism acceleration requires input on the correct subgroup, implementers MAY + // use endomorphism acceleration. + if unsafe { !blst_p1_affine_in_g1(&out) } { + return Err(Cow::from("Element not in G1")); + } + } else { + // From EIP-2537: + // + // Error cases: + // + // * An input is neither a point on the G1 elliptic curve nor the infinity point + // + // NB: There is no subgroup check for the G1 addition precompile. + // + // We use blst_p1_affine_on_curve instead of blst_p1_affine_in_g1 because the latter performs + // the subgroup check. + // + // SAFETY: out is a blst value. + if unsafe { !blst_p1_affine_on_curve(&out) } { + return Err(Cow::from("Element not on G1 curve")); + } + } + + Ok(out) } - out } From ea8da31d0c7183c2d17c01d92d35542f21344dee Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Thu, 23 Jan 2025 15:12:06 +0100 Subject: [PATCH 05/14] Added BLS G2 --- evm-tests/ethcore-builtin/src/bls.rs | 118 ++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index a345c285..6ff4121a 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -83,7 +83,7 @@ fn remove_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], Cow<'static, str>> { Ok(unpadded.try_into().unwrap()) } -pub mod g1 { +mod g1 { use super::*; /// Length of each of the elements in a g1 operation input. @@ -176,3 +176,119 @@ pub mod g1 { Ok(out) } } + +mod g2 { + use super::*; + use blst::{blst_fp2, blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve}; + + /// 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. + const G2_OUTPUT_LENGTH: usize = 256; + + /// Encodes a G2 point in affine format into byte slice with padded elements. + pub fn encode_g2_point(input: &blst_p2_affine) -> Vec { + let mut out = vec![0u8; G2_OUTPUT_LENGTH]; + 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], + ); + out + } + + /// Convert the following field elements from byte slices into a `blst_p2_affine` point. + pub fn decode_and_check_g2( + x1: &[u8; 48], + x2: &[u8; 48], + y1: &[u8; 48], + y2: &[u8; 48], + ) -> Result> { + Ok(blst_p2_affine { + x: check_canonical_fp2(x1, x2)?, + y: check_canonical_fp2(y1, y2)?, + }) + } + + /// Checks whether or not the input represents a canonical fp2 field element, returning the field + /// element if successful. + pub fn check_canonical_fp2( + input_1: &[u8; 48], + input_2: &[u8; 48], + ) -> Result> { + let fp_1 = fp_from_bendian(input_1)?; + let fp_2 = fp_from_bendian(input_2)?; + + let fp2 = blst_fp2 { fp: [fp_1, fp_2] }; + + Ok(fp2) + } + + /// Extracts a G2 point in Affine format from a 256 byte slice representation. + /// + /// NOTE: This function will perform a G2 subgroup check if `subgroup_check` is set to `true`. + pub fn extract_g2_input( + input: &[u8], + subgroup_check: bool, + ) -> Result> { + if input.len() != G2_INPUT_ITEM_LENGTH { + return Err(Cow::from(format!( + "Input should be {G2_INPUT_ITEM_LENGTH} bytes, was {}", + input.len() + ))); + } + + let mut input_fps = [&[0; FP_LENGTH]; 4]; + for i in 0..4 { + input_fps[i] = + remove_padding(&input[i * PADDED_FP_LENGTH..(i + 1) * PADDED_FP_LENGTH])?; + } + + let out = decode_and_check_g2(input_fps[0], input_fps[1], input_fps[2], input_fps[3])?; + + if subgroup_check { + // NB: Subgroup checks + // + // Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // Implementations SHOULD use the optimized subgroup check method: + // + // https://eips.ethereum.org/assets/eip-2537/fast_subgroup_checks + // + // On any input that fail the subgroup check, the precompile MUST return an error. + // + // As endomorphism acceleration requires input on the correct subgroup, implementers MAY + // use endomorphism acceleration. + if unsafe { !blst_p2_affine_in_g2(&out) } { + return Err(Cow::from("Element not in G2")); + } + } else { + // From EIP-2537: + // + // Error cases: + // + // * An input is neither a point on the G2 elliptic curve nor the infinity point + // + // NB: There is no subgroup check for the G2 addition precompile. + // + // We use blst_p2_affine_on_curve instead of blst_p2_affine_in_g2 because the latter performs + // the subgroup check. + // + // SAFETY: out is a blst value. + if unsafe { !blst_p2_affine_on_curve(&out) } { + return Err(Cow::from("Element not on G2 curve")); + } + } + + Ok(out) + } +} From 343504236cb5d5d6835fa9b746c914ed1794e942 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Thu, 23 Jan 2025 17:39:26 +0100 Subject: [PATCH 06/14] Add BLS G1-Add precompile strict. Big rafactoring for old unused precompiles code --- evm-tests/ethcore-builtin/Cargo.toml | 1 + evm-tests/ethcore-builtin/src/lib.rs | 974 +++++++++++++-------------- 2 files changed, 486 insertions(+), 489 deletions(-) diff --git a/evm-tests/ethcore-builtin/Cargo.toml b/evm-tests/ethcore-builtin/Cargo.toml index 58c1a8d2..fb431b4a 100644 --- a/evm-tests/ethcore-builtin/Cargo.toml +++ b/evm-tests/ethcore-builtin/Cargo.toml @@ -18,6 +18,7 @@ parity-bytes = "0.1" libsecp256k1 = "0.7" ripemd = { version = "0.1", default-features = false } sha2 = { version = "0.10.0", default-features = false } +# TODO: remove eth_pairings = { git = "https://github.com/matter-labs/eip1962.git", default-features = false, features = ["eip_2537"], rev = "ece6cbabc41948db4200e41f0bfdab7ab94c7af8" } hex-literal = "0.4" c-kzg = "1.0" diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index 062b8026..8cc55112 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -32,8 +32,7 @@ use std::{ use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; use eip_152::compress; use eth_pairings::public_interface::eip2537::{ - EIP2537Executor, SCALAR_BYTE_LENGTH, SERIALIZED_G1_POINT_BYTE_LENGTH, - SERIALIZED_G2_POINT_BYTE_LENGTH, + SCALAR_BYTE_LENGTH, SERIALIZED_G1_POINT_BYTE_LENGTH, SERIALIZED_G2_POINT_BYTE_LENGTH, }; use ethereum_types::{H256, U256}; use keccak_hash::keccak; @@ -672,25 +671,27 @@ enum EthereumBuiltin { Bn128Pairing(Bn128Pairing), /// blake2_f (The Blake2 compression function F, EIP-152) Blake2F(Blake2F), + Kgz(Kzg), /// bls12_381 addition in g1 Bls12G1Add(Bls12G1Add), - /// bls12_381 multiplication in g1 - Bls12G1Mul(Bls12G1Mul), - /// bls12_381 multiexponentiation in g1 - Bls12G1MultiExp(Bls12G1MultiExp), - /// bls12_381 addition in g2 - Bls12G2Add(Bls12G2Add), - /// bls12_381 multiplication in g2 - Bls12G2Mul(Bls12G2Mul), - /// bls12_381 multiexponentiation in g2 - Bls12G2MultiExp(Bls12G2MultiExp), - /// bls12_381 pairing - Bls12Pairing(Bls12Pairing), - /// bls12_381 fp to g1 mapping - Bls12MapFpToG1(Bls12MapFpToG1), - /// bls12_381 fp2 to g2 mapping - Bls12MapFp2ToG2(Bls12MapFp2ToG2), - Kgz(Kzg), + /* TODO: refator it + /// bls12_381 multiplication in g1 + Bls12G1Mul(Bls12G1Mul), + /// bls12_381 multiexponentiation in g1 + Bls12G1MultiExp(Bls12G1MultiExp), + /// bls12_381 addition in g2 + Bls12G2Add(Bls12G2Add), + /// bls12_381 multiplication in g2 + Bls12G2Mul(Bls12G2Mul), + /// bls12_381 multiexponentiation in g2 + Bls12G2MultiExp(Bls12G2MultiExp), + /// bls12_381 pairing + Bls12Pairing(Bls12Pairing), + /// bls12_381 fp to g1 mapping + Bls12MapFpToG1(Bls12MapFpToG1), + /// bls12_381 fp2 to g2 mapping + Bls12MapFp2ToG2(Bls12MapFp2ToG2), + */ } impl FromStr for EthereumBuiltin { @@ -707,16 +708,18 @@ impl FromStr for EthereumBuiltin { "alt_bn128_mul" => Ok(Self::Bn128Mul(Bn128Mul)), "alt_bn128_pairing" => Ok(Self::Bn128Pairing(Bn128Pairing)), "blake2_f" => Ok(Self::Blake2F(Blake2F)), - "bls12_381_g1_add" => Ok(Self::Bls12G1Add(Bls12G1Add)), - "bls12_381_g1_mul" => Ok(Self::Bls12G1Mul(Bls12G1Mul)), - "bls12_381_g1_multiexp" => Ok(Self::Bls12G1MultiExp(Bls12G1MultiExp)), - "bls12_381_g2_add" => Ok(Self::Bls12G2Add(Bls12G2Add)), - "bls12_381_g2_mul" => Ok(Self::Bls12G2Mul(Bls12G2Mul)), - "bls12_381_g2_multiexp" => Ok(Self::Bls12G2MultiExp(Bls12G2MultiExp)), - "bls12_381_pairing" => Ok(Self::Bls12Pairing(Bls12Pairing)), - "bls12_381_fp_to_g1" => Ok(Self::Bls12MapFpToG1(Bls12MapFpToG1)), - "bls12_381_fp2_to_g2" => Ok(Self::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), "kzg" => Ok(Self::Kgz(Kzg)), + "bls12_381_g1_add" => Ok(Self::Bls12G1Add(Bls12G1Add)), + /* TODO: refactor it + "bls12_381_g1_mul" => Ok(Self::Bls12G1Mul(Bls12G1Mul)), + "bls12_381_g1_multiexp" => Ok(Self::Bls12G1MultiExp(Bls12G1MultiExp)), + "bls12_381_g2_add" => Ok(Self::Bls12G2Add(Bls12G2Add)), + "bls12_381_g2_mul" => Ok(Self::Bls12G2Mul(Bls12G2Mul)), + "bls12_381_g2_multiexp" => Ok(Self::Bls12G2MultiExp(Bls12G2MultiExp)), + "bls12_381_pairing" => Ok(Self::Bls12Pairing(Bls12Pairing)), + "bls12_381_fp_to_g1" => Ok(Self::Bls12MapFpToG1(Bls12MapFpToG1)), + "bls12_381_fp2_to_g2" => Ok(Self::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), + */ _ => Err(()), } } @@ -734,7 +737,9 @@ impl Implementation for EthereumBuiltin { Self::Bn128Mul(inner) => inner.execute(input, output), Self::Bn128Pairing(inner) => inner.execute(input, output), Self::Blake2F(inner) => inner.execute(input, output), + Self::Kgz(inner) => inner.execute(input, output), Self::Bls12G1Add(inner) => inner.execute(input, output), + /* Refactor it Self::Bls12G1Mul(inner) => inner.execute(input, output), Self::Bls12G1MultiExp(inner) => inner.execute(input, output), Self::Bls12G2Add(inner) => inner.execute(input, output), @@ -743,7 +748,7 @@ impl Implementation for EthereumBuiltin { Self::Bls12Pairing(inner) => inner.execute(input, output), Self::Bls12MapFpToG1(inner) => inner.execute(input, output), Self::Bls12MapFp2ToG2(inner) => inner.execute(input, output), - Self::Kgz(inner) => inner.execute(input, output), + */ } } } @@ -784,10 +789,15 @@ pub struct Bn128Pairing; /// The Blake2F builtin pub struct Blake2F; +#[derive(Debug)] +/// The Kzg builtin +pub struct Kzg; + #[derive(Debug)] /// The Bls12G1Add builtin. pub struct Bls12G1Add; +/* TODO: refactor it #[derive(Debug)] /// The Bls12G1Mul builtin. pub struct Bls12G1Mul; @@ -819,10 +829,7 @@ pub struct Bls12MapFpToG1; #[derive(Debug)] /// The Bls12MapFp2ToG2 builtin. pub struct Bls12MapFp2ToG2; - -#[derive(Debug)] -/// The Kzg builtin -pub struct Kzg; +*/ impl Implementation for Identity { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { @@ -1085,24 +1092,6 @@ impl Implementation for Bn128Mul { } } -impl Implementation for Bn128Pairing { - /// Can fail if: - /// - input length is not a multiple of 192 - /// - any of odd points does not belong to bn128 curve - /// - any of even points does not belong to the twisted bn128 curve over the field F_p^2 = F_p[i] / (i^2 + 1) - fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - if input.len() % 192 != 0 { - return Err("Invalid input length, must be multiple of 192 (3 * (32*2))"); - } - - if let Err(err) = self.execute_with_error(input, output) { - trace!(target: "builtin", "Pairing error: {:?}", err); - return Err(err); - } - Ok(()) - } -} - impl Bn128Pairing { fn execute_with_error(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { use bn::{pairing_batch, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; @@ -1167,25 +1156,45 @@ impl Bn128Pairing { } } -impl Implementation for Bls12G1Add { +impl Implementation for Bn128Pairing { + /// Can fail if: + /// - input length is not a multiple of 192 + /// - any of odd points does not belong to bn128 curve + /// - any of even points does not belong to the twisted bn128 curve over the field F_p^2 = F_p[i] / (i^2 + 1) fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::g1_add(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); + if input.len() % 192 != 0 { + return Err("Invalid input length, must be multiple of 192 (3 * (32*2))"); + } - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12G1Add error: {:?}", e); + if let Err(err) = self.execute_with_error(input, output) { + trace!(target: "builtin", "Pairing error: {:?}", err); + return Err(err); + } + Ok(()) + } +} - Err("Bls12G1Add error") - } +impl Implementation for Kzg { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { + // Get and verify KZG input. + let kzg_input: kzg::KzgInput = input.try_into()?; + let kzg_settings = kzg::EnvKzgSettings::Default; + if !kzg_input.verify_kzg_proof(&kzg_settings.get()) { + return Err("BlobVerifyKzgProofFailed"); } + output.write(0, kzg::RETURN_VALUE.as_slice()); + Ok(()) } } +impl Implementation for Bls12G1Add { + fn execute(&self, _input: &[u8], _output: &mut BytesRef) -> Result<(), &'static str> { + Ok(()) + } +} + +/* TODO: refactor it + impl Implementation for Bls12G1Mul { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { let result = EIP2537Executor::g1_mul(input); @@ -1337,26 +1346,11 @@ impl Implementation for Bls12MapFp2ToG2 { } } } - -impl Implementation for Kzg { - fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - // Get and verify KZG input. - let kzg_input: kzg::KzgInput = input.try_into()?; - let kzg_settings = kzg::EnvKzgSettings::Default; - if !kzg_input.verify_kzg_proof(&kzg_settings.get()) { - return Err("BlobVerifyKzgProofFailed"); - } - output.write(0, kzg::RETURN_VALUE.as_slice()); - Ok(()) - } -} +*/ #[cfg(test)] mod tests { - use super::{ - Bls12ConstOperations, Bls12PairingPrice, Bls12PairingPricer, Builtin, EthereumBuiltin, - FromStr, Implementation, Linear, ModexpPricer, Pricing, - }; + use super::{Builtin, EthereumBuiltin, FromStr, Implementation, Linear, ModexpPricer, Pricing}; use ethereum_types::U256; use ethjson::spec::builtin::{ AltBn128Pairing as JsonAltBn128PairingPricing, Builtin as JsonBuiltin, @@ -2212,413 +2206,415 @@ mod tests { assert_eq!(b.cost(&[0; 1], 0), U256::from(0), "not activated yet"); assert_eq!(b.cost(&[0; 1], 1), U256::from(1_337), "use price #3"); } - - #[test] - fn bls12_381_g1_add() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g1_add").unwrap(), - }; - - let input = hex!(" - 00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb - 0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed2 - 000000000000000000000000000000000441e7f7f96198e4c23bd5eb16f1a7f045dbc8c53219ab2bcea91d3a027e2dfe659feac64905f8b9add7e4bfc91bec2b - 0000000000000000000000000000000005fc51bb1b40c87cd4292d4b66f8ca5ce4ef9abd2b69d4464b4879064203bda7c9fc3f896a3844ebc713f7bb20951d95 - "); - let expected = hex!(" - 0000000000000000000000000000000016b8ab56b45a9294466809b8e858c1ad15ad0d52cfcb62f8f5753dc94cee1de6efaaebce10701e3ec2ecaa9551024ea - 600000000000000000000000000000000124571eec37c0b1361023188d66ec17c1ec230d31b515e0e81e599ec19e40c8a7c8cdea9735bc3d8b4e37ca7e5dd71f6 - "); - - let mut output = [0u8; 128]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g1_mul() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), - }; - - let input = hex!(" - 000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e - 000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa3 - ac23d04ee3acc757aae6795532ce4c9f34534e506a4d843a26b052a040c79659 - "); - let expected = hex!(" - 000000000000000000000000000000001227b7021e9d3dc8bcbf5b346fc503f7f8576965769c5e22bb70056eef03c84b8c80290ae9ce20345770290c55549bce - 00000000000000000000000000000000188ddbbfb4ad2d34a8d3dc0ec92b70b63caa73ad7dea0cc9740bac2309b4bb11107912bd086379746e9a9bcd26d4db58 - "); - - let mut output = [0u8; 128]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g1_multiexp() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g1_multiexp").unwrap(), - }; - let input = hex!(" - 0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f56 - 0000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee - b3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e - 00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb - 0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed2 - 4d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d - 0000000000000000000000000000000008ab7b556c672db7883ec47efa6d98bb08cec7902ebb421aac1c31506b177ac444ffa2d9b400a6f1cbdc6240c607ee11 - 0000000000000000000000000000000016b7fa9adf4addc2192271ce7ad3c8d8f902d061c43b7d2e8e26922009b777855bffabe7ed1a09155819eabfa87f276f - 973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1 - 0000000000000000000000000000000015ff9a232d9b5a8020a85d5fe08a1dcfb73ece434258fe0e2fddf10ddef0906c42dcb5f5d62fc97f934ba900f17beb33 - 0000000000000000000000000000000009cfe4ee2241d9413c616462d7bac035a6766aeaab69c81e094d75b840df45d7e0dfac0265608b93efefb9a8728b98e4 - 4c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a - 0000000000000000000000000000000017a17b82e3bfadf3250210d8ef572c02c3610d65ab4d7366e0b748768a28ee6a1b51f77ed686a64f087f36f641e7dca9 - 00000000000000000000000000000000077ea73d233ccea51dc4d5acecf6d9332bf17ae51598f4b394a5f62fb387e9c9aa1d6823b64a074f5873422ca57545d3 - 8964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b89 - 000000000000000000000000000000000c1243478f4fbdc21ea9b241655947a28accd058d0cdb4f9f0576d32f09dddaf0850464550ff07cab5927b3e4c863ce9 - 0000000000000000000000000000000015fb54db10ffac0b6cd374eb7168a8cb3df0a7d5f872d8e98c1f623deb66df5dd08ff4c3658f2905ec8bd02598bd4f90 - 787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c944 - 000000000000000000000000000000000328f09584b6d6c98a709fc22e184123994613aca95a28ac53df8523b92273eb6f4e2d9b2a7dcebb474604d54a210719 - 000000000000000000000000000000001220ebde579911fe2e707446aaad8d3789fae96ae2e23670a4fd856ed82daaab704779eb4224027c1ed9460f39951a1b - aaee7ae2a237e8e53560c79e7baa9adf9c00a0ea4d6f514e7a6832eb15cef1e1 - 0000000000000000000000000000000002ebfa98aa92c32a29ebe17fcb1819ba82e686abd9371fcee8ea793b4c72b6464085044f818f1f5902396df0122830cb - 00000000000000000000000000000000001184715b8432ed190b459113977289a890f68f6085ea111466af15103c9c02467da33e01d6bff87fd57db6ccba442a - dac6ed3ef45c1d7d3028f0f89e5458797996d3294b95bebe049b76c7d0db317c - 0000000000000000000000000000000009d6424e002439998e91cd509f85751ad25e574830c564e7568347d19e3f38add0cab067c0b4b0801785a78bcbeaf246 - 000000000000000000000000000000000ef6d7db03ee654503b46ff0dbc3297536a422e963bda9871a8da8f4eeb98dedebd6071c4880b4636198f4c2375dc795 - bb30985756c3ca075114c92f231575d6befafe4084517f1166a47376867bd108 - 0000000000000000000000000000000002d1cdb93191d1f9f0308c2c55d0208a071f5520faca7c52ab0311dbc9ba563bd33b5dd6baa77bf45ac2c3269e945f48 - 00000000000000000000000000000000072a52106e6d7b92c594c4dacd20ef5fab7141e45c231457cd7e71463b2254ee6e72689e516fa6a8f29f2a173ce0a190 - fb730105809f64ea522983d6bbb62f7e2e8cbf702685e9be10e2ef71f8187672 - 0000000000000000000000000000000000641642f6801d39a09a536f506056f72a619c50d043673d6d39aa4af11d8e3ded38b9c3bbc970dbc1bd55d68f94b50d - 0000000000000000000000000000000009ab050de356a24aea90007c6b319614ba2f2ed67223b972767117769e3c8e31ee4056494628fb2892d3d37afb6ac943 - b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea - 000000000000000000000000000000000fd4893addbd58fb1bf30b8e62bef068da386edbab9541d198e8719b2de5beb9223d87387af82e8b55bd521ff3e47e2d - 000000000000000000000000000000000f3a923b76473d5b5a53501790cb02597bb778bdacb3805a9002b152d22241ad131d0f0d6a260739cbab2c2fe602870e - 3b77283d0a7bb9e17a27e66851792fdd605cc0a339028b8985390fd024374c76 - 0000000000000000000000000000000002cb4b24c8aa799fd7cb1e4ab1aab1372113200343d8526ea7bc64dfaf926baf5d90756a40e35617854a2079cd07fba4 - 0000000000000000000000000000000003327ca22bd64ebd673cc6d5b02b2a8804d5353c9d251637c4273ad08d581cc0d58da9bea27c37a0b3f4961dbafd276b - dd994eae929aee7428fdda2e44f8cb12b10b91c83b22abc8bbb561310b62257c - 00000000000000000000000000000000024ad70f2b2105ca37112858e84c6f5e3ffd4a8b064522faae1ecba38fabd52a6274cb46b00075deb87472f11f2e67d9 - 0000000000000000000000000000000010a502c8b2a68aa30d2cb719273550b9a3c283c35b2e18a01b0b765344ffaaa5cb30a1e3e6ecd3a53ab67658a5787681 - 7010b134989c8368c7f831f9dd9f9a890e2c1435681107414f2e8637153bbf6a - 0000000000000000000000000000000000704cc57c8e0944326ddc7c747d9e7347a7f6918977132eea269f161461eb64066f773352f293a3ac458dc3ccd5026a - 000000000000000000000000000000001099d3c2bb2d082f2fdcbed013f7ac69e8624f4fcf6dfab3ee9dcf7fbbdb8c49ee79de40e887c0b6828d2496e3a6f768 - 94c68bc8d91ac8c489ee87dbfc4b94c93c8bbd5fc04c27db8b02303f3a659054 - 00000000000000000000000000000000130535a29392c77f045ac90e47f2e7b3cffff94494fe605aad345b41043f6663ada8e2e7ecd3d06f3b8854ef92212f42 - 000000000000000000000000000000001699a3cc1f10cd2ed0dc68eb916b4402e4f12bf4746893bf70e26e209e605ea89e3d53e7ac52bd07713d3c8fc671931d - b3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746 - "); - let expected = hex!(" - 000000000000000000000000000000000b370fc4ca67fb0c3c270b1b4c4816ef953cd9f7cf6ad20e88099c40aace9c4bb3f4cd215e5796f65080c69c9f4d2a0f - 0000000000000000000000000000000007203220935ddc0190e2d7a99ec3f9231da550768373f9a5933dffd366f48146f8ea5fe5dee6539d925288083bb5a8f1 - "); - - let mut output = [0u8; 128]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g2_add() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g2_add").unwrap(), - }; - let input = hex!(" - 00000000000000000000000000000000161c595d151a765c7dee03c9210414cdffab84b9078b4b98f9df09be5ec299b8f6322c692214f00ede97958f235c352b - 00000000000000000000000000000000106883e0937cb869e579b513bde8f61020fcf26be38f8b98eae3885cedec2e028970415fc653cf10e64727b7f6232e06 - 000000000000000000000000000000000f351a82b733af31af453904874b7ca6252957a1ab51ec7f7b6fff85bbf3331f870a7e72a81594a9930859237e7a154d - 0000000000000000000000000000000012fcf20d1750901f2cfed64fd362f010ee64fafe9ddab406cc352b65829b929881a50514d53247d1cca7d6995d0bc9b2 - 00000000000000000000000000000000148b7dfc21521d79ff817c7a0305f1048851e283be13c07d5c04d28b571d48172838399ba539529e8d037ffd1f729558 - 0000000000000000000000000000000003015abea326c15098f5205a8b2d3cd74d72dac59d60671ca6ef8c9c714ea61ffdacd46d1024b5b4f7e6b3b569fabaf2 - 0000000000000000000000000000000011f0c512fe7dc2dd8abdc1d22c2ecd2e7d1b84f8950ab90fc93bf54badf7bb9a9bad8c355d52a5efb110dca891e4cc3d - 0000000000000000000000000000000019774010814d1d94caf3ecda3ef4f5c5986e966eaf187c32a8a5a4a59452af0849690cf71338193f2d8435819160bcfb - "); - let expected = hex!(" - 000000000000000000000000000000000383ab7a17cc57e239e874af3f1aaabba0e64625b848676712f05f56132dbbd1cadfabeb3fe1f461daba3f1720057ddd - 00000000000000000000000000000000096967e9b3747f1b8e344535eaa0c51e70bc77412bfaa2a7ce76f11f570c9febb8f4227316866a416a50436d098e6f9a - 000000000000000000000000000000001079452b7519a7b090d668d54c266335b1cdd1080ed867dd17a2476b11c2617da829bf740e51cb7dfd60d73ed02c0c67 - 00000000000000000000000000000000015fc3a972e05cbd9014882cfe6f2f16d0291c403bf28b05056ac625e4f71dfb1295c85d73145ef554614e6eb2d5bf02 - "); - - let mut output = [0u8; 256]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g2_mul() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g2_mul").unwrap(), - }; - - let input = hex!(" - 00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829 - 000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d9 - 00000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c0 - 00000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196 - b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea - "); - let expected = hex!(" - 000000000000000000000000000000000b24adeb2ca184c9646cb39f45e0cf8711e10bf308ddae06519562b0af3b43be44c2fcb90622726f7446ed690551d30e - 00000000000000000000000000000000069467c3edc19416067f572c51740ba8e0e7380121ade98e38ce26d907a2bf3a4e82af2bd195b6c3b7c9b29218880531 - 000000000000000000000000000000000eb8c90d0727511be53ffcb6f3b144c07983ed4b76d31ab003e45b37c7bc1066910f5e29f5adad5757af979dd0d8351d - 0000000000000000000000000000000004760f8d814189dcd893949797a3c4f56f2b60964bba3a4fc741e7ead05eb886787b2502fc64b20363eeba44e65d0ca0 - "); - - let mut output = [0u8; 256]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g2_multiexp() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g2_multiexp").unwrap(), - }; - - let input = hex!(" - 00000000000000000000000000000000039b10ccd664da6f273ea134bb55ee48f09ba585a7e2bb95b5aec610631ac49810d5d616f67ba0147e6d1be476ea220e - 0000000000000000000000000000000000fbcdff4e48e07d1f73ec42fe7eb026f5c30407cfd2f22bbbfe5b2a09e8a7bb4884178cb6afd1c95f80e646929d3004 - 0000000000000000000000000000000001ed3b0e71acb0adbf44643374edbf4405af87cfc0507db7e8978889c6c3afbe9754d1182e98ac3060d64994d31ef576 - 000000000000000000000000000000001681a2bf65b83be5a2ca50430949b6e2a099977482e9405b593f34d2ed877a3f0d1bddc37d0cec4d59d7df74b2b8f2df - b3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e - 0000000000000000000000000000000018c0ada6351b70661f053365deae56910798bd2ace6e2bf6ba4192d1a229967f6af6ca1c9a8a11ebc0a232344ee0f6d6 - 000000000000000000000000000000000cc70a587f4652039d8117b6103858adcd9728f6aebe230578389a62da0042b7623b1c0436734f463cfdd187d2090324 - 0000000000000000000000000000000009f50bd7beedb23328818f9ffdafdb6da6a4dd80c5a9048ab8b154df3cad938ccede829f1156f769d9e149791e8e0cd9 - 00000000000000000000000000000000079ba50d2511631b20b6d6f3841e616e9d11b68ec3368cd60129d9d4787ab56c4e9145a38927e51c9cd6271d493d9388 - 4d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d - 0000000000000000000000000000000003632695b09dbf86163909d2bb25995b36ad1d137cf252860fd4bb6c95749e19eb0c1383e9d2f93f2791cb0cf6c8ed9d - 000000000000000000000000000000001688a855609b0bbff4452d146396558ff18777f329fd4f76a96859dabfc6a6f6977c2496280dbe3b1f8923990c1d6407 - 000000000000000000000000000000000c8567fee05d05af279adc67179468a29d7520b067dbb348ee315a99504f70a206538b81a457cce855f4851ad48b7e80 - 000000000000000000000000000000001238dcdfa80ea46e1500026ea5feadb421de4409f4992ffbf5ae59fa67fd82f38452642a50261b849e74b4a33eed70cc - 973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1 - 000000000000000000000000000000000149704960cccf9d5ea414c73871e896b1d4cf0a946b0db72f5f2c5df98d2ec4f3adbbc14c78047961bc9620cb6cfb59 - 00000000000000000000000000000000140c5d25e534fb1bfdc19ba4cecaabe619f6e0cd3d60b0f17dafd7bcd27b286d4f4477d00c5e1af22ee1a0c67fbf177c - 00000000000000000000000000000000029a1727041590b8459890de736df15c00d80ab007c3aee692ddcdf75790c9806d198e9f4502bec2f0a623491c3f877d - 0000000000000000000000000000000008a94c98baa9409151030d4fae2bd4a64c6f11ea3c99b9661fdaed226b9a7c2a7d609be34afda5d18b8911b6e015bf49 - 4c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a - 000000000000000000000000000000001156d478661337478ab0cbc877a99d9e4d9824a2b3f605d41404d6b557b3ffabbf42635b0bbcb854cf9ed8b8637561a8 - 000000000000000000000000000000001147ed317d5642e699787a7b47e6795c9a8943a34a694007e44f8654ba96390cf19f010dcf695e22c21874022c6ce291 - 000000000000000000000000000000000c6dccdf920fd5e7fae284115511952633744c6ad94120d9cae6acda8a7c23c48bd912cba6c38de5159587e1e6cad519 - 000000000000000000000000000000001944227d462bc2e5dcc6f6db0f83dad411ba8895262836f975b2b91e06fd0e2138862162acc04e9e65050b34ccbd1a4e - 8964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b89 - 0000000000000000000000000000000019c31e3ab8cc9c920aa8f56371f133b6cb8d7b0b74b23c0c7201aca79e5ae69dc01f1f74d2492dcb081895b17d106b4e - 000000000000000000000000000000001789b0d371bd63077ccde3dbbebf3531368feb775bced187fb31cc6821481664600978e323ff21085b8c08e0f21daf72 - 000000000000000000000000000000000009eacfe8f4a2a9bae6573424d07f42bd6af8a9d55f71476a7e3c7a4b2b898550c1e72ec13afd4eff22421a03af1d31 - 000000000000000000000000000000000410bd4ea74dcfa33f2976aa1b571c67cbb596ab10f76a8aaf4548f1097e55b3373bff02683f806cb84e1e0e877819e2 - 787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c944 - 00000000000000000000000000000000147f09986691f2e57073378e8bfd58804241eed7934f6adfe6d0a6bac4da0b738495778a303e52113e1c80e698476d50 - 000000000000000000000000000000000762348b84c92a8ca6de319cf1f8f11db296a71b90fe13e1e4bcd25903829c00a5d2ad4b1c8d98c37eaad7e042ab023d - 0000000000000000000000000000000011d1d94530d4a2daf0e902a5c3382cd135938557f94b04bccea5e16ea089c5e020e13524c854a316662bd68784fe31f3 - 00000000000000000000000000000000070828522bec75b6a492fd9bca7b54dac6fbbf4f0bc3179d312bb65c647439e3868e4d5b21af5a64c93aeee8a9b7e46e - aaee7ae2a237e8e53560c79e7baa9adf9c00a0ea4d6f514e7a6832eb15cef1e1 - 000000000000000000000000000000000690a0869204c8dced5ba0ce13554b2703a3f18afb8fa8fa1c457d79c58fdc25471ae85bafad52e506fc1917fc3becff - 0000000000000000000000000000000010f7dbb16f8571ede1cec79e3f9ea03ae6468d7285984713f19607f5cab902b9a6b7cbcfd900be5c2e407cc093ea0e67 - 00000000000000000000000000000000151caf87968433cb1f85fc1854c57049be22c26497a86bfbd66a2b3af121d894dba8004a17c6ff96a5843c2719fa32d1 - 0000000000000000000000000000000011f0270f2b039409f70392879bcc2c67c836c100cf9883d3dc48d7adbcd52037d270539e863a951acd47ecaa1ca4db12 - dac6ed3ef45c1d7d3028f0f89e5458797996d3294b95bebe049b76c7d0db317c - 0000000000000000000000000000000017fae043c8fd4c520a90d4a6bd95f5b0484acc279b899e7b1d8f7f7831cc6ba37cd5965c4dc674768f5805842d433af3 - 0000000000000000000000000000000008ddd7b41b8fa4d29fb931830f29b46f4015ec202d51cb969d7c832aafc0995c875cd45eff4a083e2d5ecb5ad185b64f - 0000000000000000000000000000000015d384ab7e52420b83a69827257cb52b00f0199ed2240a142812b46cf67e92b99942ac59fb9f9efd7dd822f5a36c799f - 00000000000000000000000000000000074b3a16a9cc4be9da0ac8e2e7003d9c1ec89244d2c33441b31af76716cce439f805843a9a44701203231efdca551d5b - bb30985756c3ca075114c92f231575d6befafe4084517f1166a47376867bd108 - 000000000000000000000000000000000e25365988664e8b6ade2e5a40da49c11ff1e084cc0f8dca51f0d0578555d39e3617c8cadb2abc2633b28c5895ab0a9e - 00000000000000000000000000000000169f5fd768152169c403475dee475576fd2cc3788179453b0039ff3cb1b7a5a0fff8f82d03f56e65cad579218486c3b6 - 00000000000000000000000000000000087ccd7f92032febc1f75c7115111ede4acbb2e429cbccf3959524d0b79c449d431ff65485e1aecb442b53fec80ecb40 - 00000000000000000000000000000000135d63f264360003b2eb28f126c6621a40088c6eb15acc4aea89d6068e9d5a47f842aa4b4300f5cda5cc5831edb81596 - fb730105809f64ea522983d6bbb62f7e2e8cbf702685e9be10e2ef71f8187672 - 00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829 - 000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d9 - 00000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c0 - 00000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196 - b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea - 000000000000000000000000000000000f29b0d2b6e3466668e1328048e8dbc782c1111ab8cbe718c85d58ded992d97ca8ba20b9d048feb6ed0aa1b4139d02d3 - 000000000000000000000000000000000d1f0dae940b99fbfc6e4a58480cac8c4e6b2fe33ce6f39c7ac1671046ce94d9e16cba2bb62c6749ef73d45bea21501a - 000000000000000000000000000000001902ccece1c0c763fd06934a76d1f2f056563ae6d8592bafd589cfebd6f057726fd908614ccd6518a21c66ecc2f78b66 - 0000000000000000000000000000000017f6b113f8872c3187d20b0c765d73b850b54244a719cf461fb318796c0b8f310b5490959f9d9187f99c8ed3e25e42a9 - 3b77283d0a7bb9e17a27e66851792fdd605cc0a339028b8985390fd024374c76 - 000000000000000000000000000000000576b8cf1e69efdc277465c344cadf7f8cceffacbeca83821f3ff81717308b97f4ac046f1926e7c2eb42677d7afc257c - 000000000000000000000000000000000cc1524531e96f3c00e4250dd351aedb5a4c3184aff52ec8c13d470068f5967f3674fe173ee239933e67501a9decc668 - 0000000000000000000000000000000001610cfcaea414c241b44cf6f3cc319dcb51d6b8de29c8a6869ff7c1ebb7b747d881e922b42e8fab96bde7cf23e8e4cd - 0000000000000000000000000000000017d4444dc8b6893b681cf10dac8169054f9d2f61d3dd5fd785ae7afa49d18ebbde9ce8dde5641adc6b38173173459836 - dd994eae929aee7428fdda2e44f8cb12b10b91c83b22abc8bbb561310b62257c - 000000000000000000000000000000000ca8f961f86ee6c46fc88fbbf721ba760186f13cd4cce743f19dc60a89fd985cb3feee34dcc4656735a326f515a729e4 - 00000000000000000000000000000000174baf466b809b1155d524050f7ee58c7c5cf728c674e0ce549f5551047a4479ca15bdf69b403b03fa74eb1b26bbff6c - 0000000000000000000000000000000000e8c8b587c171b1b292779abfef57202ed29e7fe94ade9634ec5a2b3b4692a4f3c15468e3f6418b144674be70780d5b - 000000000000000000000000000000001865e99cf97d88bdf56dae32314eb32295c39a1e755cd7d1478bea8520b9ff21c39b683b92ae15568420c390c42b123b - 7010b134989c8368c7f831f9dd9f9a890e2c1435681107414f2e8637153bbf6a - 0000000000000000000000000000000017eccd446f10018219a1bd111b8786cf9febd49f9e7e754e82dd155ead59b819f0f20e42f4635d5044ec5d550d847623 - 000000000000000000000000000000000403969d2b8f914ff2ea3bf902782642e2c6157bd2a343acf60ff9125b48b558d990a74c6d4d6398e7a3cc2a16037346 - 000000000000000000000000000000000bd45f61f142bd78619fb520715320eb5e6ebafa8b078ce796ba62fe1a549d5fb9df57e92d8d2795988eb6ae18cf9d93 - 00000000000000000000000000000000097db1314e064b8e670ec286958f17065bce644cf240ab1b1b220504560d36a0b43fc18453ff3a2bb315e219965f5bd3 - 94c68bc8d91ac8c489ee87dbfc4b94c93c8bbd5fc04c27db8b02303f3a659054 - 00000000000000000000000000000000018244ab39a716e252cbfb986c7958b371e29ea9190010d1f5e1cfdb6ce4822d4055c37cd411fc9a0c46d728f2c13ecf - 0000000000000000000000000000000001985d3c667c8d68c9adb92bdc7a8af959c17146544997d97116120a0f55366bd7ad7ffa28d93ee51222ff9222779675 - 000000000000000000000000000000000c70fd4e3c8f2a451f83fb6c046431b38251b7bae44cf8d36df69a03e2d3ce6137498523fcf0bcf29b5d69e8f265e24d - 00000000000000000000000000000000047b9163a218f7654a72e0d7c651a2cf7fd95e9784a59e0bf119d081de6c0465d374a55fbc1eff9828c9fd29abf4c4bd - b3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746 - "); - let expected = hex!(" - 00000000000000000000000000000000083ad744b34f6393bc983222b004657494232c5d9fbc978d76e2377a28a34c4528da5d91cbc0977dc953397a6d21eca2 - 0000000000000000000000000000000015aec6526e151cf5b8403353517dfb9a162087a698b71f32b266d3c5c936a83975d5567c25b3a5994042ec1379c8e526 - 000000000000000000000000000000000e3647185d1a20efad19f975729908840dc33909a583600f7915025f906aef9c022fd34e618170b11178aaa824ae36b3 - 00000000000000000000000000000000159576d1d53f6cd12c39d651697e11798321f17cd287118d7ebeabf68281bc03109ee103ee8ef2ef93c71dd1dcbaf1e0 - "); - - let mut output = [0u8; 256]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_pairing() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], - native: EthereumBuiltin::from_str("bls12_381_pairing").unwrap(), - }; - - let input = hex!(" - 000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80 - 000000000000000000000000000000000874389c02d4cf1c61bc54c4c24def11dfbe7880bc998a95e70063009451ee8226fec4b278aade3a7cea55659459f1d5 - 00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e - 000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834 - 000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e - 0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e - 000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80 - 00000000000000000000000000000000118cd94e36ab177de95f52f180fdbdc584b8d30436eb882980306fa0625f07a1f7ad3b4c38a921c53d14aa9a6ba5b8d6 - 00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e - 000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834 - 000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e - 0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e - "); - let expected = hex!( - " - 0000000000000000000000000000000000000000000000000000000000000001 - " - ); - - let mut output = [0u8; 32]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_fp_to_g1() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], - native: EthereumBuiltin::from_str("bls12_381_fp_to_g1").unwrap(), - }; - - let input = hex!(" - 0000000000000000000000000000000017f66b472b36717ee0902d685c808bb5f190bbcb2c51d067f1cbec64669f10199a5868d7181dcec0498fcc71f5acaf79 - "); - let expected = hex!(" - 00000000000000000000000000000000188dc9e5ddf48977f33aeb6e505518269bf67fb624fa86b79741d842e75a6fa1be0911c2caa9e55571b6e55a3c0c0b9e - 00000000000000000000000000000000193e8b7c7e78daf104a59d7b39401a65355fa874bd34e91688580941e99a863367efc68fe871e38e07423090e93919c9 - "); - - let mut output = [0u8; 128]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_fp2_to_g2() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], - native: EthereumBuiltin::from_str("bls12_381_fp2_to_g2").unwrap(), - }; - - let input = hex!(" - 000000000000000000000000000000000f470603a402bc134db1b389fd187460f9eb2dd001a2e99f730af386508c62f0e911d831a2562da84bce11d39f2ff13f - 000000000000000000000000000000000d8c45f4ab20642d0cba9764126e0818b7d731a6ba29ed234d9d6309a5e8ddfbd85193f1fa8b7cfeed3d31b23b904ee9 - "); - let expected = hex!(" - 0000000000000000000000000000000012e74d5a0c005a86ca148e9eff8e34a00bfa8b6e6aadf633d65cd09bb29917e0ceb0d5c9d9650c162d7fe4aa27452685 - 0000000000000000000000000000000005f09101a2088712619f9c096403b66855a12f9016c55aef6047372fba933f02d9d59db1a86df7be57978021e2457821 - 00000000000000000000000000000000136975b37fe400d1d217a2b496c1552b39be4e9e71dd7ad482f5f0836d271d02959fdb698dda3d0530587fb86e0db1dd - 0000000000000000000000000000000000bad0aabd9309e92e2dd752f4dd73be07c0de2c5ddd57916b9ffa065d7440d03d44e7c042075cda694414a9fb639bb7 - "); - - let mut output = [0u8; 256]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g1_multiexp_init_from_spec() { - use ethjson::spec::builtin::{Bls12G1Multiexp, Pricing}; - - let b = Builtin::try_from(JsonBuiltin { - name: "bls12_381_g1_multiexp".to_owned(), - pricing: btreemap![ - 10000000 => PricingAt { - info: None, - price: Pricing::Bls12G1Multiexp(Bls12G1Multiexp{ - base: 12000, - }), - } - ], - }) - .unwrap(); - - match b.native { - EthereumBuiltin::Bls12G1MultiExp(..) => {} - _ => { - panic!("invalid precompile type"); - } - } - } - - #[test] - fn bls12_381_g2_multiexp_init_from_spec() { - use ethjson::spec::builtin::{Bls12G2Multiexp, Pricing}; - - let b = Builtin::try_from(JsonBuiltin { - name: "bls12_381_g2_multiexp".to_owned(), - pricing: btreemap![ - 10000000 => PricingAt { - info: None, - price: Pricing::Bls12G2Multiexp(Bls12G2Multiexp{ - base: 55000, - }), - } - ], - }) - .unwrap(); - - match b.native { - EthereumBuiltin::Bls12G2MultiExp(..) => {} - _ => { - panic!("invalid precompile type"); - } - } - } + /* TODO: refactor it + #[test] + fn bls12_381_g1_add() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + native: EthereumBuiltin::from_str("bls12_381_g1_add").unwrap(), + }; + + let input = hex!(" + 00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb + 0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed2 + 000000000000000000000000000000000441e7f7f96198e4c23bd5eb16f1a7f045dbc8c53219ab2bcea91d3a027e2dfe659feac64905f8b9add7e4bfc91bec2b + 0000000000000000000000000000000005fc51bb1b40c87cd4292d4b66f8ca5ce4ef9abd2b69d4464b4879064203bda7c9fc3f896a3844ebc713f7bb20951d95 + "); + let expected = hex!(" + 0000000000000000000000000000000016b8ab56b45a9294466809b8e858c1ad15ad0d52cfcb62f8f5753dc94cee1de6efaaebce10701e3ec2ecaa9551024ea + 600000000000000000000000000000000124571eec37c0b1361023188d66ec17c1ec230d31b515e0e81e599ec19e40c8a7c8cdea9735bc3d8b4e37ca7e5dd71f6 + "); + + let mut output = [0u8; 128]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_g1_mul() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), + }; + + let input = hex!(" + 000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e + 000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa3 + ac23d04ee3acc757aae6795532ce4c9f34534e506a4d843a26b052a040c79659 + "); + let expected = hex!(" + 000000000000000000000000000000001227b7021e9d3dc8bcbf5b346fc503f7f8576965769c5e22bb70056eef03c84b8c80290ae9ce20345770290c55549bce + 00000000000000000000000000000000188ddbbfb4ad2d34a8d3dc0ec92b70b63caa73ad7dea0cc9740bac2309b4bb11107912bd086379746e9a9bcd26d4db58 + "); + + let mut output = [0u8; 128]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_g1_multiexp() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + native: EthereumBuiltin::from_str("bls12_381_g1_multiexp").unwrap(), + }; + let input = hex!(" + 0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f56 + 0000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee + b3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e + 00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb + 0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed2 + 4d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d + 0000000000000000000000000000000008ab7b556c672db7883ec47efa6d98bb08cec7902ebb421aac1c31506b177ac444ffa2d9b400a6f1cbdc6240c607ee11 + 0000000000000000000000000000000016b7fa9adf4addc2192271ce7ad3c8d8f902d061c43b7d2e8e26922009b777855bffabe7ed1a09155819eabfa87f276f + 973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1 + 0000000000000000000000000000000015ff9a232d9b5a8020a85d5fe08a1dcfb73ece434258fe0e2fddf10ddef0906c42dcb5f5d62fc97f934ba900f17beb33 + 0000000000000000000000000000000009cfe4ee2241d9413c616462d7bac035a6766aeaab69c81e094d75b840df45d7e0dfac0265608b93efefb9a8728b98e4 + 4c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a + 0000000000000000000000000000000017a17b82e3bfadf3250210d8ef572c02c3610d65ab4d7366e0b748768a28ee6a1b51f77ed686a64f087f36f641e7dca9 + 00000000000000000000000000000000077ea73d233ccea51dc4d5acecf6d9332bf17ae51598f4b394a5f62fb387e9c9aa1d6823b64a074f5873422ca57545d3 + 8964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b89 + 000000000000000000000000000000000c1243478f4fbdc21ea9b241655947a28accd058d0cdb4f9f0576d32f09dddaf0850464550ff07cab5927b3e4c863ce9 + 0000000000000000000000000000000015fb54db10ffac0b6cd374eb7168a8cb3df0a7d5f872d8e98c1f623deb66df5dd08ff4c3658f2905ec8bd02598bd4f90 + 787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c944 + 000000000000000000000000000000000328f09584b6d6c98a709fc22e184123994613aca95a28ac53df8523b92273eb6f4e2d9b2a7dcebb474604d54a210719 + 000000000000000000000000000000001220ebde579911fe2e707446aaad8d3789fae96ae2e23670a4fd856ed82daaab704779eb4224027c1ed9460f39951a1b + aaee7ae2a237e8e53560c79e7baa9adf9c00a0ea4d6f514e7a6832eb15cef1e1 + 0000000000000000000000000000000002ebfa98aa92c32a29ebe17fcb1819ba82e686abd9371fcee8ea793b4c72b6464085044f818f1f5902396df0122830cb + 00000000000000000000000000000000001184715b8432ed190b459113977289a890f68f6085ea111466af15103c9c02467da33e01d6bff87fd57db6ccba442a + dac6ed3ef45c1d7d3028f0f89e5458797996d3294b95bebe049b76c7d0db317c + 0000000000000000000000000000000009d6424e002439998e91cd509f85751ad25e574830c564e7568347d19e3f38add0cab067c0b4b0801785a78bcbeaf246 + 000000000000000000000000000000000ef6d7db03ee654503b46ff0dbc3297536a422e963bda9871a8da8f4eeb98dedebd6071c4880b4636198f4c2375dc795 + bb30985756c3ca075114c92f231575d6befafe4084517f1166a47376867bd108 + 0000000000000000000000000000000002d1cdb93191d1f9f0308c2c55d0208a071f5520faca7c52ab0311dbc9ba563bd33b5dd6baa77bf45ac2c3269e945f48 + 00000000000000000000000000000000072a52106e6d7b92c594c4dacd20ef5fab7141e45c231457cd7e71463b2254ee6e72689e516fa6a8f29f2a173ce0a190 + fb730105809f64ea522983d6bbb62f7e2e8cbf702685e9be10e2ef71f8187672 + 0000000000000000000000000000000000641642f6801d39a09a536f506056f72a619c50d043673d6d39aa4af11d8e3ded38b9c3bbc970dbc1bd55d68f94b50d + 0000000000000000000000000000000009ab050de356a24aea90007c6b319614ba2f2ed67223b972767117769e3c8e31ee4056494628fb2892d3d37afb6ac943 + b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea + 000000000000000000000000000000000fd4893addbd58fb1bf30b8e62bef068da386edbab9541d198e8719b2de5beb9223d87387af82e8b55bd521ff3e47e2d + 000000000000000000000000000000000f3a923b76473d5b5a53501790cb02597bb778bdacb3805a9002b152d22241ad131d0f0d6a260739cbab2c2fe602870e + 3b77283d0a7bb9e17a27e66851792fdd605cc0a339028b8985390fd024374c76 + 0000000000000000000000000000000002cb4b24c8aa799fd7cb1e4ab1aab1372113200343d8526ea7bc64dfaf926baf5d90756a40e35617854a2079cd07fba4 + 0000000000000000000000000000000003327ca22bd64ebd673cc6d5b02b2a8804d5353c9d251637c4273ad08d581cc0d58da9bea27c37a0b3f4961dbafd276b + dd994eae929aee7428fdda2e44f8cb12b10b91c83b22abc8bbb561310b62257c + 00000000000000000000000000000000024ad70f2b2105ca37112858e84c6f5e3ffd4a8b064522faae1ecba38fabd52a6274cb46b00075deb87472f11f2e67d9 + 0000000000000000000000000000000010a502c8b2a68aa30d2cb719273550b9a3c283c35b2e18a01b0b765344ffaaa5cb30a1e3e6ecd3a53ab67658a5787681 + 7010b134989c8368c7f831f9dd9f9a890e2c1435681107414f2e8637153bbf6a + 0000000000000000000000000000000000704cc57c8e0944326ddc7c747d9e7347a7f6918977132eea269f161461eb64066f773352f293a3ac458dc3ccd5026a + 000000000000000000000000000000001099d3c2bb2d082f2fdcbed013f7ac69e8624f4fcf6dfab3ee9dcf7fbbdb8c49ee79de40e887c0b6828d2496e3a6f768 + 94c68bc8d91ac8c489ee87dbfc4b94c93c8bbd5fc04c27db8b02303f3a659054 + 00000000000000000000000000000000130535a29392c77f045ac90e47f2e7b3cffff94494fe605aad345b41043f6663ada8e2e7ecd3d06f3b8854ef92212f42 + 000000000000000000000000000000001699a3cc1f10cd2ed0dc68eb916b4402e4f12bf4746893bf70e26e209e605ea89e3d53e7ac52bd07713d3c8fc671931d + b3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746 + "); + let expected = hex!(" + 000000000000000000000000000000000b370fc4ca67fb0c3c270b1b4c4816ef953cd9f7cf6ad20e88099c40aace9c4bb3f4cd215e5796f65080c69c9f4d2a0f + 0000000000000000000000000000000007203220935ddc0190e2d7a99ec3f9231da550768373f9a5933dffd366f48146f8ea5fe5dee6539d925288083bb5a8f1 + "); + + let mut output = [0u8; 128]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_g2_add() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + native: EthereumBuiltin::from_str("bls12_381_g2_add").unwrap(), + }; + let input = hex!(" + 00000000000000000000000000000000161c595d151a765c7dee03c9210414cdffab84b9078b4b98f9df09be5ec299b8f6322c692214f00ede97958f235c352b + 00000000000000000000000000000000106883e0937cb869e579b513bde8f61020fcf26be38f8b98eae3885cedec2e028970415fc653cf10e64727b7f6232e06 + 000000000000000000000000000000000f351a82b733af31af453904874b7ca6252957a1ab51ec7f7b6fff85bbf3331f870a7e72a81594a9930859237e7a154d + 0000000000000000000000000000000012fcf20d1750901f2cfed64fd362f010ee64fafe9ddab406cc352b65829b929881a50514d53247d1cca7d6995d0bc9b2 + 00000000000000000000000000000000148b7dfc21521d79ff817c7a0305f1048851e283be13c07d5c04d28b571d48172838399ba539529e8d037ffd1f729558 + 0000000000000000000000000000000003015abea326c15098f5205a8b2d3cd74d72dac59d60671ca6ef8c9c714ea61ffdacd46d1024b5b4f7e6b3b569fabaf2 + 0000000000000000000000000000000011f0c512fe7dc2dd8abdc1d22c2ecd2e7d1b84f8950ab90fc93bf54badf7bb9a9bad8c355d52a5efb110dca891e4cc3d + 0000000000000000000000000000000019774010814d1d94caf3ecda3ef4f5c5986e966eaf187c32a8a5a4a59452af0849690cf71338193f2d8435819160bcfb + "); + let expected = hex!(" + 000000000000000000000000000000000383ab7a17cc57e239e874af3f1aaabba0e64625b848676712f05f56132dbbd1cadfabeb3fe1f461daba3f1720057ddd + 00000000000000000000000000000000096967e9b3747f1b8e344535eaa0c51e70bc77412bfaa2a7ce76f11f570c9febb8f4227316866a416a50436d098e6f9a + 000000000000000000000000000000001079452b7519a7b090d668d54c266335b1cdd1080ed867dd17a2476b11c2617da829bf740e51cb7dfd60d73ed02c0c67 + 00000000000000000000000000000000015fc3a972e05cbd9014882cfe6f2f16d0291c403bf28b05056ac625e4f71dfb1295c85d73145ef554614e6eb2d5bf02 + "); + + let mut output = [0u8; 256]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_g2_mul() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + native: EthereumBuiltin::from_str("bls12_381_g2_mul").unwrap(), + }; + + let input = hex!(" + 00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829 + 000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d9 + 00000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c0 + 00000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196 + b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea + "); + let expected = hex!(" + 000000000000000000000000000000000b24adeb2ca184c9646cb39f45e0cf8711e10bf308ddae06519562b0af3b43be44c2fcb90622726f7446ed690551d30e + 00000000000000000000000000000000069467c3edc19416067f572c51740ba8e0e7380121ade98e38ce26d907a2bf3a4e82af2bd195b6c3b7c9b29218880531 + 000000000000000000000000000000000eb8c90d0727511be53ffcb6f3b144c07983ed4b76d31ab003e45b37c7bc1066910f5e29f5adad5757af979dd0d8351d + 0000000000000000000000000000000004760f8d814189dcd893949797a3c4f56f2b60964bba3a4fc741e7ead05eb886787b2502fc64b20363eeba44e65d0ca0 + "); + + let mut output = [0u8; 256]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_g2_multiexp() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + native: EthereumBuiltin::from_str("bls12_381_g2_multiexp").unwrap(), + }; + + let input = hex!(" + 00000000000000000000000000000000039b10ccd664da6f273ea134bb55ee48f09ba585a7e2bb95b5aec610631ac49810d5d616f67ba0147e6d1be476ea220e + 0000000000000000000000000000000000fbcdff4e48e07d1f73ec42fe7eb026f5c30407cfd2f22bbbfe5b2a09e8a7bb4884178cb6afd1c95f80e646929d3004 + 0000000000000000000000000000000001ed3b0e71acb0adbf44643374edbf4405af87cfc0507db7e8978889c6c3afbe9754d1182e98ac3060d64994d31ef576 + 000000000000000000000000000000001681a2bf65b83be5a2ca50430949b6e2a099977482e9405b593f34d2ed877a3f0d1bddc37d0cec4d59d7df74b2b8f2df + b3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e + 0000000000000000000000000000000018c0ada6351b70661f053365deae56910798bd2ace6e2bf6ba4192d1a229967f6af6ca1c9a8a11ebc0a232344ee0f6d6 + 000000000000000000000000000000000cc70a587f4652039d8117b6103858adcd9728f6aebe230578389a62da0042b7623b1c0436734f463cfdd187d2090324 + 0000000000000000000000000000000009f50bd7beedb23328818f9ffdafdb6da6a4dd80c5a9048ab8b154df3cad938ccede829f1156f769d9e149791e8e0cd9 + 00000000000000000000000000000000079ba50d2511631b20b6d6f3841e616e9d11b68ec3368cd60129d9d4787ab56c4e9145a38927e51c9cd6271d493d9388 + 4d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d + 0000000000000000000000000000000003632695b09dbf86163909d2bb25995b36ad1d137cf252860fd4bb6c95749e19eb0c1383e9d2f93f2791cb0cf6c8ed9d + 000000000000000000000000000000001688a855609b0bbff4452d146396558ff18777f329fd4f76a96859dabfc6a6f6977c2496280dbe3b1f8923990c1d6407 + 000000000000000000000000000000000c8567fee05d05af279adc67179468a29d7520b067dbb348ee315a99504f70a206538b81a457cce855f4851ad48b7e80 + 000000000000000000000000000000001238dcdfa80ea46e1500026ea5feadb421de4409f4992ffbf5ae59fa67fd82f38452642a50261b849e74b4a33eed70cc + 973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1 + 000000000000000000000000000000000149704960cccf9d5ea414c73871e896b1d4cf0a946b0db72f5f2c5df98d2ec4f3adbbc14c78047961bc9620cb6cfb59 + 00000000000000000000000000000000140c5d25e534fb1bfdc19ba4cecaabe619f6e0cd3d60b0f17dafd7bcd27b286d4f4477d00c5e1af22ee1a0c67fbf177c + 00000000000000000000000000000000029a1727041590b8459890de736df15c00d80ab007c3aee692ddcdf75790c9806d198e9f4502bec2f0a623491c3f877d + 0000000000000000000000000000000008a94c98baa9409151030d4fae2bd4a64c6f11ea3c99b9661fdaed226b9a7c2a7d609be34afda5d18b8911b6e015bf49 + 4c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a + 000000000000000000000000000000001156d478661337478ab0cbc877a99d9e4d9824a2b3f605d41404d6b557b3ffabbf42635b0bbcb854cf9ed8b8637561a8 + 000000000000000000000000000000001147ed317d5642e699787a7b47e6795c9a8943a34a694007e44f8654ba96390cf19f010dcf695e22c21874022c6ce291 + 000000000000000000000000000000000c6dccdf920fd5e7fae284115511952633744c6ad94120d9cae6acda8a7c23c48bd912cba6c38de5159587e1e6cad519 + 000000000000000000000000000000001944227d462bc2e5dcc6f6db0f83dad411ba8895262836f975b2b91e06fd0e2138862162acc04e9e65050b34ccbd1a4e + 8964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b89 + 0000000000000000000000000000000019c31e3ab8cc9c920aa8f56371f133b6cb8d7b0b74b23c0c7201aca79e5ae69dc01f1f74d2492dcb081895b17d106b4e + 000000000000000000000000000000001789b0d371bd63077ccde3dbbebf3531368feb775bced187fb31cc6821481664600978e323ff21085b8c08e0f21daf72 + 000000000000000000000000000000000009eacfe8f4a2a9bae6573424d07f42bd6af8a9d55f71476a7e3c7a4b2b898550c1e72ec13afd4eff22421a03af1d31 + 000000000000000000000000000000000410bd4ea74dcfa33f2976aa1b571c67cbb596ab10f76a8aaf4548f1097e55b3373bff02683f806cb84e1e0e877819e2 + 787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c944 + 00000000000000000000000000000000147f09986691f2e57073378e8bfd58804241eed7934f6adfe6d0a6bac4da0b738495778a303e52113e1c80e698476d50 + 000000000000000000000000000000000762348b84c92a8ca6de319cf1f8f11db296a71b90fe13e1e4bcd25903829c00a5d2ad4b1c8d98c37eaad7e042ab023d + 0000000000000000000000000000000011d1d94530d4a2daf0e902a5c3382cd135938557f94b04bccea5e16ea089c5e020e13524c854a316662bd68784fe31f3 + 00000000000000000000000000000000070828522bec75b6a492fd9bca7b54dac6fbbf4f0bc3179d312bb65c647439e3868e4d5b21af5a64c93aeee8a9b7e46e + aaee7ae2a237e8e53560c79e7baa9adf9c00a0ea4d6f514e7a6832eb15cef1e1 + 000000000000000000000000000000000690a0869204c8dced5ba0ce13554b2703a3f18afb8fa8fa1c457d79c58fdc25471ae85bafad52e506fc1917fc3becff + 0000000000000000000000000000000010f7dbb16f8571ede1cec79e3f9ea03ae6468d7285984713f19607f5cab902b9a6b7cbcfd900be5c2e407cc093ea0e67 + 00000000000000000000000000000000151caf87968433cb1f85fc1854c57049be22c26497a86bfbd66a2b3af121d894dba8004a17c6ff96a5843c2719fa32d1 + 0000000000000000000000000000000011f0270f2b039409f70392879bcc2c67c836c100cf9883d3dc48d7adbcd52037d270539e863a951acd47ecaa1ca4db12 + dac6ed3ef45c1d7d3028f0f89e5458797996d3294b95bebe049b76c7d0db317c + 0000000000000000000000000000000017fae043c8fd4c520a90d4a6bd95f5b0484acc279b899e7b1d8f7f7831cc6ba37cd5965c4dc674768f5805842d433af3 + 0000000000000000000000000000000008ddd7b41b8fa4d29fb931830f29b46f4015ec202d51cb969d7c832aafc0995c875cd45eff4a083e2d5ecb5ad185b64f + 0000000000000000000000000000000015d384ab7e52420b83a69827257cb52b00f0199ed2240a142812b46cf67e92b99942ac59fb9f9efd7dd822f5a36c799f + 00000000000000000000000000000000074b3a16a9cc4be9da0ac8e2e7003d9c1ec89244d2c33441b31af76716cce439f805843a9a44701203231efdca551d5b + bb30985756c3ca075114c92f231575d6befafe4084517f1166a47376867bd108 + 000000000000000000000000000000000e25365988664e8b6ade2e5a40da49c11ff1e084cc0f8dca51f0d0578555d39e3617c8cadb2abc2633b28c5895ab0a9e + 00000000000000000000000000000000169f5fd768152169c403475dee475576fd2cc3788179453b0039ff3cb1b7a5a0fff8f82d03f56e65cad579218486c3b6 + 00000000000000000000000000000000087ccd7f92032febc1f75c7115111ede4acbb2e429cbccf3959524d0b79c449d431ff65485e1aecb442b53fec80ecb40 + 00000000000000000000000000000000135d63f264360003b2eb28f126c6621a40088c6eb15acc4aea89d6068e9d5a47f842aa4b4300f5cda5cc5831edb81596 + fb730105809f64ea522983d6bbb62f7e2e8cbf702685e9be10e2ef71f8187672 + 00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829 + 000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d9 + 00000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c0 + 00000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196 + b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea + 000000000000000000000000000000000f29b0d2b6e3466668e1328048e8dbc782c1111ab8cbe718c85d58ded992d97ca8ba20b9d048feb6ed0aa1b4139d02d3 + 000000000000000000000000000000000d1f0dae940b99fbfc6e4a58480cac8c4e6b2fe33ce6f39c7ac1671046ce94d9e16cba2bb62c6749ef73d45bea21501a + 000000000000000000000000000000001902ccece1c0c763fd06934a76d1f2f056563ae6d8592bafd589cfebd6f057726fd908614ccd6518a21c66ecc2f78b66 + 0000000000000000000000000000000017f6b113f8872c3187d20b0c765d73b850b54244a719cf461fb318796c0b8f310b5490959f9d9187f99c8ed3e25e42a9 + 3b77283d0a7bb9e17a27e66851792fdd605cc0a339028b8985390fd024374c76 + 000000000000000000000000000000000576b8cf1e69efdc277465c344cadf7f8cceffacbeca83821f3ff81717308b97f4ac046f1926e7c2eb42677d7afc257c + 000000000000000000000000000000000cc1524531e96f3c00e4250dd351aedb5a4c3184aff52ec8c13d470068f5967f3674fe173ee239933e67501a9decc668 + 0000000000000000000000000000000001610cfcaea414c241b44cf6f3cc319dcb51d6b8de29c8a6869ff7c1ebb7b747d881e922b42e8fab96bde7cf23e8e4cd + 0000000000000000000000000000000017d4444dc8b6893b681cf10dac8169054f9d2f61d3dd5fd785ae7afa49d18ebbde9ce8dde5641adc6b38173173459836 + dd994eae929aee7428fdda2e44f8cb12b10b91c83b22abc8bbb561310b62257c + 000000000000000000000000000000000ca8f961f86ee6c46fc88fbbf721ba760186f13cd4cce743f19dc60a89fd985cb3feee34dcc4656735a326f515a729e4 + 00000000000000000000000000000000174baf466b809b1155d524050f7ee58c7c5cf728c674e0ce549f5551047a4479ca15bdf69b403b03fa74eb1b26bbff6c + 0000000000000000000000000000000000e8c8b587c171b1b292779abfef57202ed29e7fe94ade9634ec5a2b3b4692a4f3c15468e3f6418b144674be70780d5b + 000000000000000000000000000000001865e99cf97d88bdf56dae32314eb32295c39a1e755cd7d1478bea8520b9ff21c39b683b92ae15568420c390c42b123b + 7010b134989c8368c7f831f9dd9f9a890e2c1435681107414f2e8637153bbf6a + 0000000000000000000000000000000017eccd446f10018219a1bd111b8786cf9febd49f9e7e754e82dd155ead59b819f0f20e42f4635d5044ec5d550d847623 + 000000000000000000000000000000000403969d2b8f914ff2ea3bf902782642e2c6157bd2a343acf60ff9125b48b558d990a74c6d4d6398e7a3cc2a16037346 + 000000000000000000000000000000000bd45f61f142bd78619fb520715320eb5e6ebafa8b078ce796ba62fe1a549d5fb9df57e92d8d2795988eb6ae18cf9d93 + 00000000000000000000000000000000097db1314e064b8e670ec286958f17065bce644cf240ab1b1b220504560d36a0b43fc18453ff3a2bb315e219965f5bd3 + 94c68bc8d91ac8c489ee87dbfc4b94c93c8bbd5fc04c27db8b02303f3a659054 + 00000000000000000000000000000000018244ab39a716e252cbfb986c7958b371e29ea9190010d1f5e1cfdb6ce4822d4055c37cd411fc9a0c46d728f2c13ecf + 0000000000000000000000000000000001985d3c667c8d68c9adb92bdc7a8af959c17146544997d97116120a0f55366bd7ad7ffa28d93ee51222ff9222779675 + 000000000000000000000000000000000c70fd4e3c8f2a451f83fb6c046431b38251b7bae44cf8d36df69a03e2d3ce6137498523fcf0bcf29b5d69e8f265e24d + 00000000000000000000000000000000047b9163a218f7654a72e0d7c651a2cf7fd95e9784a59e0bf119d081de6c0465d374a55fbc1eff9828c9fd29abf4c4bd + b3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746 + "); + let expected = hex!(" + 00000000000000000000000000000000083ad744b34f6393bc983222b004657494232c5d9fbc978d76e2377a28a34c4528da5d91cbc0977dc953397a6d21eca2 + 0000000000000000000000000000000015aec6526e151cf5b8403353517dfb9a162087a698b71f32b266d3c5c936a83975d5567c25b3a5994042ec1379c8e526 + 000000000000000000000000000000000e3647185d1a20efad19f975729908840dc33909a583600f7915025f906aef9c022fd34e618170b11178aaa824ae36b3 + 00000000000000000000000000000000159576d1d53f6cd12c39d651697e11798321f17cd287118d7ebeabf68281bc03109ee103ee8ef2ef93c71dd1dcbaf1e0 + "); + + let mut output = [0u8; 256]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_pairing() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], + native: EthereumBuiltin::from_str("bls12_381_pairing").unwrap(), + }; + + let input = hex!(" + 000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80 + 000000000000000000000000000000000874389c02d4cf1c61bc54c4c24def11dfbe7880bc998a95e70063009451ee8226fec4b278aade3a7cea55659459f1d5 + 00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e + 000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834 + 000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e + 0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e + 000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80 + 00000000000000000000000000000000118cd94e36ab177de95f52f180fdbdc584b8d30436eb882980306fa0625f07a1f7ad3b4c38a921c53d14aa9a6ba5b8d6 + 00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e + 000000000000000000000000000000000af1a3f6396f0c983e7c2d42d489a3ae5a3ff0a553d93154f73ac770cd0af7467aa0cef79f10bbd34621b3ec9583a834 + 000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e + 0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e + "); + let expected = hex!( + " + 0000000000000000000000000000000000000000000000000000000000000001 + " + ); + + let mut output = [0u8; 32]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_fp_to_g1() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], + native: EthereumBuiltin::from_str("bls12_381_fp_to_g1").unwrap(), + }; + + let input = hex!(" + 0000000000000000000000000000000017f66b472b36717ee0902d685c808bb5f190bbcb2c51d067f1cbec64669f10199a5868d7181dcec0498fcc71f5acaf79 + "); + let expected = hex!(" + 00000000000000000000000000000000188dc9e5ddf48977f33aeb6e505518269bf67fb624fa86b79741d842e75a6fa1be0911c2caa9e55571b6e55a3c0c0b9e + 00000000000000000000000000000000193e8b7c7e78daf104a59d7b39401a65355fa874bd34e91688580941e99a863367efc68fe871e38e07423090e93919c9 + "); + + let mut output = [0u8; 128]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_fp2_to_g2() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], + native: EthereumBuiltin::from_str("bls12_381_fp2_to_g2").unwrap(), + }; + + let input = hex!(" + 000000000000000000000000000000000f470603a402bc134db1b389fd187460f9eb2dd001a2e99f730af386508c62f0e911d831a2562da84bce11d39f2ff13f + 000000000000000000000000000000000d8c45f4ab20642d0cba9764126e0818b7d731a6ba29ed234d9d6309a5e8ddfbd85193f1fa8b7cfeed3d31b23b904ee9 + "); + let expected = hex!(" + 0000000000000000000000000000000012e74d5a0c005a86ca148e9eff8e34a00bfa8b6e6aadf633d65cd09bb29917e0ceb0d5c9d9650c162d7fe4aa27452685 + 0000000000000000000000000000000005f09101a2088712619f9c096403b66855a12f9016c55aef6047372fba933f02d9d59db1a86df7be57978021e2457821 + 00000000000000000000000000000000136975b37fe400d1d217a2b496c1552b39be4e9e71dd7ad482f5f0836d271d02959fdb698dda3d0530587fb86e0db1dd + 0000000000000000000000000000000000bad0aabd9309e92e2dd752f4dd73be07c0de2c5ddd57916b9ffa065d7440d03d44e7c042075cda694414a9fb639bb7 + "); + + let mut output = [0u8; 256]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } + + #[test] + fn bls12_381_g1_multiexp_init_from_spec() { + use ethjson::spec::builtin::{Bls12G1Multiexp, Pricing}; + + let b = Builtin::try_from(JsonBuiltin { + name: "bls12_381_g1_multiexp".to_owned(), + pricing: btreemap![ + 10000000 => PricingAt { + info: None, + price: Pricing::Bls12G1Multiexp(Bls12G1Multiexp{ + base: 12000, + }), + } + ], + }) + .unwrap(); + + match b.native { + EthereumBuiltin::Bls12G1MultiExp(..) => {} + _ => { + panic!("invalid precompile type"); + } + } + } + + #[test] + fn bls12_381_g2_multiexp_init_from_spec() { + use ethjson::spec::builtin::{Bls12G2Multiexp, Pricing}; + + let b = Builtin::try_from(JsonBuiltin { + name: "bls12_381_g2_multiexp".to_owned(), + pricing: btreemap![ + 10000000 => PricingAt { + info: None, + price: Pricing::Bls12G2Multiexp(Bls12G2Multiexp{ + base: 55000, + }), + } + ], + }) + .unwrap(); + + match b.native { + EthereumBuiltin::Bls12G2MultiExp(..) => {} + _ => { + panic!("invalid precompile type"); + } + } + } + + */ } From b7513acfcb53f237d05a37deb34aadfed23396a1 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Thu, 23 Jan 2025 19:48:04 +0100 Subject: [PATCH 07/14] Added BLS G1-ADD execution --- evm-tests/ethcore-builtin/src/bls.rs | 70 ++++++++++++++++------------ evm-tests/ethcore-builtin/src/lib.rs | 41 ++++++++++++---- 2 files changed, 72 insertions(+), 39 deletions(-) diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index 6ff4121a..64e21352 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -4,7 +4,6 @@ use blst::{ blst_bendian_from_fp, blst_fp, blst_fp_from_bendian, blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, }; -use std::borrow::Cow; use std::cmp::Ordering; use std::convert::TryInto; @@ -52,9 +51,9 @@ fn is_valid_be(input: &[u8; 48]) -> bool { /// Checks whether or not the input represents a canonical field element, returning the field /// element if successful. -fn fp_from_bendian(input: &[u8; 48]) -> Result> { +fn fp_from_bendian(input: &[u8; 48]) -> Result { if !is_valid_be(input) { - return Err(Cow::from("non-canonical fp value")); + return Err("non-canonical fp value"); } let mut fp = blst_fp::default(); // SAFETY: input has fixed length, and fp is a blst value. @@ -67,27 +66,30 @@ fn fp_from_bendian(input: &[u8; 48]) -> Result> { } /// Removes zeros with which the precompile inputs are left padded to 64 bytes. -fn remove_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], Cow<'static, str>> { +fn remove_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], &'static str> { if input.len() != PADDED_FP_LENGTH { - return Err(Cow::from(format!( - "Padded input should be {PADDED_FP_LENGTH} bytes, was {}", - input.len() - ))); + return Err(Box::leak( + format!( + "Padded input should be {PADDED_FP_LENGTH} bytes, was {}", + input.len() + ) + .into_boxed_str(), + )); } let (padding, unpadded) = input.split_at(PADDING_LENGTH); if !padding.iter().all(|&x| x == 0) { - return Err(Cow::from(format!( - "{PADDING_LENGTH} top bytes of input are not zero" - ))); + return Err(Box::leak( + format!("{PADDING_LENGTH} top bytes of input are not zero").into_boxed_str(), + )); } Ok(unpadded.try_into().unwrap()) } -mod g1 { +pub mod g1 { use super::*; /// Length of each of the elements in a g1 operation input. - const G1_INPUT_ITEM_LENGTH: usize = 128; + pub const G1_INPUT_ITEM_LENGTH: usize = 128; /// Output length of a g1 operation. const G1_OUTPUT_LENGTH: usize = 128; @@ -112,7 +114,7 @@ mod g1 { pub fn decode_and_check_g1( p0_x: &[u8; 48], p0_y: &[u8; 48], - ) -> Result> { + ) -> Result { let out = blst_p1_affine { x: fp_from_bendian(p0_x)?, y: fp_from_bendian(p0_y)?, @@ -127,12 +129,15 @@ mod g1 { pub fn extract_g1_input( input: &[u8], subgroup_check: bool, - ) -> Result> { + ) -> Result { if input.len() != G1_INPUT_ITEM_LENGTH { - return Err(Cow::from(format!( - "Input should be {G1_INPUT_ITEM_LENGTH} bytes, was {}", - input.len() - ))); + return Err(Box::leak( + format!( + "Input should be {G1_INPUT_ITEM_LENGTH} bytes, was {}", + input.len() + ) + .into_boxed_str(), + )); } let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; @@ -153,7 +158,7 @@ mod g1 { // As endomorphism acceleration requires input on the correct subgroup, implementers MAY // use endomorphism acceleration. if unsafe { !blst_p1_affine_in_g1(&out) } { - return Err(Cow::from("Element not in G1")); + return Err("Element not in G1"); } } else { // From EIP-2537: @@ -169,7 +174,7 @@ mod g1 { // // SAFETY: out is a blst value. if unsafe { !blst_p1_affine_on_curve(&out) } { - return Err(Cow::from("Element not on G1 curve")); + return Err("Element not on G1 curve"); } } @@ -177,7 +182,7 @@ mod g1 { } } -mod g2 { +pub mod g2 { use super::*; use blst::{blst_fp2, blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve}; @@ -212,7 +217,7 @@ mod g2 { x2: &[u8; 48], y1: &[u8; 48], y2: &[u8; 48], - ) -> Result> { + ) -> Result { Ok(blst_p2_affine { x: check_canonical_fp2(x1, x2)?, y: check_canonical_fp2(y1, y2)?, @@ -224,7 +229,7 @@ mod g2 { pub fn check_canonical_fp2( input_1: &[u8; 48], input_2: &[u8; 48], - ) -> Result> { + ) -> Result { let fp_1 = fp_from_bendian(input_1)?; let fp_2 = fp_from_bendian(input_2)?; @@ -239,12 +244,15 @@ mod g2 { pub fn extract_g2_input( input: &[u8], subgroup_check: bool, - ) -> Result> { + ) -> Result { if input.len() != G2_INPUT_ITEM_LENGTH { - return Err(Cow::from(format!( - "Input should be {G2_INPUT_ITEM_LENGTH} bytes, was {}", - input.len() - ))); + return Err(Box::leak( + format!( + "Input should be {G2_INPUT_ITEM_LENGTH} bytes, was {}", + input.len() + ) + .into_boxed_str(), + )); } let mut input_fps = [&[0; FP_LENGTH]; 4]; @@ -269,7 +277,7 @@ mod g2 { // As endomorphism acceleration requires input on the correct subgroup, implementers MAY // use endomorphism acceleration. if unsafe { !blst_p2_affine_in_g2(&out) } { - return Err(Cow::from("Element not in G2")); + return Err("Element not in G2"); } } else { // From EIP-2537: @@ -285,7 +293,7 @@ mod g2 { // // SAFETY: out is a blst value. if unsafe { !blst_p2_affine_on_curve(&out) } { - return Err(Cow::from("Element not on G2 curve")); + return Err("Element not on G2 curve"); } } diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index 8cc55112..dadcfbc7 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -21,14 +21,9 @@ mod bls; mod kzg; -use std::{ - cmp::{max, min}, - collections::BTreeMap, - convert::{TryFrom, TryInto}, - io::{self, Cursor, Read}, - str::FromStr, +use blst::{ + blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, }; - use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; use eip_152::compress; use eth_pairings::public_interface::eip2537::{ @@ -40,6 +35,13 @@ use log::{trace, warn}; use num::{BigUint, One, Zero}; use parity_bytes::BytesRef; use sha2::Digest; +use std::{ + cmp::{max, min}, + collections::BTreeMap, + convert::{TryFrom, TryInto}, + io::{self, Cursor, Read}, + str::FromStr, +}; /// Native implementation of a built-in contract. pub trait Implementation: Send + Sync { @@ -1188,7 +1190,30 @@ impl Implementation for Kzg { } impl Implementation for Bls12G1Add { - fn execute(&self, _input: &[u8], _output: &mut BytesRef) -> Result<(), &'static str> { + fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { + if input.len() != 256 { + return Err("G1ADD input should be 256 bytes"); + } + // NB: There is no subgroup check for the G1 addition precompile. + // + // We set the subgroup checks here to `false` + let a_aff = &bls::g1::extract_g1_input(&input[..bls::g1::G1_INPUT_ITEM_LENGTH], false)?; + let b_aff = &bls::g1::extract_g1_input(&input[bls::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 out = bls::g1::encode_g1_point(&p_aff); + output.write(0, out.as_slice()); Ok(()) } } From 480962931c1190fefbb1715da08fdb74c9421b1d Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Fri, 24 Jan 2025 00:21:39 +0100 Subject: [PATCH 08/14] Adde precompile bls_g1_add to PRAGUE HF and tests to CI --- .github/workflows/rust.yml | 3 ++- evm-tests/jsontests/src/state.rs | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 20bd0b83..906166ca 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -97,7 +97,8 @@ jobs: ethtests/GeneralStateTests/ \ ethtests/LegacyTests/Cancun/GeneralStateTests/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip7702_set_code_tx/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip7623_increase_calldata_cost/ + ethereum-spec-tests/fixtures/state_tests/prague/eip7623_increase_calldata_cost/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1add/ # Temporally disable as EOFv1 not implemented # ethtests/EIPTests/StateTests/ diff --git a/evm-tests/jsontests/src/state.rs b/evm-tests/jsontests/src/state.rs index ec0b8aac..be740319 100644 --- a/evm-tests/jsontests/src/state.rs +++ b/evm-tests/jsontests/src/state.rs @@ -547,20 +547,18 @@ fn cancun_builtins() -> BTreeMap { fn prague_builtins() -> BTreeMap { use ethjson::spec::builtin::{BuiltinCompat, Linear, PricingCompat}; - let mut builtins = berlin_builtins(); + let mut builtins = cancun_builtins(); builtins.insert( Address(H160::from_low_u64_be(0xB)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_g1_add".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), + pricing: PricingCompat::Single(Pricing::Linear(Linear { base: 375, word: 0 })), activate_at: None, }) .try_into() .unwrap(), ); + /* builtins.insert( Address(H160::from_low_u64_be(0xC)).into(), ethjson::spec::Builtin::from(BuiltinCompat { @@ -666,6 +664,8 @@ fn prague_builtins() -> BTreeMap { .unwrap(), ); + */ + builtins } From 1320ecef2ac0bdd1cecef4c2fee3c2f5789c1a00 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 29 Jan 2025 00:25:01 +0100 Subject: [PATCH 09/14] Added BLS preocompiles: g1mul, g2add, g2mul. Refactored gas price for it. Added CI tests --- .github/workflows/rust.yml | 5 +- evm-tests/ethcore-builtin/src/bls.rs | 336 +++++++++++++++++++- evm-tests/ethcore-builtin/src/lib.rs | 432 ++++---------------------- evm-tests/ethjson/src/spec/builtin.rs | 83 +---- evm-tests/jsontests/src/state.rs | 58 ++-- 5 files changed, 439 insertions(+), 475 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 906166ca..c36b2282 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -98,7 +98,10 @@ jobs: ethtests/LegacyTests/Cancun/GeneralStateTests/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip7702_set_code_tx/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip7623_increase_calldata_cost/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1add/ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1add/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1mul/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2add/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2mul/ # Temporally disable as EOFv1 not implemented # ethtests/EIPTests/StateTests/ diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index 64e21352..df74effe 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -2,7 +2,7 @@ use blst::{ blst_bendian_from_fp, blst_fp, blst_fp_from_bendian, blst_p1_affine, blst_p1_affine_in_g1, - blst_p1_affine_on_curve, + blst_p1_affine_on_curve, blst_scalar, blst_scalar_from_bendian, }; use std::cmp::Ordering; use std::convert::TryInto; @@ -25,6 +25,8 @@ const MODULUS_REPR: [u8; 48] = [ 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xab, ]; +/// Amount used to calculate the multi-scalar-multiplication discount. +const MSM_MULTIPLIER: u64 = 1000; /// BLS Encodes a single finite field element into byte slice with padding. fn fp_to_bytes(out: &mut [u8], input: *const blst_fp) { @@ -85,7 +87,50 @@ fn remove_padding(input: &[u8]) -> Result<&[u8; FP_LENGTH], &'static str> { Ok(unpadded.try_into().unwrap()) } -pub mod g1 { +/// Extracts a scalar from a 32 byte slice representation, decoding the input as a big endian +/// unsigned integer. If the input is not exactly 32 bytes long, an error is returned. +/// +/// From [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537): +/// * A scalar for the multiplication operation is encoded as 32 bytes by performing BigEndian +/// encoding of the corresponding (unsigned) integer. +/// +/// We do not check that the scalar is a canonical Fr element, because the EIP specifies: +/// * The corresponding integer is not required to be less than or equal than main subgroup order +/// `q`. +fn extract_scalar_input(input: &[u8]) -> Result { + if input.len() != SCALAR_LENGTH { + return Err(Box::leak( + format!("Input should be {SCALAR_LENGTH} bytes, was {}", input.len()).into_boxed_str(), + )); + } + + let mut out = blst_scalar::default(); + // SAFETY: input length is checked previously, out is a blst value. + unsafe { + // NOTE: we do not use `blst_scalar_fr_check` here because, from EIP-2537: + // + // * The corresponding integer is not required to be less than or equal than main subgroup + // order `q`. + blst_scalar_from_bendian(&mut out, input.as_ptr()) + }; + + Ok(out) +} + +/// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30 +/// MGas/second, see also: +fn msm_required_gas(k: usize, discount_table: &[u16], multiplication_cost: u64) -> u64 { + if k == 0 { + return 0; + } + + let index = core::cmp::min(k - 1, discount_table.len() - 1); + let discount = discount_table[index] as u64; + + (k as u64 * discount * multiplication_cost) / MSM_MULTIPLIER +} + +mod g1 { use super::*; /// Length of each of the elements in a g1 operation input. @@ -182,12 +227,12 @@ pub mod g1 { } } -pub mod g2 { +mod g2 { use super::*; use blst::{blst_fp2, blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve}; /// Length of each of the elements in a g2 operation input. - pub(super) const G2_INPUT_ITEM_LENGTH: usize = 256; + pub const G2_INPUT_ITEM_LENGTH: usize = 256; /// Output length of a g2 operation. const G2_OUTPUT_LENGTH: usize = 256; @@ -300,3 +345,286 @@ pub mod g2 { Ok(out) } } + +pub mod g1_add { + use super::*; + use blst::{blst_p1, blst_p1_add_or_double_affine, blst_p1_from_affine, blst_p1_to_affine}; + + /// 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: + pub fn g1_add(input: &[u8]) -> Result, &'static str> { + if input.len() != INPUT_LENGTH { + return Err(Box::leak( + format!( + "G1ADD input should be {INPUT_LENGTH} bytes got {}", + input.len() + ) + .into_boxed_str(), + )); + } + + // 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)) + } +} + +pub mod g1_mul { + use super::*; + use blst::{blst_p1, blst_p1_from_affine, blst_p1_to_affine, p1_affines}; + + /// Input length of g1_mul operation. + const INPUT_LENGTH: usize = 160; + + /// Base gas fee for BLS12-381 g1_mul operation. + pub const BASE_GAS_FEE: u64 = 12000; + + /// Discounts table for G1 MSM as a vector of pairs `[k, discount]`. + const DISCOUNT_TABLE: [u16; 128] = [ + 1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669, + 665, 661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619, + 617, 615, 613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589, + 588, 586, 585, 584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567, + 566, 565, 564, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, + 548, 547, 547, 546, 545, 544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534, + 533, 532, 532, 531, 530, 529, 528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520, + 520, 519, + ]; + + /// 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: + pub fn g1_mul(input: &[u8]) -> Result, &'static str> { + if input.is_empty() || input.len() % INPUT_LENGTH != 0 { + return Err(Box::leak( + format!( + "G1MSM input length should be multiple of {INPUT_LENGTH}, was {}", + input.len() + ) + .into_boxed_str(), + )); + } + + let k = input.len() / INPUT_LENGTH; + 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 slice = &input[i * INPUT_LENGTH..i * INPUT_LENGTH + g1::G1_INPUT_ITEM_LENGTH]; + + // BLST batch API for p1_affines blows up when you pass it a point at infinity, so we must + // filter points at infinity (and their corresponding scalars) from the input. + if slice.iter().all(|i| *i == 0) { + continue; + } + + // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // So we set the subgroup_check flag to `true` + let p0_aff = &g1::extract_g1_input(slice, true)?; + + let mut p0 = blst_p1::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 * INPUT_LENGTH + g1::G1_INPUT_ITEM_LENGTH + ..i * INPUT_LENGTH + g1::G1_INPUT_ITEM_LENGTH + SCALAR_LENGTH], + )? + .b, + ); + } + + // return infinity point if all points are infinity + if g1_points.is_empty() { + return Ok([0; 128].into()); + } + + let points = p1_affines::from(&g1_points); + let multiexp = points.mult(&scalars, NBITS); + + 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) }; + + Ok(g1::encode_g1_point(&multiexp_aff)) + } + + /// G1MSM required gas + pub fn required_gas(input: &[u8]) -> u64 { + let k = input.len() / INPUT_LENGTH; + msm_required_gas(k, &DISCOUNT_TABLE, BASE_GAS_FEE) + } +} + +pub mod g2_add { + use super::*; + use blst::{ + blst_p2, blst_p2_add_or_double_affine, blst_p2_affine, blst_p2_from_affine, + blst_p2_to_affine, + }; + + /// 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 + pub fn g2_add(input: &[u8]) -> Result, &'static str> { + if input.len() != INPUT_LENGTH { + return Err(Box::leak( + format!( + "G2ADD input should be {INPUT_LENGTH} bytes, was {}", + input.len() + ) + .into_boxed_str(), + )); + } + + // NB: There is no subgroup check for the G2 addition precompile. + // + // So we set the subgroup checks here to `false` + let a_aff = &g2::extract_g2_input(&input[..g2::G2_INPUT_ITEM_LENGTH], false)?; + let b_aff = &g2::extract_g2_input(&input[g2::G2_INPUT_ITEM_LENGTH..], false)?; + + 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(); + // 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(); + // SAFETY: p_aff and p are blst values. + unsafe { blst_p2_to_affine(&mut p_aff, &p) }; + + Ok(g2::encode_g2_point(&p_aff)) + } +} + +pub mod g2_mul { + use super::*; + use blst::{blst_p2, blst_p2_affine, blst_p2_from_affine, blst_p2_to_affine, p2_affines}; + + /// Base gas fee for BLS12-381 g2_mul operation. + pub const BASE_GAS_FEE: u64 = 22500; + + /// Input length of g2_mul operation. + pub const INPUT_LENGTH: usize = 288; + + // Discounts table for G2 MSM as a vector of pairs `[k, discount]`: + pub static DISCOUNT_TABLE: [u16; 128] = [ + 1000, 1000, 923, 884, 855, 832, 812, 796, 782, 770, 759, 749, 740, 732, 724, 717, 711, 704, + 699, 693, 688, 683, 679, 674, 670, 666, 663, 659, 655, 652, 649, 646, 643, 640, 637, 634, + 632, 629, 627, 624, 622, 620, 618, 615, 613, 611, 609, 607, 606, 604, 602, 600, 598, 597, + 595, 593, 592, 590, 589, 587, 586, 584, 583, 582, 580, 579, 578, 576, 575, 574, 573, 571, + 570, 569, 568, 567, 566, 565, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, + 552, 551, 550, 549, 548, 547, 546, 545, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537, + 537, 536, 535, 535, 534, 533, 532, 532, 531, 530, 530, 529, 528, 528, 527, 526, 526, 525, + 524, 524, + ]; + + /// 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: + pub fn g2_mul(input: &[u8]) -> Result, &'static str> { + let input_len = input.len(); + if input_len == 0 || input_len % INPUT_LENGTH != 0 { + return Err(Box::leak( + format!( + "G2MSM input length should be multiple of {}, was {}", + INPUT_LENGTH, input_len + ) + .into_boxed_str(), + )); + } + + let k = input_len / INPUT_LENGTH; + 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 slice = &input[i * INPUT_LENGTH..i * INPUT_LENGTH + g2::G2_INPUT_ITEM_LENGTH]; + // BLST batch API for p2_affines blows up when you pass it a point at infinity, so we must + // filter points at infinity (and their corresponding scalars) from the input. + if slice.iter().all(|i| *i == 0) { + continue; + } + + // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // So we set the subgroup_check flag to `true` + let p0_aff = &g2::extract_g2_input(slice, true)?; + + let mut p0 = blst_p2::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 * INPUT_LENGTH + g2::G2_INPUT_ITEM_LENGTH + ..i * INPUT_LENGTH + g2::G2_INPUT_ITEM_LENGTH + SCALAR_LENGTH], + )? + .b, + ); + } + + // return infinity point if all points are infinity + if g2_points.is_empty() { + return Ok([0; 256].into()); + } + + let points = p2_affines::from(&g2_points); + let multiexp = points.mult(&scalars, NBITS); + + 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) }; + + Ok(g2::encode_g2_point(&multiexp_aff)) + } + + /// G2MSM required gas + pub fn required_gas(input: &[u8]) -> u64 { + let k = input.len() / INPUT_LENGTH; + msm_required_gas(k, &DISCOUNT_TABLE, BASE_GAS_FEE) + } +} diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index dadcfbc7..a3aaad2e 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -21,14 +21,8 @@ mod bls; mod kzg; -use blst::{ - blst_p1, blst_p1_add_or_double_affine, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, -}; use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; use eip_152::compress; -use eth_pairings::public_interface::eip2537::{ - SCALAR_BYTE_LENGTH, SERIALIZED_G1_POINT_BYTE_LENGTH, SERIALIZED_G2_POINT_BYTE_LENGTH, -}; use ethereum_types::{H256, U256}; use keccak_hash::keccak; use log::{trace, warn}; @@ -82,10 +76,10 @@ enum Pricing { Blake2F(Blake2FPricer), Linear(Linear), Modexp(ModexpPricer), - Bls12Pairing(Bls12PairingPricer), - Bls12ConstOperations(Bls12ConstOperations), - Bls12MultiexpG1(Bls12MultiexpPricerG1), - Bls12MultiexpG2(Bls12MultiexpPricerG2), + // TODO + // Bls12Pairing(Bls12PairingPricer), + Bls12G1MSM(Bls12PricerG1MSM), + Bls12G2MSM(Bls12PricerG2MSM), } impl Pricer for Pricing { @@ -96,10 +90,10 @@ impl Pricer for Pricing { Self::Blake2F(inner) => inner.cost(input), Self::Linear(inner) => inner.cost(input), Self::Modexp(inner) => inner.cost(input), - Self::Bls12Pairing(inner) => inner.cost(input), - Self::Bls12ConstOperations(inner) => inner.cost(input), - Self::Bls12MultiexpG1(inner) => inner.cost(input), - Self::Bls12MultiexpG2(inner) => inner.cost(input), + // TODO + // Self::Bls12Pairing(inner) => inner.cost(input), + Self::Bls12G1MSM(inner) => inner.cost(input), + Self::Bls12G2MSM(inner) => inner.cost(input), } } } @@ -318,223 +312,33 @@ struct Bls12PairingPricer { price: Bls12PairingPrice, } -/// Pricing for constant Bls12 operations (ADD and MUL in G1 and G2, as well as mappings) +/// MSM pricer in G1 #[derive(Debug, Copy, Clone)] -pub struct Bls12ConstOperations { - /// Fixed price. - pub price: u64, -} - -/// Discount table for multiexponentiation (Peppinger algorithm) -/// Later on is normalized using the divisor -pub const BLS12_MULTIEXP_DISCOUNTS_TABLE: [[u64; 2]; BLS12_MULTIEXP_PAIRS_FOR_MAX_DISCOUNT] = [ - [1, 1200], - [2, 888], - [3, 764], - [4, 641], - [5, 594], - [6, 547], - [7, 500], - [8, 453], - [9, 438], - [10, 423], - [11, 408], - [12, 394], - [13, 379], - [14, 364], - [15, 349], - [16, 334], - [17, 330], - [18, 326], - [19, 322], - [20, 318], - [21, 314], - [22, 310], - [23, 306], - [24, 302], - [25, 298], - [26, 294], - [27, 289], - [28, 285], - [29, 281], - [30, 277], - [31, 273], - [32, 269], - [33, 268], - [34, 266], - [35, 265], - [36, 263], - [37, 262], - [38, 260], - [39, 259], - [40, 257], - [41, 256], - [42, 254], - [43, 253], - [44, 251], - [45, 250], - [46, 248], - [47, 247], - [48, 245], - [49, 244], - [50, 242], - [51, 241], - [52, 239], - [53, 238], - [54, 236], - [55, 235], - [56, 233], - [57, 232], - [58, 231], - [59, 229], - [60, 228], - [61, 226], - [62, 225], - [63, 223], - [64, 222], - [65, 221], - [66, 220], - [67, 219], - [68, 219], - [69, 218], - [70, 217], - [71, 216], - [72, 216], - [73, 215], - [74, 214], - [75, 213], - [76, 213], - [77, 212], - [78, 211], - [79, 211], - [80, 210], - [81, 209], - [82, 208], - [83, 208], - [84, 207], - [85, 206], - [86, 205], - [87, 205], - [88, 204], - [89, 203], - [90, 202], - [91, 202], - [92, 201], - [93, 200], - [94, 199], - [95, 199], - [96, 198], - [97, 197], - [98, 196], - [99, 196], - [100, 195], - [101, 194], - [102, 193], - [103, 193], - [104, 192], - [105, 191], - [106, 191], - [107, 190], - [108, 189], - [109, 188], - [110, 188], - [111, 187], - [112, 186], - [113, 185], - [114, 185], - [115, 184], - [116, 183], - [117, 182], - [118, 182], - [119, 181], - [120, 180], - [121, 179], - [122, 179], - [123, 178], - [124, 177], - [125, 176], - [126, 176], - [127, 175], - [128, 174], -]; - -/// Max discount allowed -pub const BLS12_MULTIEXP_MAX_DISCOUNT: u64 = 174; -/// Max discount is reached at this number of pairs -pub const BLS12_MULTIEXP_PAIRS_FOR_MAX_DISCOUNT: usize = 128; -/// Divisor for discounts table -pub const BLS12_MULTIEXP_DISCOUNT_DIVISOR: u64 = 1000; -/// Length of single G1 + G2 points pair for pairing operation -pub const BLS12_G1_AND_G2_PAIR_LEN: usize = - SERIALIZED_G1_POINT_BYTE_LENGTH + SERIALIZED_G2_POINT_BYTE_LENGTH; - -/// Marter trait for length of input per one pair (point + scalar) -pub trait PointScalarLength: Copy + Clone + std::fmt::Debug + Send + Sync { - /// Length itself - const LENGTH: usize; -} +pub struct Bls12PricerG1MSM; -/// Marker trait that indicated that we perform operations in G1 -#[derive(Clone, Copy, Debug)] -pub struct G1Marker; - -impl PointScalarLength for G1Marker { - const LENGTH: usize = SERIALIZED_G1_POINT_BYTE_LENGTH + SCALAR_BYTE_LENGTH; -} - -/// Marker trait that indicated that we perform operations in G2 -#[derive(Clone, Copy, Debug)] -pub struct G2Marker; - -impl PointScalarLength for G2Marker { - const LENGTH: usize = SERIALIZED_G2_POINT_BYTE_LENGTH + SCALAR_BYTE_LENGTH; -} - -/// Pricing for constant Bls12 operations (ADD and MUL in G1 and G2, as well as mappings) +/// MSM pricer in G1 #[derive(Debug, Copy, Clone)] -pub struct Bls12MultiexpPricer { - /// Base const of the operation (G1 or G2 multiplication) - pub base_price: Bls12ConstOperations, - - _marker: std::marker::PhantomData

, -} +pub struct Bls12PricerG2MSM; -impl Pricer for Bls12ConstOperations { - fn cost(&self, _input: &[u8]) -> U256 { - self.price.into() +// TODO +impl Pricer for Bls12PairingPricer { + fn cost(&self, input: &[u8]) -> U256 { + U256::from(self.price.base) + U256::from(self.price.pair) * U256::from(input.len()) } } -impl Pricer for Bls12PairingPricer { +impl Pricer for Bls12PricerG1MSM { fn cost(&self, input: &[u8]) -> U256 { - U256::from(self.price.base) - + U256::from(self.price.pair) * U256::from(input.len() / BLS12_G1_AND_G2_PAIR_LEN) + U256::from(bls::g1_mul::required_gas(input)) } } -impl Pricer for Bls12MultiexpPricer

{ +impl Pricer for Bls12PricerG2MSM { fn cost(&self, input: &[u8]) -> U256 { - let num_pairs = input.len() / P::LENGTH; - if num_pairs == 0 { - return U256::zero(); - } - let discount = if num_pairs > BLS12_MULTIEXP_PAIRS_FOR_MAX_DISCOUNT { - BLS12_MULTIEXP_MAX_DISCOUNT - } else { - let table_entry = BLS12_MULTIEXP_DISCOUNTS_TABLE[num_pairs - 1]; - table_entry[1] - }; - U256::from(self.base_price.price) * U256::from(num_pairs) * U256::from(discount) - / U256::from(BLS12_MULTIEXP_DISCOUNT_DIVISOR) + U256::from(bls::g2_mul::required_gas(input)) } } -/// Multiexp pricer in G1 -pub type Bls12MultiexpPricerG1 = Bls12MultiexpPricer; - -/// Multiexp pricer in G2 -pub type Bls12MultiexpPricerG2 = Bls12MultiexpPricer; - /// Pricing scheme, execution definition, and activation block for a built-in contract. /// /// Call `cost` to compute cost for the given input, `execute` to execute the contract @@ -623,31 +427,17 @@ impl From for Pricing { price: pricer.price, }) } - ethjson::spec::builtin::Pricing::Bls12ConstOperations(pricer) => { - Self::Bls12ConstOperations(Bls12ConstOperations { - price: pricer.price, - }) - } - ethjson::spec::builtin::Pricing::Bls12Pairing(pricer) => { - Self::Bls12Pairing(Bls12PairingPricer { - price: Bls12PairingPrice { - base: pricer.base, - pair: pricer.pair, - }, - }) - } - ethjson::spec::builtin::Pricing::Bls12G1Multiexp(pricer) => { - Self::Bls12MultiexpG1(Bls12MultiexpPricerG1 { - base_price: Bls12ConstOperations { price: pricer.base }, - _marker: std::marker::PhantomData, - }) - } - ethjson::spec::builtin::Pricing::Bls12G2Multiexp(pricer) => { - Self::Bls12MultiexpG2(Bls12MultiexpPricerG2 { - base_price: Bls12ConstOperations { price: pricer.base }, - _marker: std::marker::PhantomData, - }) - } + // TODO + // ethjson::spec::builtin::Pricing::Bls12Pairing(pricer) => { + // Self::Bls12Pairing(Bls12PairingPricer { + // price: Bls12PairingPrice { + // base: pricer.base, + // pair: pricer.pair, + // }, + // }) + // } + ethjson::spec::builtin::Pricing::Bls12PricerG1MSM => Self::Bls12G1MSM(Bls12PricerG1MSM), + ethjson::spec::builtin::Pricing::Bls12PricerG2MSM => Self::Bls12G2MSM(Bls12PricerG2MSM), } } } @@ -676,17 +466,13 @@ enum EthereumBuiltin { Kgz(Kzg), /// bls12_381 addition in g1 Bls12G1Add(Bls12G1Add), + /// bls12_381 multiplication in g1 + Bls12G1Mul(Bls12G1Mul), + /// bls12_381 addition in g2 + Bls12G2Add(Bls12G2Add), + /// bls12_381 multiplication in g2 + Bls12G2Mul(Bls12G2Mul), /* TODO: refator it - /// bls12_381 multiplication in g1 - Bls12G1Mul(Bls12G1Mul), - /// bls12_381 multiexponentiation in g1 - Bls12G1MultiExp(Bls12G1MultiExp), - /// bls12_381 addition in g2 - Bls12G2Add(Bls12G2Add), - /// bls12_381 multiplication in g2 - Bls12G2Mul(Bls12G2Mul), - /// bls12_381 multiexponentiation in g2 - Bls12G2MultiExp(Bls12G2MultiExp), /// bls12_381 pairing Bls12Pairing(Bls12Pairing), /// bls12_381 fp to g1 mapping @@ -712,12 +498,10 @@ impl FromStr for EthereumBuiltin { "blake2_f" => Ok(Self::Blake2F(Blake2F)), "kzg" => Ok(Self::Kgz(Kzg)), "bls12_381_g1_add" => Ok(Self::Bls12G1Add(Bls12G1Add)), + "bls12_381_g1_mul" => Ok(Self::Bls12G1Mul(Bls12G1Mul)), + "bls12_381_g2_add" => Ok(Self::Bls12G2Add(Bls12G2Add)), + "bls12_381_g2_mul" => Ok(Self::Bls12G2Mul(Bls12G2Mul)), /* TODO: refactor it - "bls12_381_g1_mul" => Ok(Self::Bls12G1Mul(Bls12G1Mul)), - "bls12_381_g1_multiexp" => Ok(Self::Bls12G1MultiExp(Bls12G1MultiExp)), - "bls12_381_g2_add" => Ok(Self::Bls12G2Add(Bls12G2Add)), - "bls12_381_g2_mul" => Ok(Self::Bls12G2Mul(Bls12G2Mul)), - "bls12_381_g2_multiexp" => Ok(Self::Bls12G2MultiExp(Bls12G2MultiExp)), "bls12_381_pairing" => Ok(Self::Bls12Pairing(Bls12Pairing)), "bls12_381_fp_to_g1" => Ok(Self::Bls12MapFpToG1(Bls12MapFpToG1)), "bls12_381_fp2_to_g2" => Ok(Self::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), @@ -741,12 +525,10 @@ impl Implementation for EthereumBuiltin { Self::Blake2F(inner) => inner.execute(input, output), Self::Kgz(inner) => inner.execute(input, output), Self::Bls12G1Add(inner) => inner.execute(input, output), - /* Refactor it Self::Bls12G1Mul(inner) => inner.execute(input, output), - Self::Bls12G1MultiExp(inner) => inner.execute(input, output), Self::Bls12G2Add(inner) => inner.execute(input, output), Self::Bls12G2Mul(inner) => inner.execute(input, output), - Self::Bls12G2MultiExp(inner) => inner.execute(input, output), + /* TODO: Refactor it Self::Bls12Pairing(inner) => inner.execute(input, output), Self::Bls12MapFpToG1(inner) => inner.execute(input, output), Self::Bls12MapFp2ToG2(inner) => inner.execute(input, output), @@ -799,15 +581,10 @@ pub struct Kzg; /// The Bls12G1Add builtin. pub struct Bls12G1Add; -/* TODO: refactor it #[derive(Debug)] /// The Bls12G1Mul builtin. pub struct Bls12G1Mul; -#[derive(Debug)] -/// The Bls12G1MultiExp builtin. -pub struct Bls12G1MultiExp; - #[derive(Debug)] /// The Bls12G2Add builtin. pub struct Bls12G2Add; @@ -816,9 +593,7 @@ pub struct Bls12G2Add; /// The Bls12G2Mul builtin. pub struct Bls12G2Mul; -#[derive(Debug)] -/// The Bls12G2MultiExp builtin. -pub struct Bls12G2MultiExp; +/* TODO: refactor it #[derive(Debug)] /// The Bls12Pairing builtin. @@ -1191,111 +966,38 @@ impl Implementation for Kzg { impl Implementation for Bls12G1Add { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - if input.len() != 256 { - return Err("G1ADD input should be 256 bytes"); - } - // NB: There is no subgroup check for the G1 addition precompile. - // - // We set the subgroup checks here to `false` - let a_aff = &bls::g1::extract_g1_input(&input[..bls::g1::G1_INPUT_ITEM_LENGTH], false)?; - let b_aff = &bls::g1::extract_g1_input(&input[bls::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 out = bls::g1::encode_g1_point(&p_aff); - output.write(0, out.as_slice()); + let out = bls::g1_add::g1_add(input)?; + output.write(0, &out); Ok(()) } } -/* TODO: refactor it - impl Implementation for Bls12G1Mul { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::g1_mul(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12G1Mul error: {:?}", e); - - Err("Bls12G1Mul error") - } - } - } -} - -impl Implementation for Bls12G1MultiExp { - fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::g1_multiexp(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12G1MultiExp error: {:?}", e); - - Err("Bls12G1MultiExp error") - } - } + let out = bls::g1_mul::g1_mul(input)?; + output.write(0, out.as_slice()); + Ok(()) } } impl Implementation for Bls12G2Add { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::g2_add(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12G2Add error: {:?}", e); - - Err("Bls12G2Add error") - } - } + let out = bls::g2_add::g2_add(input)?; + output.write(0, &out); + Ok(()) } } impl Implementation for Bls12G2Mul { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::g2_mul(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12G2Mul error: {:?}", e); - - Err("Bls12G2Mul error") - } - } + let out = bls::g2_mul::g2_mul(input)?; + output.write(0, out.as_slice()); + Ok(()) } } +/* TODO: refactor it + impl Implementation for Bls12G2MultiExp { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { let result = EIP2537Executor::g2_multiexp(input); @@ -2282,10 +1984,10 @@ mod tests { } #[test] - fn bls12_381_g1_multiexp() { + fn bls12_381_g1_mul() { let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g1_multiexp").unwrap(), + pricer: btreemap![0 => Pricing::Bls12PricerG1MSM], + native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), }; let input = hex!(" 0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f56 @@ -2382,7 +2084,7 @@ mod tests { #[test] fn bls12_381_g2_mul() { let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], + pricer: btreemap![0 => Pricing::Bls12PricerG2MSM], native: EthereumBuiltin::from_str("bls12_381_g2_mul").unwrap(), }; @@ -2592,17 +2294,15 @@ mod tests { } #[test] - fn bls12_381_g1_multiexp_init_from_spec() { + fn bls12_381_g1_mul_init_from_spec() { use ethjson::spec::builtin::{Bls12G1Multiexp, Pricing}; let b = Builtin::try_from(JsonBuiltin { - name: "bls12_381_g1_multiexp".to_owned(), + name: "bls12_381_g1_mul".to_owned(), pricing: btreemap![ 10000000 => PricingAt { info: None, - price: Pricing::Bls12G1Multiexp(Bls12G1Multiexp{ - base: 12000, - }), + price: Pricing::Bls12PricerG1MSM), } ], }) @@ -2617,17 +2317,15 @@ mod tests { } #[test] - fn bls12_381_g2_multiexp_init_from_spec() { + fn bls12_381_g2_mul_init_from_spec() { use ethjson::spec::builtin::{Bls12G2Multiexp, Pricing}; let b = Builtin::try_from(JsonBuiltin { - name: "bls12_381_g2_multiexp".to_owned(), + name: "bls12_381_g2_mul".to_owned(), pricing: btreemap![ 10000000 => PricingAt { info: None, - price: Pricing::Bls12G2Multiexp(Bls12G2Multiexp{ - base: 55000, - }), + price: Pricing::Bls12PricerG2MSM), } ], }) diff --git a/evm-tests/ethjson/src/spec/builtin.rs b/evm-tests/ethjson/src/spec/builtin.rs index 9012eb91..d3f0fa1c 100644 --- a/evm-tests/ethjson/src/spec/builtin.rs +++ b/evm-tests/ethjson/src/spec/builtin.rs @@ -77,22 +77,6 @@ pub struct Bls12ConstOperations { pub price: u64, } -/// Pricing for constant Bls12 operations (ADD and MUL in G1, as well as mappings) -#[derive(Debug, PartialEq, Eq, Deserialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct Bls12G1Multiexp { - /// Base const of the operation (G1 or G2 multiplication) - pub base: u64, -} - -/// Pricing for constant Bls12 operations (ADD and MUL in G2, as well as mappings) -#[derive(Debug, PartialEq, Eq, Deserialize, Clone)] -#[serde(deny_unknown_fields)] -pub struct Bls12G2Multiexp { - /// Base const of the operation (G1 or G2 multiplication) - pub base: u64, -} - /// Pricing variants. #[derive(Debug, PartialEq, Eq, Deserialize, Clone)] #[serde(deny_unknown_fields)] @@ -112,13 +96,15 @@ pub enum Pricing { /// Pricing for constant alt_bn128 operations AltBn128ConstOperations(AltBn128ConstOperations), /// Pricing of constant price bls12_381 operations - Bls12ConstOperations(Bls12ConstOperations), + // TODO + // Bls12ConstOperations(Bls12ConstOperations), /// Pricing of pairing bls12_381 operation - Bls12Pairing(Bls12Pairing), - /// Pricing of bls12_381 multiexp operations in G1 - Bls12G1Multiexp(Bls12G1Multiexp), - /// Pricing of bls12_381 multiexp operations in G2 - Bls12G2Multiexp(Bls12G2Multiexp), + // TODO + // Bls12Pairing(Bls12Pairing), + /// Pricing of bls12_381 MSM operations in G1 + Bls12PricerG1MSM, + /// Pricing of bls12_381 MSM operations in G2 + Bls12PricerG2MSM, } /// Builtin compatibility layer @@ -197,8 +183,7 @@ pub struct PricingAt { #[cfg(test)] mod tests { use super::{ - AltBn128ConstOperations, Bls12G1Multiexp, Bls12G2Multiexp, Builtin, BuiltinCompat, Linear, - Modexp, Pricing, PricingAt, + AltBn128ConstOperations, Builtin, BuiltinCompat, Linear, Modexp, Pricing, PricingAt, }; use maplit::btreemap; @@ -317,54 +302,4 @@ mod tests { ] ); } - - #[test] - fn deserialization_bls12_381_multiexp_operation() { - let s = r#"{ - "name": "bls12_381_g1_multiexp", - "pricing": { - "10000000": { - "price": { "bls12_g1_multiexp": { "base": 12000}} - } - } - }"#; - let builtin: Builtin = serde_json::from_str::(s).unwrap().into(); - assert_eq!(builtin.name, "bls12_381_g1_multiexp"); - assert_eq!( - builtin.pricing, - btreemap![ - 10000000 => PricingAt { - info: None, - price: Pricing::Bls12G1Multiexp(Bls12G1Multiexp{ - base: 12000 - }), - } - ] - ); - } - - #[test] - fn deserialization_bls12_381_multiexp_operation_in_g2() { - let s = r#"{ - "name": "bls12_381_g2_multiexp", - "pricing": { - "10000000": { - "price": { "bls12_g2_multiexp": { "base": 55000}} - } - } - }"#; - let builtin: Builtin = serde_json::from_str::(s).unwrap().into(); - assert_eq!(builtin.name, "bls12_381_g2_multiexp"); - assert_eq!( - builtin.pricing, - btreemap![ - 10000000 => PricingAt { - info: None, - price: Pricing::Bls12G2Multiexp(Bls12G2Multiexp{ - base: 55000 - }), - } - ] - ); - } } diff --git a/evm-tests/jsontests/src/state.rs b/evm-tests/jsontests/src/state.rs index be740319..48ee2647 100644 --- a/evm-tests/jsontests/src/state.rs +++ b/evm-tests/jsontests/src/state.rs @@ -241,8 +241,6 @@ impl JsonPrecompile { precompile_entry!(map, PRAGUE_BUILTINS, 0x0F); precompile_entry!(map, PRAGUE_BUILTINS, 0x10); precompile_entry!(map, PRAGUE_BUILTINS, 0x11); - precompile_entry!(map, PRAGUE_BUILTINS, 0x12); - precompile_entry!(map, PRAGUE_BUILTINS, 0x13); Some(map) } _ => None, @@ -558,15 +556,11 @@ fn prague_builtins() -> BTreeMap { .try_into() .unwrap(), ); - /* builtins.insert( Address(H160::from_low_u64_be(0xC)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_g1_mul".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), + pricing: PricingCompat::Single(Pricing::Bls12PricerG1MSM), activate_at: None, }) .try_into() @@ -574,43 +568,49 @@ fn prague_builtins() -> BTreeMap { ); builtins.insert( Address(H160::from_low_u64_be(0xD)).into(), - ethjson::spec::Builtin::from(BuiltinCompat { - name: "bls12_381_g1_multiexp".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), - activate_at: None, - }) - .try_into() - .unwrap(), - ); - builtins.insert( - Address(H160::from_low_u64_be(0xE)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_g2_add".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), + pricing: PricingCompat::Single(Pricing::Linear(Linear { base: 600, word: 0 })), activate_at: None, }) .try_into() .unwrap(), ); builtins.insert( - Address(H160::from_low_u64_be(0xF)).into(), + Address(H160::from_low_u64_be(0xE)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_g2_mul".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), + pricing: PricingCompat::Single(Pricing::Bls12PricerG2MSM), activate_at: None, }) .try_into() .unwrap(), ); + // builtins.insert( + // Address(H160::from_low_u64_be(0xE)).into(), + // ethjson::spec::Builtin::from(BuiltinCompat { + // name: "bls12_381_g2_add".to_string(), + // pricing: PricingCompat::Single(Pricing::Linear(Linear { base: 600, word: 0 })), + // activate_at: None, + // }) + // .try_into() + // .unwrap(), + // ); + // builtins.insert( + // Address(H160::from_low_u64_be(0xF)).into(), + // ethjson::spec::Builtin::from(BuiltinCompat { + // name: "bls12_381_g2_mul".to_string(), + // pricing: PricingCompat::Single(Pricing::Linear(Linear { + // base: 22_500, + // word: 0, + // })), + // activate_at: None, + // }) + // .try_into() + // .unwrap(), + // ); + /* TODO refactor + builtins.insert( Address(H160::from_low_u64_be(0x10)).into(), ethjson::spec::Builtin::from(BuiltinCompat { From 021daa2ce9e7792d99b111b244f816cb8e874e17 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 29 Jan 2025 12:55:20 +0100 Subject: [PATCH 10/14] Added BLS pairing --- evm-tests/ethcore-builtin/src/bls.rs | 102 +++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index df74effe..c82427bb 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -628,3 +628,105 @@ pub mod g2_mul { msm_required_gas(k, &DISCOUNT_TABLE, BASE_GAS_FEE) } } + +pub mod pairing { + use super::*; + use blst::{blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop}; + + /// Multiplier gas fee for BLS12-381 pairing operation. + const PAIRING_MULTIPLIER_BASE: u64 = 32600; + /// Offset gas fee for BLS12-381 pairing operation. + const PAIRING_OFFSET_BASE: u64 = 37700; + /// Input length of pairing 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 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: + pub fn pairing(input: &[u8]) -> Result, &'static str> { + let input_len = input.len(); + if input_len == 0 || input_len % INPUT_LENGTH != 0 { + return Err(Box::leak( + format!( + "Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}" + ) + .into_boxed_str(), + )); + } + + let k = input_len / INPUT_LENGTH; + // Accumulator for the fp12 multiplications of the miller loops. + let mut acc = blst_fp12::default(); + for i in 0..k { + // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // So we set the subgroup_check flag to `true` + let p1_aff = &g1::extract_g1_input( + &input[i * INPUT_LENGTH..i * INPUT_LENGTH + g1::G1_INPUT_ITEM_LENGTH], + true, + )?; + + // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check. + // + // So we set the subgroup_check flag to `true` + let p2_aff = &g2::extract_g2_input( + &input[i * INPUT_LENGTH + g1::G1_INPUT_ITEM_LENGTH + ..i * INPUT_LENGTH + g1::G1_INPUT_ITEM_LENGTH + g2::G2_INPUT_ITEM_LENGTH], + true, + )?; + + 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(); + 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 res, &acc, &cur_ml); + } + acc = res; + } else { + // On the first slice (i==0) there is no previous results and no need + // to accumulate. + // SAFETY: acc, p1_aff and p2_aff are blst values. + unsafe { + blst_miller_loop(&mut acc, p2_aff, p1_aff); + } + } + } + + // SAFETY: ret and acc are blst values. + let mut ret = blst_fp12::default(); + unsafe { + blst_final_exp(&mut ret, &acc); + } + + let mut result: u8 = 0; + // SAFETY: ret is a blst value. + unsafe { + if blst_fp12_is_one(&ret) { + result = 1; + } + } + let mut out = [0u8; 256]; + out[255] = result; + Ok(out.into()) + } + + /// Pairing required gas + pub const fn required_gas(input: &[u8]) -> u64 { + let k = input.len() / INPUT_LENGTH; + PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE + } +} From 9ecd836d33fcaf0e3b71aad1469effab3423c9b4 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Wed, 29 Jan 2025 18:55:20 +0100 Subject: [PATCH 11/14] Added BLS Pairing preocompiles and tests --- .github/workflows/rust.yml | 4 +- evm-tests/ethcore-builtin/src/lib.rs | 109 +++++++------------------- evm-tests/ethjson/src/spec/builtin.rs | 13 ++- evm-tests/jsontests/src/state.rs | 51 ++---------- 4 files changed, 43 insertions(+), 134 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c36b2282..9d15f2e0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -99,8 +99,10 @@ jobs: ethereum-spec-tests/fixtures/state_tests/prague/eip7702_set_code_tx/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip7623_increase_calldata_cost/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1add/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1mul/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1msm/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1mul/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2add/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2msm/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2mul/ # Temporally disable as EOFv1 not implemented # ethtests/EIPTests/StateTests/ diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index a3aaad2e..f741c92d 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -76,10 +76,10 @@ enum Pricing { Blake2F(Blake2FPricer), Linear(Linear), Modexp(ModexpPricer), + Bls12G1Mul(Bls12G1Pricer), + Bls12G2Mul(Bls12G2MulPricer), // TODO - // Bls12Pairing(Bls12PairingPricer), - Bls12G1MSM(Bls12PricerG1MSM), - Bls12G2MSM(Bls12PricerG2MSM), + Bls12Pairing(Bls12PairingPricer), } impl Pricer for Pricing { @@ -90,10 +90,10 @@ impl Pricer for Pricing { Self::Blake2F(inner) => inner.cost(input), Self::Linear(inner) => inner.cost(input), Self::Modexp(inner) => inner.cost(input), + Self::Bls12G1Mul(inner) => inner.cost(input), + Self::Bls12G2Mul(inner) => inner.cost(input), // TODO - // Self::Bls12Pairing(inner) => inner.cost(input), - Self::Bls12G1MSM(inner) => inner.cost(input), - Self::Bls12G2MSM(inner) => inner.cost(input), + Self::Bls12Pairing(inner) => inner.cost(input), } } } @@ -299,43 +299,33 @@ impl ModexpPricer { } } -/// Bls12 pairing price +/// MSM pricer in G1 #[derive(Debug, Copy, Clone)] -struct Bls12PairingPrice { - base: u64, - pair: u64, -} - -/// bls12_pairing pricing model. This computes a price using a base cost and a cost per pair. -#[derive(Debug)] -struct Bls12PairingPricer { - price: Bls12PairingPrice, -} +pub struct Bls12G1Pricer; -/// MSM pricer in G1 +/// MSM pricer in G2 #[derive(Debug, Copy, Clone)] -pub struct Bls12PricerG1MSM; +pub struct Bls12G2MulPricer; -/// MSM pricer in G1 +/// Pairing pricer #[derive(Debug, Copy, Clone)] -pub struct Bls12PricerG2MSM; +pub struct Bls12PairingPricer; -// TODO -impl Pricer for Bls12PairingPricer { +impl Pricer for Bls12G1Pricer { fn cost(&self, input: &[u8]) -> U256 { - U256::from(self.price.base) + U256::from(self.price.pair) * U256::from(input.len()) + U256::from(bls::g1_mul::required_gas(input)) } } -impl Pricer for Bls12PricerG1MSM { +impl Pricer for Bls12G2MulPricer { fn cost(&self, input: &[u8]) -> U256 { - U256::from(bls::g1_mul::required_gas(input)) + U256::from(bls::g2_mul::required_gas(input)) } } -impl Pricer for Bls12PricerG2MSM { +impl Pricer for Bls12PairingPricer { fn cost(&self, input: &[u8]) -> U256 { - U256::from(bls::g2_mul::required_gas(input)) + U256::from(bls::pairing::required_gas(input)) } } @@ -427,17 +417,10 @@ impl From for Pricing { price: pricer.price, }) } + ethjson::spec::builtin::Pricing::Bls12G1Mul => Self::Bls12G1Mul(Bls12G1Pricer), + ethjson::spec::builtin::Pricing::Bls12G2Mul => Self::Bls12G2Mul(Bls12G2MulPricer), // TODO - // ethjson::spec::builtin::Pricing::Bls12Pairing(pricer) => { - // Self::Bls12Pairing(Bls12PairingPricer { - // price: Bls12PairingPrice { - // base: pricer.base, - // pair: pricer.pair, - // }, - // }) - // } - ethjson::spec::builtin::Pricing::Bls12PricerG1MSM => Self::Bls12G1MSM(Bls12PricerG1MSM), - ethjson::spec::builtin::Pricing::Bls12PricerG2MSM => Self::Bls12G2MSM(Bls12PricerG2MSM), + ethjson::spec::builtin::Pricing::Bls12Pairing => Self::Bls12Pairing(Bls12PairingPricer), } } } @@ -472,9 +455,9 @@ enum EthereumBuiltin { Bls12G2Add(Bls12G2Add), /// bls12_381 multiplication in g2 Bls12G2Mul(Bls12G2Mul), + /// bls12_381 pairing + Bls12Pairing(Bls12Pairing), /* TODO: refator it - /// bls12_381 pairing - Bls12Pairing(Bls12Pairing), /// bls12_381 fp to g1 mapping Bls12MapFpToG1(Bls12MapFpToG1), /// bls12_381 fp2 to g2 mapping @@ -501,8 +484,8 @@ impl FromStr for EthereumBuiltin { "bls12_381_g1_mul" => Ok(Self::Bls12G1Mul(Bls12G1Mul)), "bls12_381_g2_add" => Ok(Self::Bls12G2Add(Bls12G2Add)), "bls12_381_g2_mul" => Ok(Self::Bls12G2Mul(Bls12G2Mul)), + "bls12_381_pairing" => Ok(Self::Bls12Pairing(Bls12Pairing)), /* TODO: refactor it - "bls12_381_pairing" => Ok(Self::Bls12Pairing(Bls12Pairing)), "bls12_381_fp_to_g1" => Ok(Self::Bls12MapFpToG1(Bls12MapFpToG1)), "bls12_381_fp2_to_g2" => Ok(Self::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), */ @@ -528,8 +511,8 @@ impl Implementation for EthereumBuiltin { Self::Bls12G1Mul(inner) => inner.execute(input, output), Self::Bls12G2Add(inner) => inner.execute(input, output), Self::Bls12G2Mul(inner) => inner.execute(input, output), - /* TODO: Refactor it Self::Bls12Pairing(inner) => inner.execute(input, output), + /* TODO: Refactor it Self::Bls12MapFpToG1(inner) => inner.execute(input, output), Self::Bls12MapFp2ToG2(inner) => inner.execute(input, output), */ @@ -593,12 +576,11 @@ pub struct Bls12G2Add; /// The Bls12G2Mul builtin. pub struct Bls12G2Mul; -/* TODO: refactor it - #[derive(Debug)] /// The Bls12Pairing builtin. pub struct Bls12Pairing; +/* TODO: refactor it #[derive(Debug)] /// The Bls12MapFpToG1 builtin. pub struct Bls12MapFpToG1; @@ -996,46 +978,15 @@ impl Implementation for Bls12G2Mul { } } -/* TODO: refactor it - -impl Implementation for Bls12G2MultiExp { - fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::g2_multiexp(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12G2MultiExp error: {:?}", e); - - Err("Bls12G2MultiExp error") - } - } - } -} - impl Implementation for Bls12Pairing { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::pair(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12Pairing error: {:?}", e); - - Err("Bls12Pairing error") - } - } + let out = bls::pairing::pairing(input)?; + output.write(0, out.as_slice()); + Ok(()) } } +/* TODO: refactor it impl Implementation for Bls12MapFpToG1 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { let result = EIP2537Executor::map_fp_to_g1(input); diff --git a/evm-tests/ethjson/src/spec/builtin.rs b/evm-tests/ethjson/src/spec/builtin.rs index d3f0fa1c..dc28d529 100644 --- a/evm-tests/ethjson/src/spec/builtin.rs +++ b/evm-tests/ethjson/src/spec/builtin.rs @@ -95,16 +95,13 @@ pub enum Pricing { AltBn128Pairing(AltBn128Pairing), /// Pricing for constant alt_bn128 operations AltBn128ConstOperations(AltBn128ConstOperations), - /// Pricing of constant price bls12_381 operations - // TODO - // Bls12ConstOperations(Bls12ConstOperations), - /// Pricing of pairing bls12_381 operation - // TODO - // Bls12Pairing(Bls12Pairing), /// Pricing of bls12_381 MSM operations in G1 - Bls12PricerG1MSM, + Bls12G1Mul, /// Pricing of bls12_381 MSM operations in G2 - Bls12PricerG2MSM, + Bls12G2Mul, + // TODO + /// Pricing of pairing bls12_381 operation + Bls12Pairing, } /// Builtin compatibility layer diff --git a/evm-tests/jsontests/src/state.rs b/evm-tests/jsontests/src/state.rs index 48ee2647..694d4d77 100644 --- a/evm-tests/jsontests/src/state.rs +++ b/evm-tests/jsontests/src/state.rs @@ -560,7 +560,7 @@ fn prague_builtins() -> BTreeMap { Address(H160::from_low_u64_be(0xC)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_g1_mul".to_string(), - pricing: PricingCompat::Single(Pricing::Bls12PricerG1MSM), + pricing: PricingCompat::Single(Pricing::Bls12G1Mul), activate_at: None, }) .try_into() @@ -580,63 +580,23 @@ fn prague_builtins() -> BTreeMap { Address(H160::from_low_u64_be(0xE)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_g2_mul".to_string(), - pricing: PricingCompat::Single(Pricing::Bls12PricerG2MSM), + pricing: PricingCompat::Single(Pricing::Bls12G2Mul), activate_at: None, }) .try_into() .unwrap(), ); - // builtins.insert( - // Address(H160::from_low_u64_be(0xE)).into(), - // ethjson::spec::Builtin::from(BuiltinCompat { - // name: "bls12_381_g2_add".to_string(), - // pricing: PricingCompat::Single(Pricing::Linear(Linear { base: 600, word: 0 })), - // activate_at: None, - // }) - // .try_into() - // .unwrap(), - // ); - // builtins.insert( - // Address(H160::from_low_u64_be(0xF)).into(), - // ethjson::spec::Builtin::from(BuiltinCompat { - // name: "bls12_381_g2_mul".to_string(), - // pricing: PricingCompat::Single(Pricing::Linear(Linear { - // base: 22_500, - // word: 0, - // })), - // activate_at: None, - // }) - // .try_into() - // .unwrap(), - // ); - /* TODO refactor - builtins.insert( - Address(H160::from_low_u64_be(0x10)).into(), - ethjson::spec::Builtin::from(BuiltinCompat { - name: "bls12_381_g2_multiexp".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), - activate_at: None, - }) - .try_into() - .unwrap(), - ); - builtins.insert( - Address(H160::from_low_u64_be(0x11)).into(), + Address(H160::from_low_u64_be(0xF)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_pairing".to_string(), - pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, - word: 0, - })), + pricing: PricingCompat::Single(Pricing::Bls12Pairing), activate_at: None, }) .try_into() .unwrap(), ); + /* TODO refactor builtins.insert( Address(H160::from_low_u64_be(0x12)).into(), ethjson::spec::Builtin::from(BuiltinCompat { @@ -663,7 +623,6 @@ fn prague_builtins() -> BTreeMap { .try_into() .unwrap(), ); - */ builtins From 054678978f6c95f202b1b85f21c7f27cf7048068 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Thu, 30 Jan 2025 13:20:45 +0100 Subject: [PATCH 12/14] Added BLS precompiles & tests: map_fp_to_g1, bls12_map_fp2_to_g2 --- .github/workflows/rust.yml | 6 ++- evm-tests/ethcore-builtin/src/bls.rs | 71 +++++++++++++++++++++++++++ evm-tests/ethcore-builtin/src/lib.rs | 59 +++++----------------- evm-tests/ethjson/src/spec/builtin.rs | 1 - evm-tests/jsontests/src/main.rs | 2 +- evm-tests/jsontests/src/state.rs | 10 ++-- 6 files changed, 93 insertions(+), 56 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9d15f2e0..19f72d15 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -103,7 +103,11 @@ jobs: ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1mul/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2add/ \ ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2msm/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2mul/ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2mul/ \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_map_fp_to_g1 \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_map_fp2_to_g2 \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_variable_length_input_contracts \ + ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_precompiles_before_fork # Temporally disable as EOFv1 not implemented # ethtests/EIPTests/StateTests/ diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index c82427bb..7daafe3f 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -730,3 +730,74 @@ pub mod pairing { PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE } } + +pub mod map_fp_to_g1 { + use super::*; + use blst::{blst_map_to_g1, blst_p1, blst_p1_to_affine}; + + /// 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: + pub fn map_fp_to_g1(input: &[u8]) -> Result, &'static str> { + if input.len() != PADDED_FP_LENGTH { + return Err(Box::leak( + format!( + "MAP_FP_TO_G1 input should be {PADDED_FP_LENGTH} bytes, was {}", + input.len() + ) + .into_boxed_str(), + )); + } + + let input_p0 = remove_padding(input)?; + let fp = fp_from_bendian(input_p0)?; + + let mut p = blst_p1::default(); + // SAFETY: p and fp are blst values. + // third argument is unused if null. + unsafe { blst_map_to_g1(&mut p, &fp, core::ptr::null()) }; + + 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)) + } +} + +pub mod map_fp2_to_g2 { + use super::*; + use crate::bls::g2::check_canonical_fp2; + use blst::{blst_map_to_g2, blst_p2, blst_p2_affine, blst_p2_to_affine}; + + /// Field-to-curve call expects 128 bytes as an input that is interpreted as + /// an element of Fp2. Output of this call is 256 bytes and is an encoded G2 + /// point. + /// See also: + pub fn map_fp2_to_g2(input: &[u8]) -> Result, &'static str> { + if input.len() != PADDED_FP2_LENGTH { + return Err(Box::leak( + format!( + "MAP_FP2_TO_G2 input should be {PADDED_FP2_LENGTH} bytes, was {}", + input.len() + ) + .into_boxed_str(), + )); + } + + let input_p0_x = remove_padding(&input[..PADDED_FP_LENGTH])?; + let input_p0_y = remove_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?; + let fp2 = check_canonical_fp2(input_p0_x, input_p0_y)?; + + let mut p = blst_p2::default(); + // SAFETY: p and fp2 are blst values. + // third argument is unused if null. + unsafe { blst_map_to_g2(&mut p, &fp2, core::ptr::null()) }; + + 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) }; + + Ok(g2::encode_g2_point(&p_aff)) + } +} diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index f741c92d..b0792e19 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -78,7 +78,6 @@ enum Pricing { Modexp(ModexpPricer), Bls12G1Mul(Bls12G1Pricer), Bls12G2Mul(Bls12G2MulPricer), - // TODO Bls12Pairing(Bls12PairingPricer), } @@ -92,7 +91,6 @@ impl Pricer for Pricing { Self::Modexp(inner) => inner.cost(input), Self::Bls12G1Mul(inner) => inner.cost(input), Self::Bls12G2Mul(inner) => inner.cost(input), - // TODO Self::Bls12Pairing(inner) => inner.cost(input), } } @@ -419,7 +417,6 @@ impl From for Pricing { } ethjson::spec::builtin::Pricing::Bls12G1Mul => Self::Bls12G1Mul(Bls12G1Pricer), ethjson::spec::builtin::Pricing::Bls12G2Mul => Self::Bls12G2Mul(Bls12G2MulPricer), - // TODO ethjson::spec::builtin::Pricing::Bls12Pairing => Self::Bls12Pairing(Bls12PairingPricer), } } @@ -457,12 +454,10 @@ enum EthereumBuiltin { Bls12G2Mul(Bls12G2Mul), /// bls12_381 pairing Bls12Pairing(Bls12Pairing), - /* TODO: refator it - /// bls12_381 fp to g1 mapping - Bls12MapFpToG1(Bls12MapFpToG1), - /// bls12_381 fp2 to g2 mapping - Bls12MapFp2ToG2(Bls12MapFp2ToG2), - */ + /// bls12_381 fp to g1 mapping + Bls12MapFpToG1(Bls12MapFpToG1), + /// bls12_381 fp2 to g2 mapping + Bls12MapFp2ToG2(Bls12MapFp2ToG2), } impl FromStr for EthereumBuiltin { @@ -485,10 +480,8 @@ impl FromStr for EthereumBuiltin { "bls12_381_g2_add" => Ok(Self::Bls12G2Add(Bls12G2Add)), "bls12_381_g2_mul" => Ok(Self::Bls12G2Mul(Bls12G2Mul)), "bls12_381_pairing" => Ok(Self::Bls12Pairing(Bls12Pairing)), - /* TODO: refactor it - "bls12_381_fp_to_g1" => Ok(Self::Bls12MapFpToG1(Bls12MapFpToG1)), - "bls12_381_fp2_to_g2" => Ok(Self::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), - */ + "bls12_381_fp_to_g1" => Ok(Self::Bls12MapFpToG1(Bls12MapFpToG1)), + "bls12_381_fp2_to_g2" => Ok(Self::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), _ => Err(()), } } @@ -512,10 +505,8 @@ impl Implementation for EthereumBuiltin { Self::Bls12G2Add(inner) => inner.execute(input, output), Self::Bls12G2Mul(inner) => inner.execute(input, output), Self::Bls12Pairing(inner) => inner.execute(input, output), - /* TODO: Refactor it Self::Bls12MapFpToG1(inner) => inner.execute(input, output), Self::Bls12MapFp2ToG2(inner) => inner.execute(input, output), - */ } } } @@ -580,7 +571,6 @@ pub struct Bls12G2Mul; /// The Bls12Pairing builtin. pub struct Bls12Pairing; -/* TODO: refactor it #[derive(Debug)] /// The Bls12MapFpToG1 builtin. pub struct Bls12MapFpToG1; @@ -588,7 +578,6 @@ pub struct Bls12MapFpToG1; #[derive(Debug)] /// The Bls12MapFp2ToG2 builtin. pub struct Bls12MapFp2ToG2; -*/ impl Implementation for Identity { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { @@ -986,45 +975,21 @@ impl Implementation for Bls12Pairing { } } -/* TODO: refactor it impl Implementation for Bls12MapFpToG1 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::map_fp_to_g1(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12MapFpToG1 error: {:?}", e); - - Err("Bls12MapFpToG1 error") - } - } + let out = bls::map_fp_to_g1::map_fp_to_g1(input)?; + output.write(0, out.as_slice()); + Ok(()) } } impl Implementation for Bls12MapFp2ToG2 { fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> { - let result = EIP2537Executor::map_fp2_to_g2(input); - - match result { - Ok(result_bytes) => { - output.write(0, &result_bytes[..]); - - Ok(()) - } - Err(e) => { - trace!(target: "builtin", "Bls12MapFp2ToG2 error: {:?}", e); - - Err("Bls12MapFp2ToG2 error") - } - } + let out = bls::map_fp2_to_g2::map_fp2_to_g2(input)?; + output.write(0, out.as_slice()); + Ok(()) } } -*/ #[cfg(test)] mod tests { diff --git a/evm-tests/ethjson/src/spec/builtin.rs b/evm-tests/ethjson/src/spec/builtin.rs index dc28d529..b75209e6 100644 --- a/evm-tests/ethjson/src/spec/builtin.rs +++ b/evm-tests/ethjson/src/spec/builtin.rs @@ -99,7 +99,6 @@ pub enum Pricing { Bls12G1Mul, /// Pricing of bls12_381 MSM operations in G2 Bls12G2Mul, - // TODO /// Pricing of pairing bls12_381 operation Bls12Pairing, } diff --git a/evm-tests/jsontests/src/main.rs b/evm-tests/jsontests/src/main.rs index 8dcacf46..bb5161fd 100644 --- a/evm-tests/jsontests/src/main.rs +++ b/evm-tests/jsontests/src/main.rs @@ -105,7 +105,7 @@ fn main() -> Result<(), String> { let mut tests_result = TestExecutionResult::new(); for src_name in matches.get_many::("PATH").unwrap() { let path = Path::new(src_name); - assert!(path.exists(), "data source is not exist"); + assert!(path.exists(), "data source is not exist: {path:?}"); if path.is_file() { run_test_for_file(&spec, &verbose_output, path, &mut tests_result); } else if path.is_dir() { diff --git a/evm-tests/jsontests/src/state.rs b/evm-tests/jsontests/src/state.rs index 694d4d77..3bb7e15d 100644 --- a/evm-tests/jsontests/src/state.rs +++ b/evm-tests/jsontests/src/state.rs @@ -596,13 +596,12 @@ fn prague_builtins() -> BTreeMap { .try_into() .unwrap(), ); - /* TODO refactor builtins.insert( - Address(H160::from_low_u64_be(0x12)).into(), + Address(H160::from_low_u64_be(0x10)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_fp_to_g1".to_string(), pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, + base: 5_500, word: 0, })), activate_at: None, @@ -611,11 +610,11 @@ fn prague_builtins() -> BTreeMap { .unwrap(), ); builtins.insert( - Address(H160::from_low_u64_be(0x13)).into(), + Address(H160::from_low_u64_be(0x11)).into(), ethjson::spec::Builtin::from(BuiltinCompat { name: "bls12_381_fp2_to_g2".to_string(), pricing: PricingCompat::Single(Pricing::Linear(Linear { - base: 50_000, + base: 23_800, word: 0, })), activate_at: None, @@ -623,7 +622,6 @@ fn prague_builtins() -> BTreeMap { .try_into() .unwrap(), ); - */ builtins } From 2cf6fe6a60261c3e2c7e5edbf30446a6a473e8b0 Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Thu, 30 Jan 2025 19:05:29 +0100 Subject: [PATCH 13/14] Added gas cost and tests for all tests ofr BLS12-381 --- .github/workflows/rust.yml | 13 +- evm-tests/ethcore-builtin/src/bls.rs | 6 +- evm-tests/ethcore-builtin/src/lib.rs | 302 ++++++++++++--------------- 3 files changed, 131 insertions(+), 190 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 19f72d15..92f22e8b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -96,18 +96,7 @@ jobs: cargo run -r -p evm-jsontests -F enable-slow-tests -- state -f \ ethtests/GeneralStateTests/ \ ethtests/LegacyTests/Cancun/GeneralStateTests/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip7702_set_code_tx/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip7623_increase_calldata_cost/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1add/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1msm/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g1mul/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2add/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2msm/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_g2mul/ \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_map_fp_to_g1 \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_map_fp2_to_g2 \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_variable_length_input_contracts \ - ethereum-spec-tests/fixtures/state_tests/prague/eip2537_bls_12_381_precompiles/bls12_precompiles_before_fork + ethereum-spec-tests/fixtures/state_tests/prague/ # Temporally disable as EOFv1 not implemented # ethtests/EIPTests/StateTests/ diff --git a/evm-tests/ethcore-builtin/src/bls.rs b/evm-tests/ethcore-builtin/src/bls.rs index 7daafe3f..5ecad32f 100644 --- a/evm-tests/ethcore-builtin/src/bls.rs +++ b/evm-tests/ethcore-builtin/src/bls.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - use blst::{ blst_bendian_from_fp, blst_fp, blst_fp_from_bendian, blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, blst_scalar, blst_scalar_from_bendian, @@ -719,8 +717,8 @@ pub mod pairing { result = 1; } } - let mut out = [0u8; 256]; - out[255] = result; + let mut out = [0u8; 32]; + out[31] = result; Ok(out.into()) } diff --git a/evm-tests/ethcore-builtin/src/lib.rs b/evm-tests/ethcore-builtin/src/lib.rs index b0792e19..e1be1f8d 100644 --- a/evm-tests/ethcore-builtin/src/lib.rs +++ b/evm-tests/ethcore-builtin/src/lib.rs @@ -76,7 +76,7 @@ enum Pricing { Blake2F(Blake2FPricer), Linear(Linear), Modexp(ModexpPricer), - Bls12G1Mul(Bls12G1Pricer), + Bls12G1Mul(Bls12G1MulPricer), Bls12G2Mul(Bls12G2MulPricer), Bls12Pairing(Bls12PairingPricer), } @@ -299,7 +299,7 @@ impl ModexpPricer { /// MSM pricer in G1 #[derive(Debug, Copy, Clone)] -pub struct Bls12G1Pricer; +pub struct Bls12G1MulPricer; /// MSM pricer in G2 #[derive(Debug, Copy, Clone)] @@ -309,7 +309,7 @@ pub struct Bls12G2MulPricer; #[derive(Debug, Copy, Clone)] pub struct Bls12PairingPricer; -impl Pricer for Bls12G1Pricer { +impl Pricer for Bls12G1MulPricer { fn cost(&self, input: &[u8]) -> U256 { U256::from(bls::g1_mul::required_gas(input)) } @@ -415,7 +415,7 @@ impl From for Pricing { price: pricer.price, }) } - ethjson::spec::builtin::Pricing::Bls12G1Mul => Self::Bls12G1Mul(Bls12G1Pricer), + ethjson::spec::builtin::Pricing::Bls12G1Mul => Self::Bls12G1Mul(Bls12G1MulPricer), ethjson::spec::builtin::Pricing::Bls12G2Mul => Self::Bls12G2Mul(Bls12G2MulPricer), ethjson::spec::builtin::Pricing::Bls12Pairing => Self::Bls12Pairing(Bls12PairingPricer), } @@ -993,7 +993,10 @@ impl Implementation for Bls12MapFp2ToG2 { #[cfg(test)] mod tests { - use super::{Builtin, EthereumBuiltin, FromStr, Implementation, Linear, ModexpPricer, Pricing}; + use super::{ + Bls12G1MulPricer, Bls12G2MulPricer, Bls12PairingPricer, Builtin, EthereumBuiltin, FromStr, + Implementation, Linear, ModexpPricer, Pricing, + }; use ethereum_types::U256; use ethjson::spec::builtin::{ AltBn128Pairing as JsonAltBn128PairingPricing, Builtin as JsonBuiltin, @@ -1849,63 +1852,62 @@ mod tests { assert_eq!(b.cost(&[0; 1], 0), U256::from(0), "not activated yet"); assert_eq!(b.cost(&[0; 1], 1), U256::from(1_337), "use price #3"); } - /* TODO: refactor it - #[test] - fn bls12_381_g1_add() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g1_add").unwrap(), - }; + #[test] + fn bls12_381_g1_add() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Linear(Linear { base: 375, word: 0 })], + native: EthereumBuiltin::from_str("bls12_381_g1_add").unwrap(), + }; - let input = hex!(" + let input = hex!(" 00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb 0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed2 000000000000000000000000000000000441e7f7f96198e4c23bd5eb16f1a7f045dbc8c53219ab2bcea91d3a027e2dfe659feac64905f8b9add7e4bfc91bec2b 0000000000000000000000000000000005fc51bb1b40c87cd4292d4b66f8ca5ce4ef9abd2b69d4464b4879064203bda7c9fc3f896a3844ebc713f7bb20951d95 "); - let expected = hex!(" + let expected = hex!(" 0000000000000000000000000000000016b8ab56b45a9294466809b8e858c1ad15ad0d52cfcb62f8f5753dc94cee1de6efaaebce10701e3ec2ecaa9551024ea 600000000000000000000000000000000124571eec37c0b1361023188d66ec17c1ec230d31b515e0e81e599ec19e40c8a7c8cdea9735bc3d8b4e37ca7e5dd71f6 "); - let mut output = [0u8; 128]; + let mut output = [0u8; 128]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_g1_mul() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), - }; + #[test] + fn bls12_381_g1_mul() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12G1Mul(Bls12G1MulPricer)], + native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), + }; - let input = hex!(" + let input = hex!(" 000000000000000000000000000000000b3a1dfe2d1b62538ed49648cb2a8a1d66bdc4f7a492eee59942ab810a306876a7d49e5ac4c6bb1613866c158ded993e 000000000000000000000000000000001300956110f47ca8e2aacb30c948dfd046bf33f69bf54007d76373c5a66019454da45e3cf14ce2b9d53a50c9b4366aa3 ac23d04ee3acc757aae6795532ce4c9f34534e506a4d843a26b052a040c79659 "); - let expected = hex!(" + let expected = hex!(" 000000000000000000000000000000001227b7021e9d3dc8bcbf5b346fc503f7f8576965769c5e22bb70056eef03c84b8c80290ae9ce20345770290c55549bce 00000000000000000000000000000000188ddbbfb4ad2d34a8d3dc0ec92b70b63caa73ad7dea0cc9740bac2309b4bb11107912bd086379746e9a9bcd26d4db58 "); - let mut output = [0u8; 128]; + let mut output = [0u8; 128]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_g1_mul() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12PricerG1MSM], - native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), - }; - let input = hex!(" + #[test] + fn bls12_381_g1_mul_extend() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12G1Mul(Bls12G1MulPricer)], + native: EthereumBuiltin::from_str("bls12_381_g1_mul").unwrap(), + }; + let input = hex!(" 0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f56 0000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992fee b3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e @@ -1955,25 +1957,25 @@ mod tests { 000000000000000000000000000000001699a3cc1f10cd2ed0dc68eb916b4402e4f12bf4746893bf70e26e209e605ea89e3d53e7ac52bd07713d3c8fc671931d b3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746 "); - let expected = hex!(" + let expected = hex!(" 000000000000000000000000000000000b370fc4ca67fb0c3c270b1b4c4816ef953cd9f7cf6ad20e88099c40aace9c4bb3f4cd215e5796f65080c69c9f4d2a0f 0000000000000000000000000000000007203220935ddc0190e2d7a99ec3f9231da550768373f9a5933dffd366f48146f8ea5fe5dee6539d925288083bb5a8f1 "); - let mut output = [0u8; 128]; + let mut output = [0u8; 128]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_g2_add() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g2_add").unwrap(), - }; - let input = hex!(" + #[test] + fn bls12_381_g2_add() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Linear(Linear { base: 600, word: 0 })], + native: EthereumBuiltin::from_str("bls12_381_g2_add").unwrap(), + }; + let input = hex!(" 00000000000000000000000000000000161c595d151a765c7dee03c9210414cdffab84b9078b4b98f9df09be5ec299b8f6322c692214f00ede97958f235c352b 00000000000000000000000000000000106883e0937cb869e579b513bde8f61020fcf26be38f8b98eae3885cedec2e028970415fc653cf10e64727b7f6232e06 000000000000000000000000000000000f351a82b733af31af453904874b7ca6252957a1ab51ec7f7b6fff85bbf3331f870a7e72a81594a9930859237e7a154d @@ -1983,56 +1985,56 @@ mod tests { 0000000000000000000000000000000011f0c512fe7dc2dd8abdc1d22c2ecd2e7d1b84f8950ab90fc93bf54badf7bb9a9bad8c355d52a5efb110dca891e4cc3d 0000000000000000000000000000000019774010814d1d94caf3ecda3ef4f5c5986e966eaf187c32a8a5a4a59452af0849690cf71338193f2d8435819160bcfb "); - let expected = hex!(" + let expected = hex!(" 000000000000000000000000000000000383ab7a17cc57e239e874af3f1aaabba0e64625b848676712f05f56132dbbd1cadfabeb3fe1f461daba3f1720057ddd 00000000000000000000000000000000096967e9b3747f1b8e344535eaa0c51e70bc77412bfaa2a7ce76f11f570c9febb8f4227316866a416a50436d098e6f9a 000000000000000000000000000000001079452b7519a7b090d668d54c266335b1cdd1080ed867dd17a2476b11c2617da829bf740e51cb7dfd60d73ed02c0c67 00000000000000000000000000000000015fc3a972e05cbd9014882cfe6f2f16d0291c403bf28b05056ac625e4f71dfb1295c85d73145ef554614e6eb2d5bf02 "); - let mut output = [0u8; 256]; + let mut output = [0u8; 256]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_g2_mul() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12PricerG2MSM], - native: EthereumBuiltin::from_str("bls12_381_g2_mul").unwrap(), - }; + #[test] + fn bls12_381_g2_mul() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12G2Mul(Bls12G2MulPricer)], + native: EthereumBuiltin::from_str("bls12_381_g2_mul").unwrap(), + }; - let input = hex!(" + let input = hex!(" 00000000000000000000000000000000159da74f15e4c614b418997f81a1b8a3d9eb8dd80d94b5bad664bff271bb0f2d8f3c4ceb947dc6300d5003a2f7d7a829 000000000000000000000000000000000cdd4d1d4666f385dd54052cf5c1966328403251bebb29f0d553a9a96b5ade350c8493270e9b5282d8a06f9fa8d7b1d9 00000000000000000000000000000000189f8d3c94fdaa72cc67a7f93d35f91e22206ff9e97eed9601196c28d45b69c802ae92bcbf582754717b0355e08d37c0 00000000000000000000000000000000054b0a282610f108fc7f6736b8c22c8778d082bf4b0d0abca5a228198eba6a868910dd5c5c440036968e977955054196 b6a9408625b0ca8fcbfb21d34eec2d8e24e9a30d2d3b32d7a37d110b13afbfea "); - let expected = hex!(" + let expected = hex!(" 000000000000000000000000000000000b24adeb2ca184c9646cb39f45e0cf8711e10bf308ddae06519562b0af3b43be44c2fcb90622726f7446ed690551d30e 00000000000000000000000000000000069467c3edc19416067f572c51740ba8e0e7380121ade98e38ce26d907a2bf3a4e82af2bd195b6c3b7c9b29218880531 000000000000000000000000000000000eb8c90d0727511be53ffcb6f3b144c07983ed4b76d31ab003e45b37c7bc1066910f5e29f5adad5757af979dd0d8351d 0000000000000000000000000000000004760f8d814189dcd893949797a3c4f56f2b60964bba3a4fc741e7ead05eb886787b2502fc64b20363eeba44e65d0ca0 "); - let mut output = [0u8; 256]; + let mut output = [0u8; 256]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_g2_multiexp() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12ConstOperations(Bls12ConstOperations{price: 1})], - native: EthereumBuiltin::from_str("bls12_381_g2_multiexp").unwrap(), - }; + #[test] + fn bls12_381_g2_mul_extend() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12G2Mul(Bls12G2MulPricer)], + native: EthereumBuiltin::from_str("bls12_381_g2_mul").unwrap(), + }; - let input = hex!(" + let input = hex!(" 00000000000000000000000000000000039b10ccd664da6f273ea134bb55ee48f09ba585a7e2bb95b5aec610631ac49810d5d616f67ba0147e6d1be476ea220e 0000000000000000000000000000000000fbcdff4e48e07d1f73ec42fe7eb026f5c30407cfd2f22bbbfe5b2a09e8a7bb4884178cb6afd1c95f80e646929d3004 0000000000000000000000000000000001ed3b0e71acb0adbf44643374edbf4405af87cfc0507db7e8978889c6c3afbe9754d1182e98ac3060d64994d31ef576 @@ -2114,28 +2116,28 @@ mod tests { 00000000000000000000000000000000047b9163a218f7654a72e0d7c651a2cf7fd95e9784a59e0bf119d081de6c0465d374a55fbc1eff9828c9fd29abf4c4bd b3682accc3939283b870357cf83683350baf73aa0d3d68bda82a0f6ae7e51746 "); - let expected = hex!(" + let expected = hex!(" 00000000000000000000000000000000083ad744b34f6393bc983222b004657494232c5d9fbc978d76e2377a28a34c4528da5d91cbc0977dc953397a6d21eca2 0000000000000000000000000000000015aec6526e151cf5b8403353517dfb9a162087a698b71f32b266d3c5c936a83975d5567c25b3a5994042ec1379c8e526 000000000000000000000000000000000e3647185d1a20efad19f975729908840dc33909a583600f7915025f906aef9c022fd34e618170b11178aaa824ae36b3 00000000000000000000000000000000159576d1d53f6cd12c39d651697e11798321f17cd287118d7ebeabf68281bc03109ee103ee8ef2ef93c71dd1dcbaf1e0 "); - let mut output = [0u8; 256]; + let mut output = [0u8; 256]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_pairing() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], - native: EthereumBuiltin::from_str("bls12_381_pairing").unwrap(), - }; + #[test] + fn bls12_381_pairing() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer)], + native: EthereumBuiltin::from_str("bls12_381_pairing").unwrap(), + }; - let input = hex!(" + let input = hex!(" 000000000000000000000000000000001830f52d9bff64a623c6f5259e2cd2c2a08ea17a8797aaf83174ea1e8c3bd3955c2af1d39bfa474815bfe60714b7cd80 000000000000000000000000000000000874389c02d4cf1c61bc54c4c24def11dfbe7880bc998a95e70063009451ee8226fec4b278aade3a7cea55659459f1d5 00000000000000000000000000000000197737f831d4dc7e708475f4ca7ca15284db2f3751fcaac0c17f517f1ddab35e1a37907d7b99b39d6c8d9001cd50e79e @@ -2149,111 +2151,63 @@ mod tests { 000000000000000000000000000000001918cb6e448ed69fb906145de3f11455ee0359d030e90d673ce050a360d796de33ccd6a941c49a1414aca1c26f9e699e 0000000000000000000000000000000019a915154a13249d784093facc44520e7f3a18410ab2a3093e0b12657788e9419eec25729944f7945e732104939e7a9e "); - let expected = hex!( - " + let expected = hex!( + " 0000000000000000000000000000000000000000000000000000000000000001 " - ); + ); - let mut output = [0u8; 32]; + let mut output = [0u8; 32]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_fp_to_g1() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], - native: EthereumBuiltin::from_str("bls12_381_fp_to_g1").unwrap(), - }; + #[test] + fn bls12_381_fp_to_g1() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Linear(Linear { base: 5_500, word: 0 })], + native: EthereumBuiltin::from_str("bls12_381_fp_to_g1").unwrap(), + }; - let input = hex!(" + let input = hex!(" 0000000000000000000000000000000017f66b472b36717ee0902d685c808bb5f190bbcb2c51d067f1cbec64669f10199a5868d7181dcec0498fcc71f5acaf79 "); - let expected = hex!(" + let expected = hex!(" 00000000000000000000000000000000188dc9e5ddf48977f33aeb6e505518269bf67fb624fa86b79741d842e75a6fa1be0911c2caa9e55571b6e55a3c0c0b9e 00000000000000000000000000000000193e8b7c7e78daf104a59d7b39401a65355fa874bd34e91688580941e99a863367efc68fe871e38e07423090e93919c9 "); - let mut output = [0u8; 128]; + let mut output = [0u8; 128]; - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } - #[test] - fn bls12_381_fp2_to_g2() { - let f = Builtin { - pricer: btreemap![0 => Pricing::Bls12Pairing(Bls12PairingPricer{price: Bls12PairingPrice{base: 1, pair: 1}})], - native: EthereumBuiltin::from_str("bls12_381_fp2_to_g2").unwrap(), - }; + #[test] + fn bls12_381_fp2_to_g2() { + let f = Builtin { + pricer: btreemap![0 => Pricing::Linear(Linear { base: 23_800, word: 0 })], + native: EthereumBuiltin::from_str("bls12_381_fp2_to_g2").unwrap(), + }; - let input = hex!(" + let input = hex!(" 000000000000000000000000000000000f470603a402bc134db1b389fd187460f9eb2dd001a2e99f730af386508c62f0e911d831a2562da84bce11d39f2ff13f 000000000000000000000000000000000d8c45f4ab20642d0cba9764126e0818b7d731a6ba29ed234d9d6309a5e8ddfbd85193f1fa8b7cfeed3d31b23b904ee9 "); - let expected = hex!(" + let expected = hex!(" 0000000000000000000000000000000012e74d5a0c005a86ca148e9eff8e34a00bfa8b6e6aadf633d65cd09bb29917e0ceb0d5c9d9650c162d7fe4aa27452685 0000000000000000000000000000000005f09101a2088712619f9c096403b66855a12f9016c55aef6047372fba933f02d9d59db1a86df7be57978021e2457821 00000000000000000000000000000000136975b37fe400d1d217a2b496c1552b39be4e9e71dd7ad482f5f0836d271d02959fdb698dda3d0530587fb86e0db1dd 0000000000000000000000000000000000bad0aabd9309e92e2dd752f4dd73be07c0de2c5ddd57916b9ffa065d7440d03d44e7c042075cda694414a9fb639bb7 "); - let mut output = [0u8; 256]; - - f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) - .expect("Builtin should not fail"); - assert_eq!(&output[..], &expected[..]); - } - - #[test] - fn bls12_381_g1_mul_init_from_spec() { - use ethjson::spec::builtin::{Bls12G1Multiexp, Pricing}; - - let b = Builtin::try_from(JsonBuiltin { - name: "bls12_381_g1_mul".to_owned(), - pricing: btreemap![ - 10000000 => PricingAt { - info: None, - price: Pricing::Bls12PricerG1MSM), - } - ], - }) - .unwrap(); - - match b.native { - EthereumBuiltin::Bls12G1MultiExp(..) => {} - _ => { - panic!("invalid precompile type"); - } - } - } - - #[test] - fn bls12_381_g2_mul_init_from_spec() { - use ethjson::spec::builtin::{Bls12G2Multiexp, Pricing}; - - let b = Builtin::try_from(JsonBuiltin { - name: "bls12_381_g2_mul".to_owned(), - pricing: btreemap![ - 10000000 => PricingAt { - info: None, - price: Pricing::Bls12PricerG2MSM), - } - ], - }) - .unwrap(); - - match b.native { - EthereumBuiltin::Bls12G2MultiExp(..) => {} - _ => { - panic!("invalid precompile type"); - } - } - } - - */ + let mut output = [0u8; 256]; + + f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])) + .expect("Builtin should not fail"); + assert_eq!(&output[..], &expected[..]); + } } From abdefa5e91458d6398d32eeec7cac85f224090be Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Fri, 7 Feb 2025 12:45:07 +0100 Subject: [PATCH 14/14] Feat: Add state tests dump for jsottests (#78) * Added for jsottests - state tests dump * chore: code review suggestions to feat/state-tests-dump (#79) * Small refactoring * Added CI clippy for evm-jsontests * Modified prefix for dump file name --------- Co-authored-by: Oleksandr Anyshchenko --- .github/workflows/rust.yml | 2 + evm-tests/jsontests/Cargo.toml | 2 +- evm-tests/jsontests/src/state.rs | 470 +++++++++++++++++++------------ 3 files changed, 296 insertions(+), 178 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 92f22e8b..bd40e327 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,6 +25,8 @@ jobs: run: cargo clippy --no-default-features -- -D clippy::all -D clippy::nursery - name: Clippy with features run: cargo clippy --features tracing,create-fixed -- -D clippy::all -D clippy::nursery + - name: Clippy with features for evm-jsontests + run: cargo clippy -p evm-jsontests --features dump-state -- -D clippy::all -D clippy::nursery build: runs-on: ubuntu-latest diff --git a/evm-tests/jsontests/Cargo.toml b/evm-tests/jsontests/Cargo.toml index 6a1d7237..c1cf1778 100644 --- a/evm-tests/jsontests/Cargo.toml +++ b/evm-tests/jsontests/Cargo.toml @@ -22,9 +22,9 @@ ethcore-builtin = { path = "../ethcore-builtin" } rlp = "0.6" sha3 = "0.10" parity-bytes = "0.1" -env_logger = "0.11" hex-literal = "0.4" [features] enable-slow-tests = [] print-debug = ["evm/print-debug"] +dump-state = ["evm/with-serde"] diff --git a/evm-tests/jsontests/src/state.rs b/evm-tests/jsontests/src/state.rs index 3bb7e15d..62df7ae5 100644 --- a/evm-tests/jsontests/src/state.rs +++ b/evm-tests/jsontests/src/state.rs @@ -28,6 +28,101 @@ pub struct VerboseOutput { pub print_state: bool, } +#[derive(Default, Debug, Clone)] +#[cfg_attr(feature = "dump-state", derive(serde::Serialize, serde::Deserialize))] +pub struct StateTestsDump { + pub state: BTreeMap, + pub caller: H160, + pub gas_price: U256, + pub effective_gas_price: U256, + pub caller_secret_key: H256, + pub used_gas: u64, + pub state_hash: H256, + pub result_state: BTreeMap, + pub to: H160, + pub value: U256, + pub data: Vec, + pub gas_limit: u64, + pub access_list: Vec<(H160, Vec)>, +} + +trait StateTestsDumper { + fn set_state(&mut self, _state: &BTreeMap) {} + fn set_used_gas(&mut self, _used_gas: u64) {} + fn set_vicinity(&mut self, _vicinity: &MemoryVicinity) {} + fn set_tx_data( + &mut self, + _to: H160, + _value: U256, + _data: Vec, + _gas_limit: u64, + _access_list: Vec<(H160, Vec)>, + ) { + } + fn set_caller_secret_key(&mut self, _caller_secret_key: H256) {} + fn set_state_hash(&mut self, _state_hash: H256) {} + fn set_result_state(&mut self, _state: &BTreeMap) {} + fn dump_to_file(&self, _spec: &ForkSpec) {} +} + +#[cfg(not(feature = "dump-state"))] +impl StateTestsDumper for StateTestsDump {} + +#[cfg(feature = "dump-state")] +impl StateTestsDumper for StateTestsDump { + fn set_state(&mut self, state: &BTreeMap) { + self.state = state.clone(); + } + + fn set_used_gas(&mut self, used_gas: u64) { + self.used_gas = used_gas; + } + + fn set_vicinity(&mut self, vicinity: &MemoryVicinity) { + self.caller = vicinity.origin; + self.gas_price = vicinity.gas_price; + self.effective_gas_price = vicinity.effective_gas_price; + } + + fn set_tx_data( + &mut self, + to: H160, + value: U256, + data: Vec, + gas_limit: u64, + access_list: Vec<(H160, Vec)>, + ) { + self.to = to; + self.value = value; + self.data = data; + self.gas_limit = gas_limit; + self.access_list = access_list; + } + + fn set_caller_secret_key(&mut self, caller_secret_key: H256) { + self.caller_secret_key = caller_secret_key; + } + + fn set_state_hash(&mut self, state_hash: H256) { + self.state_hash = state_hash; + } + + fn set_result_state(&mut self, state: &BTreeMap) { + self.result_state = state.clone(); + } + + fn dump_to_file(&self, spec: &ForkSpec) { + use std::time::{SystemTime, UNIX_EPOCH}; + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_micros(); + let path = format!("{spec:?}_BLS12-382_{now}.json"); + let json = serde_json::to_string(&self).unwrap(); + std::fs::write(path, json).unwrap(); + } +} + #[derive(Clone, Debug)] pub struct FailedTestDetails { pub name: String, @@ -70,6 +165,10 @@ impl Test { crate::utils::unwrap_to_state(&self.0.pre_state) } + pub fn unwrap_caller_secret_key(&self) -> H256 { + self.0.transaction.secret.unwrap().into() + } + pub fn unwrap_caller(&self) -> H160 { let hash: H256 = self.0.transaction.secret.unwrap().into(); let mut secret_key = [0; 32]; @@ -682,25 +781,25 @@ fn check_create_exit_reason( let check_result = exception == "TR_InitCodeLimitExceeded" || exception == "TransactionException.INITCODE_SIZE_EXCEEDED"; assert!( - check_result, - "unexpected exception {exception:?} for CreateContractLimit error for test: {name}" - ); + check_result, + "unexpected exception {exception:?} for CreateContractLimit error for test: {name}" + ); return true; } ExitError::MaxNonce => { let check_result = exception == "TR_NonceHasMaxValue" || exception == "TransactionException.NONCE_IS_MAX"; assert!(check_result, - "unexpected exception {exception:?} for MaxNonce error for test: {name}" - ); + "unexpected exception {exception:?} for MaxNonce error for test: {name}" + ); return true; } ExitError::OutOfGas => { let check_result = exception == "TransactionException.INTRINSIC_GAS_TOO_LOW"; assert!(check_result, - "unexpected exception {exception:?} for OutOfGas error for test: {name}" - ); + "unexpected exception {exception:?} for OutOfGas error for test: {name}" + ); return true; } _ => { @@ -761,9 +860,9 @@ fn assert_vicinity_validation( ); let is_checked = expected == "tipTooHigh" || expected == "TR_TipGtFeeCap"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } InvalidTxReason::GasPriceLessThenBlockBaseFee => { @@ -774,9 +873,9 @@ fn assert_vicinity_validation( let is_checked = expected == "lowFeeCap" || expected == "TR_FeeCapLessThanBlocks"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } _ => panic!("Unexpected validation reason: {reason:?} [{spec:?}] {name}"), @@ -791,9 +890,9 @@ fn assert_vicinity_validation( ); let is_checked = expected == "TR_TipGtFeeCap"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } InvalidTxReason::GasPriceLessThenBlockBaseFee => { @@ -803,9 +902,9 @@ fn assert_vicinity_validation( ); let is_checked = expected == "TR_FeeCapLessThanBlocks"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } _ => panic!("Unexpected validation reason: {reason:?} [{spec:?}] {name}"), @@ -820,9 +919,9 @@ fn assert_vicinity_validation( ); let is_checked = expected == "TR_TipGtFeeCap"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } InvalidTxReason::GasPriceLessThenBlockBaseFee => { @@ -832,9 +931,9 @@ fn assert_vicinity_validation( ); let is_checked = expected == "TR_FeeCapLessThanBlocks"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } _ => panic!("Unexpected validation reason: {reason:?} [{spec:?}] {name}"), @@ -850,9 +949,9 @@ fn assert_vicinity_validation( let is_checked = expected == "TR_TipGtFeeCap" || expected == "TransactionException.PRIORITY_GREATER_THAN_MAX_FEE_PER_GAS"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } InvalidTxReason::GasPriceLessThenBlockBaseFee => { @@ -864,9 +963,9 @@ fn assert_vicinity_validation( let is_checked = expected == "TR_FeeCapLessThanBlocks" || expected == "TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } _ => panic!("Unexpected validation reason: {reason:?} [{spec:?}] {name}"), @@ -881,9 +980,9 @@ fn assert_vicinity_validation( let is_checked = expected == "TR_FeeCapLessThanBlocks" || expected == "TransactionException.INSUFFICIENT_MAX_FEE_PER_GAS"; assert!( - is_checked, - "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", - ); + is_checked, + "unexpected error message {expected:?} for: {reason:?} [{spec:?}] {name}:{i}", + ); } } _ => panic!("Unexpected validation reason: {reason:?} [{spec:?}] {name}"), @@ -900,143 +999,143 @@ fn check_validate_exit_reason( spec: &ForkSpec, ) -> bool { expect_exception.as_deref().map_or_else( - || { - panic!("unexpected validation error reason: {reason:?} {name}"); - }, - |exception| { - match reason { - InvalidTxReason::OutOfFund => { - let check_result = exception - == "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS" - || exception == "TR_NoFunds" - || exception == "TR_NoFundsX" - || exception == "TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS" - || exception=="TransactionException.INSUFFICIENT_ACCOUNT_FUNDS|TransactionException.GASLIMIT_PRICE_PRODUCT_OVERFLOW"; - assert!( - check_result, - "unexpected exception {exception:?} for OutOfFund for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::GasLimitReached => { - let check_result = exception == "TR_GasLimitReached" - || exception == "TransactionException.GAS_ALLOWANCE_EXCEEDED"; - assert!( - check_result, - "unexpected exception {exception:?} for GasLimitReached for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::IntrinsicGas => { - let check_result = exception == "TR_NoFundsOrGas" - || exception == "TR_IntrinsicGas" - || exception == "TransactionException.INTRINSIC_GAS_TOO_LOW" - || exception == "IntrinsicGas" - || exception == "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS|TransactionException.INTRINSIC_GAS_TOO_LOW"; - assert!( - check_result, - "unexpected exception {exception:?} for IntrinsicGas for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::BlobVersionNotSupported => { - let check_result = exception - == "TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH" - || exception == "TR_BLOBVERSION_INVALID"; - assert!( - check_result, - "unexpected exception {exception:?} for BlobVersionNotSupported for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::BlobCreateTransaction => { - let check_result = exception == "TR_BLOBCREATE" - || exception == "TransactionException.TYPE_3_TX_CONTRACT_CREATION"; - assert!( - check_result, - "unexpected exception {exception:?} for BlobCreateTransaction for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::BlobGasPriceGreaterThanMax => { - let check_result = - exception == "TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS"; - assert!( - check_result, - "unexpected exception {exception:?} for BlobGasPriceGreaterThanMax for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::TooManyBlobs => { - let check_result = exception == "TR_BLOBLIST_OVERSIZE" - || exception == "TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED"; - assert!( - check_result, - "unexpected exception {exception:?} for TooManyBlobs for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::EmptyBlobs => { - let check_result = exception == "TransactionException.TYPE_3_TX_ZERO_BLOBS" - || exception == "TR_EMPTYBLOB"; - assert!( - check_result, - "unexpected exception {exception:?} for EmptyBlobs for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::MaxFeePerBlobGasNotSupported => { - let check_result = - exception == "TransactionException.TYPE_3_TX_PRE_FORK|TransactionException.TYPE_3_TX_ZERO_BLOBS"; - assert!( - check_result, - "unexpected exception {exception:?} for MaxFeePerBlobGasNotSupported for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::BlobVersionedHashesNotSupported => { - let check_result = exception == "TransactionException.TYPE_3_TX_PRE_FORK" - || exception == "TR_TypeNotSupportedBlob"; - assert!( - check_result, - "unexpected exception {exception:?} for BlobVersionedHashesNotSupported for test: [{spec:?}] {name}" - ); - }, - InvalidTxReason::InvalidAuthorizationChain => { - let check_result = exception == "TransactionException.TYPE_4_INVALID_AUTHORIZATION_FORMAT"; - assert!( - check_result, - "unexpected exception {exception:?} for InvalidAuthorizationChain for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::InvalidAuthorizationSignature => { - let check_result = exception == "TransactionException.TYPE_4_INVALID_AUTHORITY_SIGNATURE"; - assert!( - check_result, - "unexpected exception {exception:?} for InvalidAuthorizationSignature for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::AuthorizationListNotExist => { - let check_result = exception == "TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST" || exception == "TransactionException.TYPE_4_TX_CONTRACT_CREATION"; - assert!( - check_result, - "unexpected exception {exception:?} for AuthorizationListNotExist for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::CreateTransaction => { - let check_result = exception == "TransactionException.TYPE_4_TX_CONTRACT_CREATION"; - assert!( - check_result, - "unexpected exception {exception:?} for CreateTransaction for test: [{spec:?}] {name}" - ); - } - InvalidTxReason::GasFloorMoreThanGasLimit => { - let check_result = exception == "TransactionException.INTRINSIC_GAS_TOO_LOW"; - assert!( - check_result, - "unexpected exception {exception:?} for GasFloorMoreThanGasLimit for test: [{spec:?}] {name}" - ); - } - _ => { - panic!( - "unexpected exception {exception:?} for reason {reason:?} for test: [{spec:?}] {name}" - ); - } - } - true - }, - ) + || { + panic!("unexpected validation error reason: {reason:?} {name}"); + }, + |exception| { + match reason { + InvalidTxReason::OutOfFund => { + let check_result = exception + == "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS" + || exception == "TR_NoFunds" + || exception == "TR_NoFundsX" + || exception == "TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS" + || exception == "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS|TransactionException.GASLIMIT_PRICE_PRODUCT_OVERFLOW"; + assert!( + check_result, + "unexpected exception {exception:?} for OutOfFund for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::GasLimitReached => { + let check_result = exception == "TR_GasLimitReached" + || exception == "TransactionException.GAS_ALLOWANCE_EXCEEDED"; + assert!( + check_result, + "unexpected exception {exception:?} for GasLimitReached for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::IntrinsicGas => { + let check_result = exception == "TR_NoFundsOrGas" + || exception == "TR_IntrinsicGas" + || exception == "TransactionException.INTRINSIC_GAS_TOO_LOW" + || exception == "IntrinsicGas" + || exception == "TransactionException.INSUFFICIENT_ACCOUNT_FUNDS|TransactionException.INTRINSIC_GAS_TOO_LOW"; + assert!( + check_result, + "unexpected exception {exception:?} for IntrinsicGas for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::BlobVersionNotSupported => { + let check_result = exception + == "TransactionException.TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH" + || exception == "TR_BLOBVERSION_INVALID"; + assert!( + check_result, + "unexpected exception {exception:?} for BlobVersionNotSupported for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::BlobCreateTransaction => { + let check_result = exception == "TR_BLOBCREATE" + || exception == "TransactionException.TYPE_3_TX_CONTRACT_CREATION"; + assert!( + check_result, + "unexpected exception {exception:?} for BlobCreateTransaction for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::BlobGasPriceGreaterThanMax => { + let check_result = + exception == "TransactionException.INSUFFICIENT_MAX_FEE_PER_BLOB_GAS"; + assert!( + check_result, + "unexpected exception {exception:?} for BlobGasPriceGreaterThanMax for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::TooManyBlobs => { + let check_result = exception == "TR_BLOBLIST_OVERSIZE" + || exception == "TransactionException.TYPE_3_TX_BLOB_COUNT_EXCEEDED"; + assert!( + check_result, + "unexpected exception {exception:?} for TooManyBlobs for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::EmptyBlobs => { + let check_result = exception == "TransactionException.TYPE_3_TX_ZERO_BLOBS" + || exception == "TR_EMPTYBLOB"; + assert!( + check_result, + "unexpected exception {exception:?} for EmptyBlobs for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::MaxFeePerBlobGasNotSupported => { + let check_result = + exception == "TransactionException.TYPE_3_TX_PRE_FORK|TransactionException.TYPE_3_TX_ZERO_BLOBS"; + assert!( + check_result, + "unexpected exception {exception:?} for MaxFeePerBlobGasNotSupported for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::BlobVersionedHashesNotSupported => { + let check_result = exception == "TransactionException.TYPE_3_TX_PRE_FORK" + || exception == "TR_TypeNotSupportedBlob"; + assert!( + check_result, + "unexpected exception {exception:?} for BlobVersionedHashesNotSupported for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::InvalidAuthorizationChain => { + let check_result = exception == "TransactionException.TYPE_4_INVALID_AUTHORIZATION_FORMAT"; + assert!( + check_result, + "unexpected exception {exception:?} for InvalidAuthorizationChain for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::InvalidAuthorizationSignature => { + let check_result = exception == "TransactionException.TYPE_4_INVALID_AUTHORITY_SIGNATURE"; + assert!( + check_result, + "unexpected exception {exception:?} for InvalidAuthorizationSignature for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::AuthorizationListNotExist => { + let check_result = exception == "TransactionException.TYPE_4_EMPTY_AUTHORIZATION_LIST" || exception == "TransactionException.TYPE_4_TX_CONTRACT_CREATION"; + assert!( + check_result, + "unexpected exception {exception:?} for AuthorizationListNotExist for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::CreateTransaction => { + let check_result = exception == "TransactionException.TYPE_4_TX_CONTRACT_CREATION"; + assert!( + check_result, + "unexpected exception {exception:?} for CreateTransaction for test: [{spec:?}] {name}" + ); + } + InvalidTxReason::GasFloorMoreThanGasLimit => { + let check_result = exception == "TransactionException.INTRINSIC_GAS_TOO_LOW"; + assert!( + check_result, + "unexpected exception {exception:?} for GasFloorMoreThanGasLimit for test: [{spec:?}] {name}" + ); + } + _ => { + panic!( + "unexpected exception {exception:?} for reason {reason:?} for test: [{spec:?}] {name}" + ); + } + } + true + }, + ) } #[allow(clippy::cognitive_complexity)] @@ -1124,7 +1223,6 @@ fn test_run( spec: spec.clone(), state: original_state, }); - if verbose_output.verbose_failed { println!(" [{spec:?}] {name}: {tx_err:?} ... validation failed\t<----"); } @@ -1203,6 +1301,12 @@ fn test_run( vicinity.effective_gas_price * gas_limit }; + // Dump state transaction data + let mut state_tests_dump = StateTestsDump::default(); + state_tests_dump.set_state(&original_state); + state_tests_dump.set_caller_secret_key(test.unwrap_caller_secret_key()); + state_tests_dump.set_vicinity(&vicinity); + let metadata = StackSubstateMetadata::new(transaction.gas_limit.into(), &gasometer_config); let executor_state = MemoryStackState::new(metadata, &backend); @@ -1211,7 +1315,7 @@ fn test_run( StackExecutor::new_with_precompiles(executor_state, &gasometer_config, &precompile); executor.state_mut().withdraw(caller, total_fee).unwrap(); - let access_list = transaction + let access_list: Vec<(H160, Vec)> = transaction .access_list .into_iter() .map(|(address, keys)| (address.0, keys.into_iter().map(|k| k.0).collect())) @@ -1224,6 +1328,14 @@ fn test_run( ethjson::maybe::MaybeEmpty::Some(to) => { let value = transaction.value.into(); + state_tests_dump.set_tx_data( + to.0, + value, + data.clone(), + gas_limit, + access_list.clone(), + ); + // Exit reason for Call do not analyzed as it mostly do not expect exceptions let _reason = executor.transact_call( caller, @@ -1263,11 +1375,9 @@ fn test_run( } } + let used_gas = executor.used_gas(); if verbose_output.print_state { - println!( - "gas_limit: {gas_limit}\nused_gas: {:?}", - executor.used_gas() - ); + println!("gas_limit: {gas_limit}\nused_gas: {used_gas}"); } let actual_fee = executor.fee(vicinity.effective_gas_price); @@ -1317,6 +1427,7 @@ fn test_run( let (is_valid_hash, actual_hash) = crate::utils::check_valid_hash(&state.hash.0, backend.state()); + if !is_valid_hash { let failed_res = FailedTestDetails { expected_hash: state.hash.0, @@ -1356,6 +1467,11 @@ fn test_run( } else if verbose_output.very_verbose && !verbose_output.verbose_failed { println!(" [{spec:?}] {name}:{i} ... passed"); } + + state_tests_dump.set_used_gas(used_gas); + state_tests_dump.set_state_hash(actual_hash); + state_tests_dump.set_result_state(backend.state()); + state_tests_dump.dump_to_file(spec); } } tests_result