diff --git a/Cargo.lock b/Cargo.lock index 54a015535b4..bbf1b52988c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1045,6 +1045,32 @@ dependencies = [ "termcolor", ] +[[package]] +name = "eth_pairings" +version = "0.6.0" +source = "git+https://github.com/matter-labs/eip1962.git?rev=ece6cbabc41948db4200e41f0bfdab7ab94c7af8#ece6cbabc41948db4200e41f0bfdab7ab94c7af8" +dependencies = [ + "byteorder", + "eth_pairings_repr_derive", + "fixed_width_field", + "fixed_width_group_and_loop", + "num-bigint 0.2.6", + "num-traits 0.2.11", + "once_cell", + "static_assertions", +] + +[[package]] +name = "eth_pairings_repr_derive" +version = "0.2.0" +source = "git+https://github.com/matter-labs/eip1962.git?rev=ece6cbabc41948db4200e41f0bfdab7ab94c7af8#ece6cbabc41948db4200e41f0bfdab7ab94c7af8" +dependencies = [ + "byteorder", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.17", +] + [[package]] name = "ethabi" version = "12.0.0" @@ -1257,6 +1283,7 @@ dependencies = [ "byteorder", "common-types", "eip-152", + "eth_pairings", "ethereum-types", "ethjson", "hex-literal", @@ -1869,6 +1896,22 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed_width_field" +version = "0.1.0" +source = "git+https://github.com/matter-labs/eip1962.git?rev=ece6cbabc41948db4200e41f0bfdab7ab94c7af8#ece6cbabc41948db4200e41f0bfdab7ab94c7af8" +dependencies = [ + "simple_uint", +] + +[[package]] +name = "fixed_width_group_and_loop" +version = "0.1.0" +source = "git+https://github.com/matter-labs/eip1962.git?rev=ece6cbabc41948db4200e41f0bfdab7ab94c7af8#ece6cbabc41948db4200e41f0bfdab7ab94c7af8" +dependencies = [ + "simple_uint", +] + [[package]] name = "fixedbitset" version = "0.1.9" @@ -3013,7 +3056,7 @@ version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" dependencies = [ - "num-bigint", + "num-bigint 0.1.44", "num-integer", "num-iter", "num-traits 0.2.11", @@ -3031,6 +3074,17 @@ dependencies = [ "rustc-serialize", ] +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg 1.0.0", + "num-integer", + "num-traits 0.2.11", +] + [[package]] name = "num-integer" version = "0.1.42" @@ -3099,6 +3153,12 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" + [[package]] name = "oorandom" version = "11.1.0" @@ -4551,6 +4611,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +[[package]] +name = "simple_uint" +version = "0.1.0" +source = "git+https://github.com/matter-labs/eip1962.git?rev=ece6cbabc41948db4200e41f0bfdab7ab94c7af8#ece6cbabc41948db4200e41f0bfdab7ab94c7af8" +dependencies = [ + "byteorder", + "crunchy", + "rustc-hex 2.1.0", + "static_assertions", +] + [[package]] name = "slab" version = "0.4.2" diff --git a/ethcore/builtin/Cargo.toml b/ethcore/builtin/Cargo.toml index 16780253706..68031ab8f1b 100644 --- a/ethcore/builtin/Cargo.toml +++ b/ethcore/builtin/Cargo.toml @@ -17,6 +17,7 @@ log = "0.4" num = { version = "0.1", default-features = false, features = ["bigint"] } parity-bytes = "0.1" parity-crypto = { version = "0.6.1", features = ["publickey"] } +eth_pairings = { git = "https://github.com/matter-labs/eip1962.git", default-features = false, features = ["eip_2537"], rev = "ece6cbabc41948db4200e41f0bfdab7ab94c7af8" } [dev-dependencies] hex-literal = "0.2.1" diff --git a/ethcore/builtin/src/lib.rs b/ethcore/builtin/src/lib.rs index 8f9dde5fc3e..8ba36e963db 100644 --- a/ethcore/builtin/src/lib.rs +++ b/ethcore/builtin/src/lib.rs @@ -37,6 +37,12 @@ use num::{BigUint, Zero, One}; use parity_bytes::BytesRef; use parity_crypto::digest; use eip_152::compress; +use eth_pairings::public_interface::eip2537::{ + EIP2537Executor, + SERIALIZED_G1_POINT_BYTE_LENGTH, + SERIALIZED_G2_POINT_BYTE_LENGTH, + SCALAR_BYTE_LENGTH +}; /// Native implementation of a built-in contract. pub trait Implementation: Send + Sync { @@ -77,6 +83,10 @@ enum Pricing { Blake2F(Blake2FPricer), Linear(Linear), Modexp(ModexpPricer), + Bls12Pairing(Bls12PairingPricer), + Bls12ConstOperations(Bls12ConstOperations), + Bls12MultiexpG1(Bls12MultiexpPricerG1), + Bls12MultiexpG2(Bls12MultiexpPricerG2), } impl Pricer for Pricing { @@ -87,6 +97,10 @@ impl Pricer for Pricing { Pricing::Blake2F(inner) => inner.cost(input), Pricing::Linear(inner) => inner.cost(input), Pricing::Modexp(inner) => inner.cost(input), + Pricing::Bls12Pairing(inner) => inner.cost(input), + Pricing::Bls12ConstOperations(inner) => inner.cost(input), + Pricing::Bls12MultiexpG1(inner) => inner.cost(input), + Pricing::Bls12MultiexpG2(inner) => inner.cost(input), } } } @@ -207,6 +221,118 @@ impl ModexpPricer { } } +/// Bls12 pairing price +#[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, +} + +/// Pricing for constant Bls12 operations (ADD and MUL in G1 and G2, as well as mappings) +#[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; +} +/// 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) +#[derive(Debug, Copy, Clone)] +pub struct Bls12MultiexpPricer { + /// Base const of the operation (G1 or G2 multiplication) + pub base_price: Bls12ConstOperations, + + _marker: std::marker::PhantomData

