Skip to content

Commit

Permalink
feat: implement g1_mul (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
fgimenez authored Mar 26, 2024
1 parent 569fb93 commit 2fa48b8
Showing 1 changed file with 108 additions and 4 deletions.
112 changes: 108 additions & 4 deletions crates/precompile/src/bls12_381.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ use revm_primitives::{Bytes, PrecompileError, PrecompileResult, B256};
use std::ops::Add;

const G1ADD_BASE: u64 = 500;
const G1MUL_BASE: u64 = 12000;
const G1ADD_INPUT_LENGTH: usize = 256;
const G1MUL_INPUT_LENGTH: usize = 160;
const INPUT_ITEM_LENGTH: usize = 128;
const OUTPUT_LENGTH: usize = 128;
const FP_LENGTH: usize = 48;
const PADDED_INPUT_LENGTH: usize = 64;
const PADDING_LENGTH: usize = 16;
const FP_CONCAT_LENGTH: usize = 96;
const SCALAR_LENGTH: usize = 32;

/// bls12381 precompiles
pub fn precompiles() -> impl Iterator<Item = PrecompileWithAddress> {
Expand Down Expand Up @@ -78,6 +81,35 @@ fn add_g1_affine_projective(p0: G1Affine, p1_projective: G1Projective) -> G1Proj
p0.add(p1_projective)
}

// Multiplies a G1 point in projective format by scalar.
fn mul_g1_projective_scalar(p0: G1Projective, scalar0: [u8; SCALAR_LENGTH]) -> G1Projective {
let mut q = G1Projective::default();
let mut n = p0;

for byte in scalar0.into_iter().rev() {
for bit_index in 0..8 {
let bit = (byte >> bit_index) & 1;
if bit == 0x01 {
q = q.add(n);
}
n = n.double();
}
}
q
}

// Extracts an Scalar from a 32 byte slice representation.
fn extract_scalar_input(input: &[u8]) -> Result<[u8; SCALAR_LENGTH], PrecompileError> {
if input.len() != SCALAR_LENGTH {
return Err(PrecompileError::Other(format!(
"Input should be {SCALAR_LENGTH} bits, was {}",
input.len()
)));
}

Ok(input.try_into().unwrap())
}

// Extracts a G1 point in Affine format from a 128 byte slice representation.
fn extract_g1_input(input: &[u8]) -> Result<G1Affine, PrecompileError> {
if input.len() != INPUT_ITEM_LENGTH {
Expand Down Expand Up @@ -156,13 +188,39 @@ fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult {
const BLS12_G1MUL: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(BLS12_G1MUL_ADDRESS), Precompile::Standard(g1_mul));

fn g1_mul(_input: &Bytes, gas_limit: u64) -> PrecompileResult {
const G1MUL_BASE: u64 = 12000;
// G1 multiplication call expects `160` bytes as an input that is interpreted as
// byte concatenation of encoding of G1 point (`128` bytes) and encoding of a
// scalar value (`32` bytes).
// Output is an encoding of multiplication operation result - single G1 point
// (`128` bytes).
fn g1_mul(input: &Bytes, gas_limit: u64) -> PrecompileResult {
if G1MUL_BASE > gas_limit {
return Err(PrecompileError::OutOfGas);
}
let result = 1;
Ok((G1MUL_BASE, B256::with_last_byte(result as u8).into()))
if input.len() != G1MUL_INPUT_LENGTH {
return Err(PrecompileError::Other(format!(
"G1MUL Input should be {G1MUL_INPUT_LENGTH} bits, was {}",
input.len()
)));
}

let p0 = extract_g1_input(&input[..INPUT_ITEM_LENGTH])?;
let p0_projective: G1Projective = p0.into();

let input_scalar0 = extract_scalar_input(&input[INPUT_ITEM_LENGTH..])?;

let out = mul_g1_projective_scalar(p0_projective, input_scalar0);
let out: G1Affine = out.into();

// take into account point of infinity encoding
// https://eips.ethereum.org/EIPS/eip-2537#point-of-infinity-encoding
let out_bytes = if out.is_identity().into() {
[0u8; OUTPUT_LENGTH]
} else {
set_padding(out.to_uncompressed())
};

Ok((G1MUL_BASE, out_bytes.into()))
}

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MULTIEXP precompile.
Expand Down Expand Up @@ -317,4 +375,50 @@ mod test {
assert_eq!(expected_output, actual_output);
}
}

#[rstest]
// test vectors from https://github.com/ethereum/go-ethereum/blob/master/core/vm/testdata/precompiles/blsG1Mul.json and https://github.com/ethereum/go-ethereum/blob/master/core/vm/testdata/precompiles/fail-blsG1Mul.json
#[case::zero_times_g1_equals_inf("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false, 12000)]
#[case::x_times_inf_equals_inf("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false, 12000)]
#[case::one_times_g1_equals_g1("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", false, 12000)]
#[case::seventeen_times_g1("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000011", "000000000000000000000000000000001098f178f84fc753a76bb63709e9be91eec3ff5f7f3a5f4836f34fe8a1a6d6c5578d8fd820573cef3a01e2bfef3eaf3a000000000000000000000000000000000ea923110b733b531006075f796cc9368f2477fe26020f465468efbb380ce1f8eebaf5c770f31d320f9bd378dc758436", false, 12000)]
#[case::matter_g1_mul_zero("0000000000000000000000000000000012196c5a43d69224d8713389285f26b98f86ee910ab3dd668e413738282003cc5b7357af9a7af54bb713d62255e80f560000000000000000000000000000000006ba8102bfbeea4416b710c73e8cce3032c31c6269c44906f8ac4f7874ce99fb17559992486528963884ce429a992feeb3c940fe79b6966489b527955de7599194a9ac69a6ff58b8d99e7b1084f0464e", "000000000000000000000000000000000f1f230329be03ac700ba718bc43c8ee59a4b2d1e20c7de95b22df14e7867eae4658ed2f2dfed4f775d4dcedb4235cf00000000000000000000000000000000012924104fdb82fb074cfc868bdd22012694b5bae2c0141851a5d6a97d8bc6f22ecb2f6ddec18cba6483f2e73faa5b942", false, 12000)]
#[case::matter_g1_mul_one("00000000000000000000000000000000117dbe419018f67844f6a5e1b78a1e597283ad7b8ee7ac5e58846f5a5fd68d0da99ce235a91db3ec1cf340fe6b7afcdb0000000000000000000000000000000013316f23de032d25e912ae8dc9b54c8dba1be7cecdbb9d2228d7e8f652011d46be79089dd0a6080a73c82256ce5e4ed24d0e25bf3f6fc9f4da25d21fdc71773f1947b7a8a775b8177f7eca990b05b71d", "00000000000000000000000000000000195592b927f3f1783a0c7b5117702cb09fa4f95bb2d35aa2a70fe89ba84aa4f385bdb2bfd4e1aaffbb0bfa002ac0e51b000000000000000000000000000000000607f070f4ae567633d019a63d0411a07d767bd7b6fe258c3ba1e720279e94c31f23166b806eabdb830bb632b003ca8b", false, 12000)]
#[case::matter_g1_mul_two("0000000000000000000000000000000008ab7b556c672db7883ec47efa6d98bb08cec7902ebb421aac1c31506b177ac444ffa2d9b400a6f1cbdc6240c607ee110000000000000000000000000000000016b7fa9adf4addc2192271ce7ad3c8d8f902d061c43b7d2e8e26922009b777855bffabe7ed1a09155819eabfa87f276f973f40c12c92b703d7b7848ef8b4466d40823aad3943a312b57432b91ff68be1", "0000000000000000000000000000000014f9bc24d65e3a2d046dbae935781596fb277359ba785808fd9ff7fd135ba8c1ddc27d97a16cc844427afbf4f8fc75a60000000000000000000000000000000017e3a485f84e2f2bdcf3255fe939945abe60dca5e0ae55eae9675dcc8d73e06d00b440a27ab4dc21c37f0bd492d70cf4", false, 12000)]
#[case::matter_g1_mul_three("0000000000000000000000000000000015ff9a232d9b5a8020a85d5fe08a1dcfb73ece434258fe0e2fddf10ddef0906c42dcb5f5d62fc97f934ba900f17beb330000000000000000000000000000000009cfe4ee2241d9413c616462d7bac035a6766aeaab69c81e094d75b840df45d7e0dfac0265608b93efefb9a8728b98e44c51f97bcdda93904ae26991b471e9ea942e2b5b8ed26055da11c58bc7b5002a", "000000000000000000000000000000000827517654873d535010e589eaf22f646cf7626144ca04738286de1f1d345342d5ae0eab9cd37ced9a3db90e569301720000000000000000000000000000000002a474c2443d71b0231d2b2b874a6aeac0452dd75da88e6f27949edafc7d094cb1577a79f4e643db42edcaecc17d66da", false, 12000)]
#[case::matter_g1_mul_four("0000000000000000000000000000000017a17b82e3bfadf3250210d8ef572c02c3610d65ab4d7366e0b748768a28ee6a1b51f77ed686a64f087f36f641e7dca900000000000000000000000000000000077ea73d233ccea51dc4d5acecf6d9332bf17ae51598f4b394a5f62fb387e9c9aa1d6823b64a074f5873422ca57545d38964d5867927bc3e35a0b4c457482373969bff5edff8a781d65573e07fd87b89", "000000000000000000000000000000000d7e5794c88c549970383454d98f9b7cebb7fdf8545256f1a5e42a61aa1d61193f02075dc6314b650da14f3776da6ead0000000000000000000000000000000002054faff236d38d2307aa6cbbc696d50f5b3ffead1be2df97a05ebbcbc9e02eaf153f311a1e141eb95d411c0ec6e981", false, 12000)]
#[case::matter_g1_mul_five("000000000000000000000000000000000c1243478f4fbdc21ea9b241655947a28accd058d0cdb4f9f0576d32f09dddaf0850464550ff07cab5927b3e4c863ce90000000000000000000000000000000015fb54db10ffac0b6cd374eb7168a8cb3df0a7d5f872d8e98c1f623deb66df5dd08ff4c3658f2905ec8bd02598bd4f90787c38b944eadbd03fd3187f450571740f6cd00e5b2e560165846eb800e5c944", "000000000000000000000000000000000ff16ff83b45eae09d858f8fe443c3f0e0b7418a87ac27bb00f7eea343d20a4a7f5c0fcc56da9b792fe12bd38d0d43c600000000000000000000000000000000042a815a4a5dca00bd1791889491c882a21f0fe0a53809d83740407455cf9c980c5547961f9ebe61871a4896dace7fbd", false, 12000)]
#[case::matter_g1_mul_19("0000000000000000000000000000000010fcfe8af8403a52400bf79e1bd0058f66b9cab583afe554aa1d82a3e794fffad5f0e19d385263b2dd9ef69d1154f10a000000000000000000000000000000000aba6a0b58b49f7c6c2802afd2a5ed1320bf062c7b93135f3c0ed7a1d7b1ee27b2b986cde732a60fa585ca6ab7cc154bd411519f2a33b07f65e7d721950e0f0d5161c71a402810e46817627a17c56c0f", "000000000000000000000000000000001608c3bfb131eae485545b7d19b8f42de18dcea6a0db3279eac2b7c008fbead54046bf13dd63835abe9c63110e12526c000000000000000000000000000000000abb41b2f17cfcc2292c5bf559b38af3b25db40121c6a5627997f65765eee1743c204f1161abe3f71ac1fe4de6aec1d7", false, 12000)]
#[case::matter_g1_mul_28("0000000000000000000000000000000010cde0dbf4e18009c94ba648477624bbfb3732481d21663dd13cea914d6c54ec060557010ebe333d5e4b266e1563c631000000000000000000000000000000000fb24d3d4063fd054cd5b7288498f107114ff323226aca58d3336444fc79c010db15094ceda6eb99770c168d459f0da05061073223f066e35242772385c67aaefb3f7ea7df244d73369db1ea0b208792", "00000000000000000000000000000000028a89c904f63eb8e68096bd2001458a4b9b32556c93fab5e52ab26ed73d62f0489d6bf1906a62c8148d50d30222a65f0000000000000000000000000000000007e54f21e2ac6d5287289ed9e2a15d457b5dac22ef36c19cb28a6cf9a0d11c981bf6549ddaf7ddc0a59b3d3a4698d975", false, 12000)]
#[case::matter_g1_mul_37("00000000000000000000000000000000024ca57c2dc2a7deec3082f2f2110b6788c57a8cdc43515044d275fe7d6f20540055bde823b7b091134fb811d23468ce0000000000000000000000000000000009cd91a281b96a881b20946fda164a987243c052378fcd8fee3926b75576dfa1d29a0aaca4b653da4e61da82577218082c01b7795c2d16b5bbbb1e107be36cc91b25130888956b0cdd344de9b4659447", "000000000000000000000000000000001344d2c2bc5ef45dc69597e948ed6021d84f7bf2c36119869a3f84288f3bdd6fc3a0de2b9e2564a930c2207c1ee36a0e000000000000000000000000000000000dc4d15ae09642ffa17d77510fb1ad4bf9e06084e9d352f4e234ea35f33458df4f23a209e29da42c41fb9a3cec3e8242", false, 12000)]
#[case::matter_g1_mul_46("000000000000000000000000000000000178e6828261ee6855b38234ed15c27551bb1648ac6ec9a9e70744643cd1f134b2309dd0c34b1e59ddfe3f831ab814c90000000000000000000000000000000002ec930fb58c898ede931384c5a5f9edd2f5c70b8c3794edb83a12f23be5400949f95e81c96c666c1a72dffb50b81158f7bfd990cc4dac62a0d730f56b4eb1c1ad77ca9cd58b089c23c2f6efa00b7fa4", "000000000000000000000000000000000f990d646495fff77d090f4a69b8af0e1762982b53ef8ae9bb955ad8b894942b85c7726587c9fd956ad58eb9e3ca25630000000000000000000000000000000007b7315e1f93cfba8076cf539aae01fd3bbe1cf92daa168a6fd6a2e7c969d35c51fe7eba04f1e0dd3e2020635f2c4f09", false, 12000)]
#[case::matter_g1_mul_55("0000000000000000000000000000000018724e2b9a2f383329207ee85577805f35d5c5bb9f6903e3c962e57ab7eb9d1639d1e9adbde53499863b299f576325a00000000000000000000000000000000016d2c22eabd4a06a5ae67b890a25fbede7d0e96c625b80329b19be6aa861f44b6e85778130d0bdf69f2abd491ee9751ab96df57a600dc3b5aabff5b1034886d24f6fcf035bcacaaec738deb2cfb8f852", "0000000000000000000000000000000014911a8b41cb65cb7ccb940a472cfa58861f1a506a4f719888eb35d48ed9774ea0a0dc3ba38760253bedb4a1acd0963a00000000000000000000000000000000031388c90440f22cc63a1e9450256e5cfcf2f7448641ac66b43d542c4b77e9c590b957efdb1c6d75846b3faccf033276", false, 12000)]
#[case::matter_g1_mul_64("000000000000000000000000000000001465358836eb5c6e173e425f675aa231f9c62e9b122584078f2ab9af7440a4ce4ac2cd21ce35a0017b01e4913b40f73d00000000000000000000000000000000170e2da3bca3d0a8659e31df4d8a3a73e681c22beb21577bea6bbc3de1cabff8a1db28b51fdd46ba906767b69db2f679830630695c8dabe9aded1b5365bf93770aab7e9ef4140a2bbde2f0a7b109724d", "00000000000000000000000000000000024b59fbec5240fbdf3fb4e565bbec20f26edbc2a1bf7ecaaeb5278ed9fe13d1e360fa298e2d3f9b2880b00aff827f620000000000000000000000000000000013ca56975d9fd667bab347ed67fb96a433d57836ca4069976e12459152e1369154bd095a15980880e21fd02b1d7e3156", false, 12000)]
#[case::matter_g1_mul_73("000000000000000000000000000000000bb6f731b345bb1319b9acab09c186449a51dad8b6526251bc58e958cfd933137067e6f778b019f131cc7b23e08a0706000000000000000000000000000000001979a4f3e444c5950d0e2d71f97e99578b3058a6e414dfca313b898c4e02787e6eed89a2d1b05f31cff4af1e12bbedc3ebf66fce49c6beb12737fe05e3adc0a51ecfa9144ccf6253088dd1a7a483de07", "0000000000000000000000000000000005720fd4bff4da704edb7e317e3d41f1d1f45e3c1f22c1b98ee0b6875af414f6f58793e8ffd5c89bcec2af711973ca1600000000000000000000000000000000051441e34eed472766186a44b2028d86eebadd597cb7e3fa4f935d30aa043f11fb18670b31f0a3b8aa23bc8f05361064", false, 12000)]
#[case::matter_g1_mul_82("00000000000000000000000000000000021203675e0ae188ec782160e21492a6ee39fa97d922c1ef9bbfd79b82b3fad54fab11ba633fb8f02cf92249d85d9d8000000000000000000000000000000000062783335b87300c97b38e03e5b1318d15a499b29a473c187f930bf34bc1214b4d822725678cbde978c7b5ae6d4bad51a79fd15e80b694122dddb01f836460b3eff99e61ea6309d6b395c94fb5a43dff", "00000000000000000000000000000000141464b4326b0353aa99674bbd98853b926aa580c1e03673297bcbe9094eb1d795331d16d883e0583ed0551f064d7a0f0000000000000000000000000000000002dbbfb86c4d313bdbc8ebd266c190e38645016aca22261665dc850b0d7db8b240aacebec8af097724e5291ff43e6f90", false, 12000)]
#[case::matter_g1_mul_91("000000000000000000000000000000001667fdc9b89d12fb0704fdec910cab1b51ac04219ef6e50f996688b2ceb26dca0e9e8594c5b81fca2e8fc2c8d8fa9a4700000000000000000000000000000000193118d1f237c68a8a0961fb220c0fd6a08853908a039dd57f8ed334063e5316bf83e8c3c3f44420734abbd7ddda31a6f6787b565e8d71be6fdb0c97c4659389c800a2047f668b366214adc716f402d5", "0000000000000000000000000000000003e1d921b5e0280f7370d55967e716bdacb7521547e22190e89862dbfcce02dfe7fa7927a70e7bc33448b9321de3d8ae000000000000000000000000000000001163f78de4af8494666c64d47d68a0feb0905c42ddfa024398401202d1fe0d6672bd1bd4222a8d106668ba4617683485", false, 12000)]
#[case::fail_empty_input("", "", true, 12000)]
#[case::fail_short_input("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb00000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000007", "", true, 12000)]
#[case::fail_large_input("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb000000000000000000000000000000000008b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000007", "", true, 12000)]
#[case::fail_violate_top_bytes("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb0000000000000000000000000000000108b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e10000000000000000000000000000000000000000000000000000000000000007", "", true, 12000)]
#[case::fail_invalid_field_element("0000000000000000000000000000000017f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb000000000000000000000000000000001a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaac0000000000000000000000000000000000000000000000000000000000000007", "", true, 12000)]
#[case::fail_point_not_on_curve("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", "", true, 12000)]
fn test_g1_mul(
#[case] input: &str,
#[case] expected_output: &str,
#[case] expected_error: bool,
#[case] expected_gas: u64,
) {
let input = Bytes::from_hex(input).unwrap();
let target_gas: u64 = 30_000_000;
let res = g1_mul(&input, target_gas);
if expected_error {
assert!(res.is_err());
} else {
let (actual_gas, actual_output) = res.unwrap();
assert_eq!(expected_gas, actual_gas);
let expected_output = Bytes::from_hex(expected_output).unwrap();
assert_eq!(expected_output, actual_output);
}
}
}

0 comments on commit 2fa48b8

Please sign in to comment.