+} + +impl Pricer for Bls12ConstOperations { + fn cost(&self, _input: &[u8]) -> U256 { + self.price.into() + } +} + +impl Pricer for Bls12PairingPricer { + 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) + } +} + +impl Pricer for Bls12MultiexpPricer

{ + 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) + } +} + +/// 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 @@ -297,6 +423,38 @@ impl From for Pricing { price: pricer.price }) } + ethjson::spec::builtin::Pricing::Bls12ConstOperations(pricer) => { + Pricing::Bls12ConstOperations(Bls12ConstOperations { + price: pricer.price + }) + }, + ethjson::spec::builtin::Pricing::Bls12Pairing(pricer) => { + Pricing::Bls12Pairing(Bls12PairingPricer { + price : Bls12PairingPrice { + base: pricer.base, + pair: pricer.pair + } + } + ) + }, + ethjson::spec::builtin::Pricing::Bls12G1Multiexp(pricer) => { + Pricing::Bls12MultiexpG1(Bls12MultiexpPricerG1 { + base_price: Bls12ConstOperations { + price: pricer.base, + }, + _marker: std::marker::PhantomData + } + ) + }, + ethjson::spec::builtin::Pricing::Bls12G2Multiexp(pricer) => { + Pricing::Bls12MultiexpG2(Bls12MultiexpPricerG2 { + base_price: Bls12ConstOperations { + price: pricer.base + }, + _marker: std::marker::PhantomData + } + ) + }, } } } @@ -320,7 +478,25 @@ enum EthereumBuiltin { /// alt_bn128_pairing Bn128Pairing(Bn128Pairing), /// blake2_f (The Blake2 compression function F, EIP-152) - Blake2F(Blake2F) + Blake2F(Blake2F), + /// 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), } impl FromStr for EthereumBuiltin { @@ -337,6 +513,15 @@ impl FromStr for EthereumBuiltin { "alt_bn128_mul" => Ok(EthereumBuiltin::Bn128Mul(Bn128Mul)), "alt_bn128_pairing" => Ok(EthereumBuiltin::Bn128Pairing(Bn128Pairing)), "blake2_f" => Ok(EthereumBuiltin::Blake2F(Blake2F)), + "bls12_381_g1_add" => Ok(EthereumBuiltin::Bls12G1Add(Bls12G1Add)), + "bls12_381_g1_mul" => Ok(EthereumBuiltin::Bls12G1Mul(Bls12G1Mul)), + "bls12_381_g1_multiexp" => Ok(EthereumBuiltin::Bls12G1MultiExp(Bls12G1MultiExp)), + "bls12_381_g2_add" => Ok(EthereumBuiltin::Bls12G2Add(Bls12G2Add)), + "bls12_381_g2_mul" => Ok(EthereumBuiltin::Bls12G2Mul(Bls12G2Mul)), + "bls12_381_g2_multiexp" => Ok(EthereumBuiltin::Bls12G2MultiExp(Bls12G2MultiExp)), + "bls12_381_pairing" => Ok(EthereumBuiltin::Bls12Pairing(Bls12Pairing)), + "bls12_381_fp_to_g1" => Ok(EthereumBuiltin::Bls12MapFpToG1(Bls12MapFpToG1)), + "bls12_381_fp2_to_g2" => Ok(EthereumBuiltin::Bls12MapFp2ToG2(Bls12MapFp2ToG2)), _ => return Err(EthcoreError::Msg(format!("invalid builtin name: {}", name))), } } @@ -354,6 +539,15 @@ impl Implementation for EthereumBuiltin { EthereumBuiltin::Bn128Mul(inner) => inner.execute(input, output), EthereumBuiltin::Bn128Pairing(inner) => inner.execute(input, output), EthereumBuiltin::Blake2F(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12G1Add(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12G1Mul(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12G1MultiExp(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12G2Add(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12G2Mul(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12G2MultiExp(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12Pairing(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12MapFpToG1(inner) => inner.execute(input, output), + EthereumBuiltin::Bls12MapFp2ToG2(inner) => inner.execute(input, output), } } } @@ -394,6 +588,42 @@ pub struct Bn128Pairing; /// The Blake2F builtin pub struct Blake2F; +#[derive(Debug)] +/// The Bls12G1Add builtin. +pub struct Bls12G1Add; + +#[derive(Debug)] +/// The Bls12G1Mul builtin. +pub struct Bls12G1Mul; + +#[derive(Debug)] +/// The Bls12G1MultiExp builtin. +pub struct Bls12G1MultiExp; + +#[derive(Debug)] +/// The Bls12G2Add builtin. +pub struct Bls12G2Add; + +#[derive(Debug)] +/// The Bls12G2Mul builtin. +pub struct Bls12G2Mul; + +#[derive(Debug)] +/// The Bls12G2MultiExp builtin. +pub struct Bls12G2MultiExp; + +#[derive(Debug)] +/// The Bls12Pairing builtin. +pub struct Bls12Pairing; + +#[derive(Debug)] +/// The Bls12MapFpToG1 builtin. +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> { output.write(0, input); @@ -756,6 +986,178 @@ impl Bn128Pairing { } } +impl Implementation for Bls12G1Add { + 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[..]); + + Ok(()) + }, + Err(e) => { + trace!(target: "builtin", "Bls12G1Add error: {:?}", e); + + Err("Bls12G1Add error") + } + } + } +} + +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") + } + } + } +} + +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") + } + } + } +} + +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") + } + } + } +} + +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") + } + } + } +} + +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") + } + } + } +} + +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") + } + } + } +} + + #[cfg(test)] mod tests { use std::convert::TryFrom; @@ -770,7 +1172,9 @@ mod tests { use parity_bytes::BytesRef; use super::{ Builtin, EthereumBuiltin, FromStr, Implementation, Linear, - ModexpPricer, modexp as me, Pricing + ModexpPricer, modexp as me, Pricing, + Bls12ConstOperations, + Bls12PairingPrice,Bls12PairingPricer }; #[test] @@ -1523,4 +1927,400 @@ 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::{Pricing, Bls12G1Multiexp}; + + 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::{Pricing, Bls12G2Multiexp}; + + 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"); + } + } + } } diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 1949efb0093..bdf8f1168e4 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -4888,6 +4888,87 @@ } } }, + "000000000000000000000000000000000000000a": { + "builtin": { + "name": "bls12_381_g1_add", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_const_operations": { "price": 600 } + } + } + }, + "000000000000000000000000000000000000000b": { + "builtin": { + "name": "bls12_381_g1_mul", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_const_operations": { "price": 12000 } + } + } + }, + "000000000000000000000000000000000000000c": { + "builtin": { + "name": "bls12_381_g1_multiexp", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_g1_multiexp": { "base": 12000 } + } + } + }, + "000000000000000000000000000000000000000d": { + "builtin": { + "name": "bls12_381_g2_add", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_const_operations": { "price": 4500 } + } + } + }, + "000000000000000000000000000000000000000e": { + "builtin": { + "name": "bls12_381_g2_mul", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_const_operations": { "price": 55000 } + } + } + }, + "000000000000000000000000000000000000000f": { + "builtin": { + "name": "bls12_381_g2_multiexp", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_g2_multiexp": { "base": 55000 } + } + } + }, + "0000000000000000000000000000000000000010": { + "builtin": { + "name": "bls12_381_pairing", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_pairing": { "base": 115000, "pair": 23000 } + } + } + }, + "0000000000000000000000000000000000000011": { + "builtin": { + "name": "bls12_381_fp_to_g1", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_const_operations": { "price": 5500 } + } + } + }, + "0000000000000000000000000000000000000012": { + "builtin": { + "name": "bls12_381_fp2_to_g2", + "activate_at": "0x7fffffffffffff", + "pricing": { + "bls12_const_operations": { "price": 110000 } + } + } + }, "0x3282791d6fd713f1e94f4bfd565eaa78b3a0599d": { "balance": "0x487a9a304539440000" }, diff --git a/ethcore/res/ethereum/test-specs/berlin_test.json b/ethcore/res/ethereum/test-specs/berlin_test.json index 817350db08b..8aa5a1960a7 100644 --- a/ethcore/res/ethereum/test-specs/berlin_test.json +++ b/ethcore/res/ethereum/test-specs/berlin_test.json @@ -110,13 +110,94 @@ "0000000000000000000000000000000000000009": { "builtin": { "name": "blake2_f", - "activate_at": "0x00", + "activate_at": "0x0", "pricing": { "blake2_f": { "gas_per_round": 1 } } } + }, + "000000000000000000000000000000000000000a": { + "builtin": { + "name": "bls12_381_g1_add", + "activate_at": "0x0", + "pricing": { + "bls12_const_operations": { "price": 600 } + } + } + }, + "000000000000000000000000000000000000000b": { + "builtin": { + "name": "bls12_381_g1_mul", + "activate_at": "0x0", + "pricing": { + "bls12_const_operations": { "price": 12000 } + } + } + }, + "000000000000000000000000000000000000000c": { + "builtin": { + "name": "bls12_381_g1_multiexp", + "activate_at": "0x0", + "pricing": { + "bls12_g1_multiexp": { "base": 12000 } + } + } + }, + "000000000000000000000000000000000000000d": { + "builtin": { + "name": "bls12_381_g2_add", + "activate_at": "0x0", + "pricing": { + "bls12_const_operations": { "price": 4500 } + } + } + }, + "000000000000000000000000000000000000000e": { + "builtin": { + "name": "bls12_381_g2_mul", + "activate_at": "0x0", + "pricing": { + "bls12_const_operations": { "price": 55000 } + } + } + }, + "000000000000000000000000000000000000000f": { + "builtin": { + "name": "bls12_381_g2_multiexp", + "activate_at": "0x0", + "pricing": { + "bls12_g2_multiexp": { "base": 55000 } + } + } + }, + "0000000000000000000000000000000000000010": { + "builtin": { + "name": "bls12_381_pairing", + "activate_at": "0x0", + "pricing": { + "bls12_pairing": { "base": 115000, "pair": 23000 } + } + } + }, + "0000000000000000000000000000000000000011": { + "builtin": { + "name": "bls12_381_fp_to_g1", + "activate_at": "0x0", + "pricing": { + "bls12_const_operations": { "price": 5500 } + } + } + }, + "0000000000000000000000000000000000000012": { + "builtin": { + "name": "bls12_381_fp2_to_g2", + "activate_at": "0x00", + "pricing": { + "bls12_const_operations": { "price": 110000 } + } + } } } } diff --git a/ethcore/spec/src/chain.rs b/ethcore/spec/src/chain.rs index fe7ca8d5ad4..10b8b33dd36 100644 --- a/ethcore/spec/src/chain.rs +++ b/ethcore/spec/src/chain.rs @@ -152,7 +152,7 @@ mod tests { use tempfile::TempDir; use ethcore::test_helpers::get_temp_state_db; - use super::{new_ropsten, new_foundation}; + use super::{new_ropsten, new_foundation, new_berlin_test_machine}; #[test] fn ensure_db_good() { @@ -189,4 +189,9 @@ mod tests { let genesis = frontier.genesis_block(); assert_eq!(view!(BlockView, &genesis).header_view().hash(), "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3".parse().unwrap()); } + + #[test] + fn berlin_test_spec() { + let _ = new_berlin_test_machine(); + } } diff --git a/json/src/spec/builtin.rs b/json/src/spec/builtin.rs index 173975fafe7..9a66c3a732a 100644 --- a/json/src/spec/builtin.rs +++ b/json/src/spec/builtin.rs @@ -57,6 +57,41 @@ pub struct AltBn128Pairing { pub pair: u64, } + +/// Bls12 pairing price +#[derive(Debug, PartialEq, Deserialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct Bls12Pairing { + /// Price per final exp + pub base: u64, + /// Price per pair (Miller loop) + pub pair: u64, +} + +/// Pricing for constant Bls12 operations (ADD and MUL in G1 and G2, as well as mappings) +#[derive(Debug, PartialEq, Deserialize, Clone)] +#[serde(deny_unknown_fields)] +pub struct Bls12ConstOperations { + /// Fixed price. + pub price: u64, +} + +/// Pricing for constant Bls12 operations (ADD and MUL in G1, as well as mappings) +#[derive(Debug, PartialEq, 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, 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, Deserialize, Clone)] #[serde(deny_unknown_fields)] @@ -75,6 +110,14 @@ pub enum Pricing { AltBn128Pairing(AltBn128Pairing), /// Pricing for constant alt_bn128 operations AltBn128ConstOperations(AltBn128ConstOperations), + /// Pricing of constant price bls12_381 operations + 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), } /// Builtin compability layer @@ -139,7 +182,7 @@ pub struct PricingAt { #[cfg(test)] mod tests { - use super::{Builtin, BuiltinCompat, Pricing, PricingAt, Linear, Modexp, AltBn128ConstOperations}; + use super::{Builtin, BuiltinCompat, Pricing, PricingAt, Linear, Modexp, AltBn128ConstOperations, Bls12G1Multiexp, Bls12G2Multiexp}; use maplit::btreemap; #[test] @@ -242,4 +285,48 @@ 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 + }), + } + ]); + } }