diff --git a/soroban-env-host/benches/common/cost_types/bls12_381.rs b/soroban-env-host/benches/common/cost_types/bls12_381.rs new file mode 100644 index 000000000..b2b818df3 --- /dev/null +++ b/soroban-env-host/benches/common/cost_types/bls12_381.rs @@ -0,0 +1,312 @@ +use crate::common::HostCostMeasurement; +use ark_bls12_381::{Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_ff::UniformRand; +use ark_serialize::CanonicalSerialize; +use rand::{rngs::StdRng, Rng, RngCore}; +use soroban_env_host::{ + cost_runner::{ + Bls12381DecodeFpRun, Bls12381DecodeFpSample, Bls12381EncodeFpRun, Bls12381EncodeFpSample, + Bls12381FrAddRun, Bls12381FrAddSubMulSample, Bls12381FrFromU256Run, + Bls12381FrFromU256Sample, Bls12381FrInvRun, Bls12381FrInvSample, Bls12381FrMulRun, + Bls12381FrPowRun, Bls12381FrPowSample, Bls12381FrSubRun, Bls12381FrToU256Run, + Bls12381FrToU256Sample, Bls12381G1AddRun, Bls12381G1AddSample, Bls12381G1MsmRun, + Bls12381G1MsmSample, Bls12381G1MulRun, Bls12381G1MulSample, + Bls12381G1ProjectiveToAffineRun, Bls12381G1ProjectiveToAffineSample, Bls12381G1ValidateRun, + Bls12381G1ValidateSample, Bls12381G2AddRun, Bls12381G2AddSample, Bls12381G2MsmRun, + Bls12381G2MsmSample, Bls12381G2MulRun, Bls12381G2MulSample, + Bls12381G2ProjectiveToAffineRun, Bls12381G2ProjectiveToAffineSample, Bls12381G2ValidateRun, + Bls12381G2ValidateSample, Bls12381HashToG1Run, Bls12381HashToG1Sample, Bls12381HashToG2Run, + Bls12381HashToG2Sample, Bls12381MapFp2ToG2Run, Bls12381MapFp2ToG2Sample, + Bls12381MapFpToG1Run, Bls12381MapFpToG1Sample, Bls12381PairingRun, Bls12381PairingSample, + }, + xdr::ContractCostType, + Host, TryIntoVal, U256Val, U256, +}; + +pub(crate) struct Bls12381EncodeFpMeasure; +impl HostCostMeasurement for Bls12381EncodeFpMeasure { + type Runner = Bls12381EncodeFpRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381EncodeFpSample { + let buf = vec![0; 1000]; + let fp = Fq::rand(rng); + Bls12381EncodeFpSample(buf, fp) + } +} +pub(crate) struct Bls12381DecodeFpMeasure; +impl HostCostMeasurement for Bls12381DecodeFpMeasure { + type Runner = Bls12381DecodeFpRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381DecodeFpSample { + let mut buf = vec![]; + let _ = Fq::rand(rng).serialize_uncompressed(&mut buf).unwrap(); + Bls12381DecodeFpSample(buf) + } +} +pub(crate) struct Bls12381G1ValidateMeasure; +impl HostCostMeasurement for Bls12381G1ValidateMeasure { + type Runner = Bls12381G1ValidateRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381G1ValidateSample { + Bls12381G1ValidateSample(G1Affine::rand(rng), ContractCostType::Bls12381G1Validate) + } +} +pub(crate) struct Bls12381G2ValidateMeasure; +impl HostCostMeasurement for Bls12381G2ValidateMeasure { + type Runner = Bls12381G2ValidateRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381G2ValidateSample { + Bls12381G2ValidateSample(G2Affine::rand(rng), ContractCostType::Bls12381G2Validate) + } +} +pub(crate) struct Bls12381FrFromU256Measure; +impl HostCostMeasurement for Bls12381FrFromU256Measure { + type Runner = Bls12381FrFromU256Run; + + fn new_random_case(host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381FrFromU256Sample { + let mut buf = [0; 32]; + rng.fill_bytes(&mut buf); + let u = U256::from_be_bytes(buf); + let val: U256Val = u.try_into_val(host).unwrap(); + Bls12381FrFromU256Sample(val) + } +} +pub(crate) struct Bls12381FrToU256Measure; +impl HostCostMeasurement for Bls12381FrToU256Measure { + type Runner = Bls12381FrToU256Run; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381FrToU256Sample { + Bls12381FrToU256Sample(Fr::rand(rng)) + } +} +pub(crate) struct Bls12381FrAddMeasure; +impl HostCostMeasurement for Bls12381FrAddMeasure { + type Runner = Bls12381FrAddRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381FrAddSubMulSample { + Bls12381FrAddSubMulSample(Fr::rand(rng), Fr::rand(rng)) + } +} +pub(crate) struct Bls12381FrSubMeasure; +impl HostCostMeasurement for Bls12381FrSubMeasure { + type Runner = Bls12381FrSubRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381FrAddSubMulSample { + Bls12381FrAddSubMulSample(Fr::rand(rng), Fr::rand(rng)) + } +} +pub(crate) struct Bls12381FrMulMeasure; +impl HostCostMeasurement for Bls12381FrMulMeasure { + type Runner = Bls12381FrMulRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381FrAddSubMulSample { + Bls12381FrAddSubMulSample(Fr::rand(rng), Fr::rand(rng)) + } +} +pub(crate) struct Bls12381FrPowMeasure; +impl HostCostMeasurement for Bls12381FrPowMeasure { + type Runner = Bls12381FrPowRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, input: u64) -> Bls12381FrPowSample { + assert!(input <= 64); + let rhs = if input == 64 { + u64::MAX + } else { + (1 << input) - 1 + }; + Bls12381FrPowSample(Fr::rand(rng), rhs) + } +} +pub(crate) struct Bls12381FrInvMeasure; +impl HostCostMeasurement for Bls12381FrInvMeasure { + type Runner = Bls12381FrInvRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381FrInvSample { + Bls12381FrInvSample(Fr::rand(rng)) + } +} + +pub(crate) struct Bls12381G1AddMeasure; + +impl HostCostMeasurement for Bls12381G1AddMeasure { + type Runner = Bls12381G1AddRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381G1AddSample { + let p0 = G1Affine::rand(rng); + let p1 = G1Affine::rand(rng); + Bls12381G1AddSample(p0, p1) + } +} + +pub(crate) struct Bls12381G1ProjectiveToAffineMeasure; + +impl HostCostMeasurement for Bls12381G1ProjectiveToAffineMeasure { + type Runner = Bls12381G1ProjectiveToAffineRun; + + fn new_random_case( + _host: &Host, + rng: &mut StdRng, + _input: u64, + ) -> Bls12381G1ProjectiveToAffineSample { + let p0 = G1Projective::rand(rng); + Bls12381G1ProjectiveToAffineSample(p0) + } +} + +pub(crate) struct Bls12381G1MulMeasure; + +impl HostCostMeasurement for Bls12381G1MulMeasure { + type Runner = Bls12381G1MulRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381G1MulSample { + let p = G1Affine::rand(rng); + let s = Fr::rand(rng); + Bls12381G1MulSample(p, s) + } +} + +pub(crate) struct Bls12381G1MsmMeasure; + +impl HostCostMeasurement for Bls12381G1MsmMeasure { + type Runner = Bls12381G1MsmRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, input: u64) -> Bls12381G1MsmSample { + Bls12381G1MsmSample( + (0..input) + .into_iter() + .map(|_| G1Affine::rand(rng)) + .collect(), + (0..input).into_iter().map(|_| Fr::rand(rng)).collect(), + ) + } +} + +pub(crate) struct Bls12381MapFpToG1Measure; + +impl HostCostMeasurement for Bls12381MapFpToG1Measure { + type Runner = Bls12381MapFpToG1Run; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381MapFpToG1Sample { + let fp = Fq::rand(rng); + Bls12381MapFpToG1Sample(fp) + } +} + +pub(crate) struct Bls12381HashToG1Measure; + +impl HostCostMeasurement for Bls12381HashToG1Measure { + type Runner = Bls12381HashToG1Run; + const STEP_SIZE: u64 = 64; + + fn new_random_case(_host: &Host, rng: &mut StdRng, input: u64) -> Bls12381HashToG1Sample { + let len = Self::INPUT_BASE_SIZE + input * Self::STEP_SIZE; + let domain = "SOROBAN-V01-CS01-with-BLS12381G1_XMD:SHA-256_SSWU_RO_" + .as_bytes() + .to_vec(); + let mut msg = vec![0u8; len as usize]; + rng.fill(msg.as_mut_slice()); + Bls12381HashToG1Sample(domain, msg) + } +} + +pub(crate) struct Bls12381G2ProjectiveToAffineMeasure; + +impl HostCostMeasurement for Bls12381G2ProjectiveToAffineMeasure { + type Runner = Bls12381G2ProjectiveToAffineRun; + + fn new_random_case( + _host: &Host, + rng: &mut StdRng, + _input: u64, + ) -> Bls12381G2ProjectiveToAffineSample { + let p0 = G2Projective::rand(rng); + Bls12381G2ProjectiveToAffineSample(p0) + } +} + +pub(crate) struct Bls12381G2AddMeasure; + +impl HostCostMeasurement for Bls12381G2AddMeasure { + type Runner = Bls12381G2AddRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381G2AddSample { + let p0 = G2Affine::rand(rng); + let p1 = G2Affine::rand(rng); + Bls12381G2AddSample(p0, p1) + } +} + +pub(crate) struct Bls12381G2MulMeasure; + +impl HostCostMeasurement for Bls12381G2MulMeasure { + type Runner = Bls12381G2MulRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381G2MulSample { + let p = G2Affine::rand(rng); + let s = Fr::rand(rng); + Bls12381G2MulSample(p, s) + } +} + +pub(crate) struct Bls12381G2MsmMeasure; + +impl HostCostMeasurement for Bls12381G2MsmMeasure { + type Runner = Bls12381G2MsmRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, input: u64) -> Bls12381G2MsmSample { + Bls12381G2MsmSample( + (0..input) + .into_iter() + .map(|_| G2Affine::rand(rng)) + .collect(), + (0..input).into_iter().map(|_| Fr::rand(rng)).collect(), + ) + } +} + +pub(crate) struct Bls12381MapFp2ToG2Measure; + +impl HostCostMeasurement for Bls12381MapFp2ToG2Measure { + type Runner = Bls12381MapFp2ToG2Run; + + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Bls12381MapFp2ToG2Sample { + let fp2 = Fq2::rand(rng); + Bls12381MapFp2ToG2Sample(fp2) + } +} + +pub(crate) struct Bls12381HashToG2Measure; + +impl HostCostMeasurement for Bls12381HashToG2Measure { + type Runner = Bls12381HashToG2Run; + const STEP_SIZE: u64 = 64; + + fn new_random_case(_host: &Host, rng: &mut StdRng, input: u64) -> Bls12381HashToG2Sample { + let len = Self::INPUT_BASE_SIZE + input * Self::STEP_SIZE; + let domain = "SOROBAN-V01-CS01-with-BLS12381G2_XMD:SHA-256_SSWU_RO_" + .as_bytes() + .to_vec(); + let mut msg = vec![0u8; len as usize]; + rng.fill(msg.as_mut_slice()); + Bls12381HashToG2Sample(domain, msg) + } +} + +pub(crate) struct Bls12381PairingMeasure; + +impl HostCostMeasurement for Bls12381PairingMeasure { + type Runner = Bls12381PairingRun; + + fn new_random_case(_host: &Host, rng: &mut StdRng, input: u64) -> Bls12381PairingSample { + Bls12381PairingSample( + (0..input) + .into_iter() + .map(|_| G1Affine::rand(rng)) + .collect(), + (0..input) + .into_iter() + .map(|_| G2Affine::rand(rng)) + .collect(), + ) + } +} diff --git a/soroban-env-host/benches/common/cost_types/mod.rs b/soroban-env-host/benches/common/cost_types/mod.rs index 651449342..c36092d88 100644 --- a/soroban-env-host/benches/common/cost_types/mod.rs +++ b/soroban-env-host/benches/common/cost_types/mod.rs @@ -1,3 +1,4 @@ +mod bls12_381; mod compute_ed25519_pubkey; mod compute_keccak256_hash; mod compute_sha256_hash; @@ -18,6 +19,7 @@ mod visit_object; mod vm_ops; mod wasm_insn_exec; +pub(crate) use bls12_381::*; pub(crate) use compute_ed25519_pubkey::*; pub(crate) use compute_keccak256_hash::*; pub(crate) use compute_sha256_hash::*; diff --git a/soroban-env-host/benches/common/experimental/bls12_381.rs b/soroban-env-host/benches/common/experimental/bls12_381.rs new file mode 100644 index 000000000..67c39d15c --- /dev/null +++ b/soroban-env-host/benches/common/experimental/bls12_381.rs @@ -0,0 +1,61 @@ +use crate::common::HostCostMeasurement; +use ark_bls12_381::{Fq2, G1Affine, G2Affine}; +use ark_ff::UniformRand; +use ark_serialize::CanonicalSerialize; +use rand::rngs::StdRng; +use soroban_env_host::{ + cost_runner::{ + Bls12381Fp2DeserializeUncompressedRun, Bls12381G1AffineDeserializeUncompressedRun, + Bls12381G1AffineSerializeUncompressedRun, Bls12381G2AffineDeserializeUncompressedRun, + Bls12381G2AffineSerializeUncompressedRun, + }, + Host, +}; + +pub(crate) struct Bls12381G1AffineSerializeUncompressedMeasure; +impl HostCostMeasurement for Bls12381G1AffineSerializeUncompressedMeasure { + type Runner = Bls12381G1AffineSerializeUncompressedRun; + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> G1Affine { + G1Affine::rand(rng) + } +} +pub(crate) struct Bls12381G2AffineSerializeUncompressedMeasure; +impl HostCostMeasurement for Bls12381G2AffineSerializeUncompressedMeasure { + type Runner = Bls12381G2AffineSerializeUncompressedRun; + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> G2Affine { + G2Affine::rand(rng) + } +} + +pub(crate) struct Bls12381G1AffineDeserializeUncompressedMeasure; +impl HostCostMeasurement for Bls12381G1AffineDeserializeUncompressedMeasure { + type Runner = Bls12381G1AffineDeserializeUncompressedRun; + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Vec { + let mut buf = vec![]; + let _ = G1Affine::rand(rng) + .serialize_uncompressed(&mut buf) + .unwrap(); + buf + } +} +pub(crate) struct Bls12381G2AffineDeserializeUncompressedMeasure; +impl HostCostMeasurement for Bls12381G2AffineDeserializeUncompressedMeasure { + type Runner = Bls12381G2AffineDeserializeUncompressedRun; + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Vec { + let mut buf = vec![]; + let _ = G2Affine::rand(rng) + .serialize_uncompressed(&mut buf) + .unwrap(); + buf + } +} + +pub(crate) struct Bls12381Fp2DeserializeUncompressedMeasure; +impl HostCostMeasurement for Bls12381Fp2DeserializeUncompressedMeasure { + type Runner = Bls12381Fp2DeserializeUncompressedRun; + fn new_random_case(_host: &Host, rng: &mut StdRng, _input: u64) -> Vec { + let mut buf = vec![]; + let _ = Fq2::rand(rng).serialize_uncompressed(&mut buf).unwrap(); + buf + } +} diff --git a/soroban-env-host/benches/common/experimental/mod.rs b/soroban-env-host/benches/common/experimental/mod.rs index d64b260e0..b011b3778 100644 --- a/soroban-env-host/benches/common/experimental/mod.rs +++ b/soroban-env-host/benches/common/experimental/mod.rs @@ -1,3 +1,4 @@ +mod bls12_381; mod decode_secp256r1_sig; mod ecdsa_secp256k1_verify; mod ecdsa_secp256r1_recover; @@ -5,6 +6,7 @@ mod ed25519_scalar_mul; mod read_xdr; mod sec1_decode_point_compressed; +pub(crate) use bls12_381::*; pub(crate) use decode_secp256r1_sig::*; pub(crate) use ecdsa_secp256k1_verify::*; pub(crate) use ecdsa_secp256r1_recover::*; diff --git a/soroban-env-host/benches/common/measure.rs b/soroban-env-host/benches/common/measure.rs index 3fde3a8db..1ec48598c 100644 --- a/soroban-env-host/benches/common/measure.rs +++ b/soroban-env-host/benches/common/measure.rs @@ -98,8 +98,15 @@ impl Measurements { let ymin = points.iter().map(|(_, y)| *y).reduce(f32::min).unwrap(); let ymax = points.iter().map(|(_, y)| *y).reduce(f32::max).unwrap(); let ymean = points.iter().map(|(_, y)| *y).sum::() / points.len().max(1) as f32; + let mut ystd = points + .iter() + .map(|(_, y)| (*y - ymean) * (*y - ymean)) + .sum::() + / points.len().max(1) as f32; + ystd = ystd.sqrt(); if ymin == ymax { + println!("{} output: min == max == {}", out_name, ymin); return; } let hist = textplots::utils::histogram(&points, ymin, ymax, 30); @@ -125,12 +132,13 @@ impl Measurements { in_max / in_min.max(1.0) ); println!( - "{} output: min {}; max {}; max/min = {}; mean = {}; count = {}", + "{} output: min {}; max {}; max/min = {}; mean = {}; std = {}, count = {}", out_name, ymin.separate_with_commas(), ymax.separate_with_commas(), ymax / ymin.max(1.0), ymean.separate_with_commas(), + ystd.separate_with_commas(), points.len() ); Chart::new(180, 60, ymin - 100.0, ymax + 100.0) @@ -316,8 +324,8 @@ pub trait HostCostMeasurement: Sized { ::run(host, samples, recycled_samples) } - fn get_tracker(host: &Host) -> CostTracker { - ::get_tracker(host) + fn get_tracker(host: &Host, sample: &::SampleType) -> CostTracker { + ::get_tracker(host, sample) } // This is kind of a hack to account for the additional cpu_insn overhead @@ -340,7 +348,8 @@ fn harness( host: &Host, alloc_group_token: Option<&mut AllocationGroupToken>, runner: &mut R, - samples: Vec<<::Runner as CostRunner>::SampleType>, + sample: <::Runner as CostRunner>::SampleType, + repeat_iters: u64, ) -> Measurement where R: FnMut( @@ -349,7 +358,8 @@ where &mut Vec<<::Runner as CostRunner>::RecycledType>, ), { - let mut recycled_samples = Vec::with_capacity(samples.len()); + let samples = (0..repeat_iters).map(|_| sample.clone()).collect(); + let mut recycled_samples = Vec::with_capacity(repeat_iters as usize); host.as_budget().reset_unlimited().unwrap(); let mut ht = HostTracker::new(); @@ -361,7 +371,7 @@ where // Note: the `iterations` here is not same as `RUN_ITERATIONS`. This is the `N` part of the // cost model, which is `RUN_ITERATIONS` * "model iterations from the sample" - let ct = HCM::get_tracker(&host); + let ct = HCM::get_tracker(&host, &sample); Measurement { iterations: ct.iterations, inputs: ct.inputs, @@ -398,15 +408,18 @@ where Some(s) => s, None => break, }; - let samples = (0..::RUN_ITERATIONS) - .map(|_| sample.clone()) - .collect(); // This part is the `N_r * Overhead_s` part of equation [2]. // This is 0 unless we are doing wasm-insn level calibration let samples_cpu_insns_overhead = ::RUN_ITERATIONS .saturating_mul(HCM::get_insns_overhead_per_sample(&host, &sample)); - let mut mes = harness::(&host, Some(&mut alloc_group_token), &mut runner, samples); + let mut mes = harness::( + &host, + Some(&mut alloc_group_token), + &mut runner, + sample, + ::RUN_ITERATIONS, + ); mes.cpu_insns -= samples_cpu_insns_overhead; // the return result contains `N_r * (f(x) + Overhead_b)` (see equation [2]) ret.push(mes); diff --git a/soroban-env-host/benches/common/mod.rs b/soroban-env-host/benches/common/mod.rs index c427eea65..798be807e 100644 --- a/soroban-env-host/benches/common/mod.rs +++ b/soroban-env-host/benches/common/mod.rs @@ -60,6 +60,12 @@ pub(crate) fn for_each_experimental_cost_measurement( call_bench::(&mut params)?; call_bench::(&mut params)?; call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + Ok(params) } @@ -115,6 +121,32 @@ pub(crate) fn for_each_host_cost_measurement( call_bench::(&mut params)?; call_bench::(&mut params)?; + // P22 cost types + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + call_bench::(&mut params)?; + // These three mem ones are derived analytically, we do not calibrate them typically if std::env::var("INCLUDE_ANALYTICAL_COSTTYPES").is_ok() { call_bench::(&mut params)?; diff --git a/soroban-env-host/benches/variation_histograms.rs b/soroban-env-host/benches/variation_histograms.rs index d0d4992ce..f95b7f9c0 100644 --- a/soroban-env-host/benches/variation_histograms.rs +++ b/soroban-env-host/benches/variation_histograms.rs @@ -16,7 +16,7 @@ impl Benchmark for LinearModelTables { fn bench( ) -> std::io::Result<(MeteredCostComponent, MeteredCostComponent)> { // the inputs will be ignored if the measurment is for a constant model - let mut measurements = measure_cost_variation::(100_000, || 0, || 0, false)?; + let mut measurements = measure_cost_variation::(1_000, || 10, || 10, false)?; measurements.check_range_against_baseline(&HCM::Runner::COST_TYPE)?; measurements.preprocess(); measurements.report_histogram("cpu", |m| m.cpu_insns); diff --git a/soroban-env-host/src/cost_runner/cost_types/bls12_381.rs b/soroban-env-host/src/cost_runner/cost_types/bls12_381.rs new file mode 100644 index 000000000..33408298e --- /dev/null +++ b/soroban-env-host/src/cost_runner/cost_types/bls12_381.rs @@ -0,0 +1,353 @@ +use ark_bls12_381::{Bls12_381, Fq, Fq2, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_ec::pairing::PairingOutput; + +use crate::{ + cost_runner::{CostRunner, CostType}, + impl_const_cost_runner_for_bls_consume_sample, impl_const_cost_runner_for_bls_deref_sample, + impl_lin_cost_runner_for_bls_deref_sample, + xdr::ContractCostType::{ + self, Bls12381DecodeFp, Bls12381EncodeFp, Bls12381FrAddSub, Bls12381FrFromU256, + Bls12381FrInv, Bls12381FrMul, Bls12381FrPow, Bls12381FrToU256, Bls12381G1Add, + Bls12381G1Msm, Bls12381G1Mul, Bls12381G1ProjectiveToAffine, Bls12381G1Validate, + Bls12381G2Add, Bls12381G2Msm, Bls12381G2Mul, Bls12381G2ProjectiveToAffine, + Bls12381G2Validate, Bls12381HashToG1, Bls12381HashToG2, Bls12381MapFp2ToG2, + Bls12381MapFpToG1, Bls12381Pairing, + }, + Host, U256Val, +}; +use std::hint::black_box; + +pub struct Bls12381EncodeFpRun; +pub struct Bls12381DecodeFpRun; +pub struct Bls12381G1ValidateRun; +pub struct Bls12381G2ValidateRun; +pub struct Bls12381G1ProjectiveToAffineRun; +pub struct Bls12381G2ProjectiveToAffineRun; +pub struct Bls12381G1AddRun; +pub struct Bls12381G1MulRun; +pub struct Bls12381G1MsmRun; +pub struct Bls12381MapFpToG1Run; +pub struct Bls12381HashToG1Run; +pub struct Bls12381G2AddRun; +pub struct Bls12381G2MulRun; +pub struct Bls12381G2MsmRun; +pub struct Bls12381MapFp2ToG2Run; +pub struct Bls12381HashToG2Run; +pub struct Bls12381PairingRun; +pub struct Bls12381FrFromU256Run; +pub struct Bls12381FrToU256Run; +pub struct Bls12381FrAddRun; +pub struct Bls12381FrSubRun; +pub struct Bls12381FrMulRun; +pub struct Bls12381FrPowRun; +pub struct Bls12381FrInvRun; + +#[derive(Clone)] +pub struct Bls12381G1ProjectiveToAffineSample(pub G1Projective); +#[derive(Clone)] +pub struct Bls12381G1AddSample(pub G1Affine, pub G1Affine); +#[derive(Clone)] +pub struct Bls12381G1MulSample(pub G1Affine, pub Fr); +#[derive(Clone)] +pub struct Bls12381G1MsmSample(pub Vec, pub Vec); +#[derive(Clone)] +pub struct Bls12381MapFpToG1Sample(pub Fq); +#[derive(Clone)] +pub struct Bls12381HashToG1Sample(pub Vec, pub Vec); +#[derive(Clone)] +pub struct Bls12381G2ProjectiveToAffineSample(pub G2Projective); +#[derive(Clone)] +pub struct Bls12381G2AddSample(pub G2Affine, pub G2Affine); +#[derive(Clone)] +pub struct Bls12381G2MulSample(pub G2Affine, pub Fr); +#[derive(Clone)] +pub struct Bls12381G2MsmSample(pub Vec, pub Vec); +#[derive(Clone)] +pub struct Bls12381MapFp2ToG2Sample(pub Fq2); +#[derive(Clone)] +pub struct Bls12381HashToG2Sample(pub Vec, pub Vec); +#[derive(Clone)] +pub struct Bls12381PairingSample(pub Vec, pub Vec); +#[derive(Clone)] +pub struct Bls12381EncodeFpSample(pub Vec, pub Fq); +#[derive(Clone)] +pub struct Bls12381DecodeFpSample(pub Vec); +#[derive(Clone)] +pub struct Bls12381G1ValidateSample(pub G1Affine, pub ContractCostType); +#[derive(Clone)] +pub struct Bls12381G2ValidateSample(pub G2Affine, pub ContractCostType); +#[derive(Clone)] +pub struct Bls12381FrToU256Sample(pub Fr); +#[derive(Clone)] +pub struct Bls12381FrFromU256Sample(pub U256Val); +#[derive(Clone)] +pub struct Bls12381FrAddSubMulSample(pub Fr, pub Fr); +#[derive(Clone)] +pub struct Bls12381FrPowSample(pub Fr, pub u64); +#[derive(Clone)] +pub struct Bls12381FrInvSample(pub Fr); + +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G1ProjectiveToAffineRun, + Bls12381G1ProjectiveToAffine, + g1_projective_into_affine, + Bls12381G1ProjectiveToAffineSample, + G1Affine, + p0 +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G1AddRun, + Bls12381G1Add, + g1_add_internal, + Bls12381G1AddSample, + G1Projective, + p0, + p1 +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G1MulRun, + Bls12381G1Mul, + g1_mul_internal, + Bls12381G1MulSample, + G1Projective, + p0, + scalar +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381MapFpToG1Run, + Bls12381MapFpToG1, + map_fp_to_g1_internal, + Bls12381MapFpToG1Sample, + G1Affine, + fq +); + +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G2ProjectiveToAffineRun, + Bls12381G2ProjectiveToAffine, + g2_projective_into_affine, + Bls12381G2ProjectiveToAffineSample, + G2Affine, + p0 +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G2AddRun, + Bls12381G2Add, + g2_add_internal, + Bls12381G2AddSample, + G2Projective, + p0, + p1 +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G2MulRun, + Bls12381G2Mul, + g2_mul_internal, + Bls12381G2MulSample, + G2Projective, + p0, + scalar +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381MapFp2ToG2Run, + Bls12381MapFp2ToG2, + map_fp2_to_g2_internal, + Bls12381MapFp2ToG2Sample, + G2Affine, + fq2 +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G1ValidateRun, + Bls12381G1Validate, + metered_check_point, + Bls12381G1ValidateSample, + G1Affine, + pt, + ct +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381G2ValidateRun, + Bls12381G2Validate, + metered_check_point, + Bls12381G2ValidateSample, + G2Affine, + pt, + ct +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381FrFromU256Run, + Bls12381FrFromU256, + fr_from_u256val, + Bls12381FrFromU256Sample, + Fr, + sv +); +impl_const_cost_runner_for_bls_consume_sample!( + Bls12381FrToU256Run, + Bls12381FrToU256, + fr_to_u256val, + Bls12381FrToU256Sample, + U256Val, + fr +); + +impl_lin_cost_runner_for_bls_deref_sample!( + Bls12381HashToG1Run, + Bls12381HashToG1, + hash_to_g1_internal, + Bls12381HashToG1Sample, + G1Affine, + domain, + msg +); +impl_lin_cost_runner_for_bls_deref_sample!( + Bls12381HashToG2Run, + Bls12381HashToG2, + hash_to_g2_internal, + Bls12381HashToG2Sample, + G2Affine, + domain, + msg +); + +impl_lin_cost_runner_for_bls_deref_sample!( + Bls12381G1MsmRun, + Bls12381G1Msm, + g1_msm_internal, + Bls12381G1MsmSample, + G1Projective, + vp, + vs +); + +impl_lin_cost_runner_for_bls_deref_sample!( + Bls12381G2MsmRun, + Bls12381G2Msm, + g2_msm_internal, + Bls12381G2MsmSample, + G2Projective, + vp, + vs +); + +type InternalPairingOutput = PairingOutput; +impl_lin_cost_runner_for_bls_deref_sample!( + Bls12381PairingRun, + Bls12381Pairing, + pairing_internal, + Bls12381PairingSample, + InternalPairingOutput, + vp1, + vp2 +); + +// ser/deser + +impl CostRunner for Bls12381EncodeFpRun { + const COST_TYPE: CostType = CostType::Contract(Bls12381EncodeFp); + + const RUN_ITERATIONS: u64 = 1; + + type SampleType = Bls12381EncodeFpSample; + + type RecycledType = Option; + + fn run_iter( + host: &crate::Host, + _iter: u64, + mut sample: Bls12381EncodeFpSample, + ) -> Self::RecycledType { + let Bls12381EncodeFpSample(buf, fp) = &mut sample; + let _ = host + .serialize_uncompressed_into_slice(fp, buf, 1, "test") + .unwrap(); + black_box(Some(sample)) + } + + fn run_baseline_iter( + host: &crate::Host, + _iter: u64, + sample: Bls12381EncodeFpSample, + ) -> Self::RecycledType { + black_box(host.charge_budget(Bls12381EncodeFp, None).unwrap()); + black_box(Some(sample)) + } +} + +impl CostRunner for Bls12381DecodeFpRun { + const COST_TYPE: CostType = CostType::Contract(Bls12381DecodeFp); + + const RUN_ITERATIONS: u64 = 1; + + type SampleType = Bls12381DecodeFpSample; + + type RecycledType = (Option, Option); + + fn run_iter( + host: &crate::Host, + _iter: u64, + sample: Bls12381DecodeFpSample, + ) -> Self::RecycledType { + let Bls12381DecodeFpSample(buf) = &sample; + let res = host + .deserialize_uncompessed_no_validate(buf, 1, "test") + .unwrap(); + black_box((Some(sample), Some(res))) + } + + fn run_baseline_iter( + host: &crate::Host, + _iter: u64, + sample: Self::SampleType, + ) -> Self::RecycledType { + black_box(host.charge_budget(Bls12381DecodeFp, None).unwrap()); + black_box((Some(sample), None)) + } +} + +// fr arith + +impl_const_cost_runner_for_bls_deref_sample!( + Bls12381FrAddRun, + Bls12381FrAddSub, + fr_add_internal, + Bls12381FrAddSubMulSample, + (), + lhs, + rhs +); +impl_const_cost_runner_for_bls_deref_sample!( + Bls12381FrSubRun, + Bls12381FrAddSub, + fr_sub_internal, + Bls12381FrAddSubMulSample, + (), + lhs, + rhs +); +impl_const_cost_runner_for_bls_deref_sample!( + Bls12381FrMulRun, + Bls12381FrMul, + fr_mul_internal, + Bls12381FrAddSubMulSample, + (), + lhs, + rhs +); +impl_const_cost_runner_for_bls_deref_sample!( + Bls12381FrInvRun, + Bls12381FrInv, + fr_inv_internal, + Bls12381FrInvSample, + Fr, + lhs +); +impl_lin_cost_runner_for_bls_deref_sample!( + Bls12381FrPowRun, + Bls12381FrPow, + fr_pow_internal, + Bls12381FrPowSample, + Fr, + lhs, + rhs +); diff --git a/soroban-env-host/src/cost_runner/cost_types/mod.rs b/soroban-env-host/src/cost_runner/cost_types/mod.rs index 84405b512..01e5976cc 100644 --- a/soroban-env-host/src/cost_runner/cost_types/mod.rs +++ b/soroban-env-host/src/cost_runner/cost_types/mod.rs @@ -1,3 +1,4 @@ +mod bls12_381; mod compute_ed25519_pubkey; mod compute_keccak256_hash; mod compute_sha256_hash; @@ -18,6 +19,7 @@ mod visit_object; mod vm_ops; mod wasm_insn_exec; +pub use bls12_381::*; pub use compute_ed25519_pubkey::*; pub use compute_keccak256_hash::*; pub use compute_sha256_hash::*; diff --git a/soroban-env-host/src/cost_runner/experimental/bls12_381.rs b/soroban-env-host/src/cost_runner/experimental/bls12_381.rs new file mode 100644 index 000000000..509b478c4 --- /dev/null +++ b/soroban-env-host/src/cost_runner/experimental/bls12_381.rs @@ -0,0 +1,137 @@ +use ark_bls12_381::{Fq2, G1Affine, G2Affine}; + +use super::ExperimentalCostType::*; +use crate::{ + budget::CostTracker, + cost_runner::{CostRunner, CostType}, +}; +use std::hint::black_box; + +pub struct Bls12381G1AffineSerializeUncompressedRun; +pub struct Bls12381G2AffineSerializeUncompressedRun; +pub struct Bls12381G1AffineDeserializeUncompressedRun; +pub struct Bls12381G2AffineDeserializeUncompressedRun; +pub struct Bls12381Fp2DeserializeUncompressedRun; + +// ser/deser + +macro_rules! impl_ser_runner_for_bls { + ($runner: ident, $cost: ident, $units: literal, $sample: ident) => { + impl CostRunner for $runner { + const COST_TYPE: CostType = CostType::Experimental($cost); + + const RUN_ITERATIONS: u64 = 1; + + type SampleType = $sample; + + type RecycledType = (Option<$sample>, Option>); + + fn run_iter(host: &crate::Host, _iter: u64, sample: $sample) -> Self::RecycledType { + let mut buf = vec![0u8; 1000]; + let _ = host + .serialize_uncompressed_into_slice(&sample, &mut buf, $units, "test") + .unwrap(); + black_box((None, Some(buf))) + } + + fn run_baseline_iter( + host: &crate::Host, + _iter: u64, + sample: $sample, + ) -> Self::RecycledType { + black_box( + host.charge_budget(crate::xdr::ContractCostType::Int256AddSub, None) + .unwrap(), + ); + black_box((Some(sample), None)) + } + + fn get_tracker(_host: &crate::Host, _sample: &$sample) -> CostTracker { + CostTracker { + iterations: Self::RUN_ITERATIONS, + inputs: None, + cpu: 0, + mem: 0, + } + } + } + }; +} + +impl_ser_runner_for_bls!( + Bls12381G1AffineSerializeUncompressedRun, + Bls12381G1AffineSerializeUncompressed, + 2, + G1Affine +); +impl_ser_runner_for_bls!( + Bls12381G2AffineSerializeUncompressedRun, + Bls12381G2AffineSerializeUncompressed, + 4, + G2Affine +); + +macro_rules! impl_deser_runner_for_bls { + ($runner: ident, $cost: ident, $units: literal, $rt: ty) => { + impl CostRunner for $runner { + const COST_TYPE: CostType = CostType::Experimental($cost); + + const RUN_ITERATIONS: u64 = 1; + + type SampleType = Vec; + + type RecycledType = (Option, Option<$rt>); + + fn run_iter( + host: &crate::Host, + _iter: u64, + sample: Self::SampleType, + ) -> Self::RecycledType { + let res = host + .deserialize_uncompessed_no_validate(&sample, $units, "test") + .unwrap(); + black_box((None, Some(res))) + } + + fn run_baseline_iter( + host: &crate::Host, + _iter: u64, + sample: Self::SampleType, + ) -> Self::RecycledType { + black_box( + host.charge_budget(crate::xdr::ContractCostType::Int256AddSub, None) + .unwrap(), + ); + black_box((Some(sample), None)) + } + + fn get_tracker(_host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { + CostTracker { + iterations: Self::RUN_ITERATIONS, + inputs: None, + cpu: 0, + mem: 0, + } + } + } + }; +} + +impl_deser_runner_for_bls!( + Bls12381G1AffineDeserializeUncompressedRun, + Bls12381G1AffineDeserializeUncompressed, + 2, + G1Affine +); +impl_deser_runner_for_bls!( + Bls12381G2AffineDeserializeUncompressedRun, + Bls12381G2AffineDeserializeUncompressed, + 4, + G2Affine +); +impl_deser_runner_for_bls!( + Bls12381Fp2DeserializeUncompressedRun, + Bls12381Fp2DeserializeUncompressed, + 2, + Fq2 +); diff --git a/soroban-env-host/src/cost_runner/experimental/decode_secp256r1_sig.rs b/soroban-env-host/src/cost_runner/experimental/decode_secp256r1_sig.rs index 3a50a93b1..59fcd070e 100644 --- a/soroban-env-host/src/cost_runner/experimental/decode_secp256r1_sig.rs +++ b/soroban-env-host/src/cost_runner/experimental/decode_secp256r1_sig.rs @@ -27,7 +27,7 @@ impl CostRunner for DecodeSecp256r1SigRun { DecodeEcdsaCurve256SigRun::::run_iter(host, iter, sample) } - fn get_tracker(_host: &crate::Host) -> CostTracker { + fn get_tracker(_host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { CostTracker { iterations: Self::RUN_ITERATIONS, inputs: None, diff --git a/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256k1_verify.rs b/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256k1_verify.rs index 091dc78dd..00058380f 100644 --- a/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256k1_verify.rs +++ b/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256k1_verify.rs @@ -37,7 +37,7 @@ impl CostRunner for EcdsaSecp256k1VerifyRun { black_box(sample) } - fn get_tracker(_host: &crate::Host) -> CostTracker { + fn get_tracker(_host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { CostTracker { iterations: Self::RUN_ITERATIONS, inputs: None, diff --git a/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256r1_recover.rs b/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256r1_recover.rs index 7b6f44177..71234b832 100644 --- a/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256r1_recover.rs +++ b/soroban-env-host/src/cost_runner/experimental/ecdsa_secp256r1_recover.rs @@ -38,7 +38,7 @@ impl CostRunner for EcdsaSecp256r1RecoverRun { black_box(sample) } - fn get_tracker(_host: &crate::Host) -> CostTracker { + fn get_tracker(_host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { CostTracker { iterations: Self::RUN_ITERATIONS, inputs: None, diff --git a/soroban-env-host/src/cost_runner/experimental/ed25519_scalar_mut.rs b/soroban-env-host/src/cost_runner/experimental/ed25519_scalar_mut.rs index f71f911c3..95ed2b5d0 100644 --- a/soroban-env-host/src/cost_runner/experimental/ed25519_scalar_mut.rs +++ b/soroban-env-host/src/cost_runner/experimental/ed25519_scalar_mut.rs @@ -35,7 +35,7 @@ impl CostRunner for Ed25519ScalarMulRun { black_box(sample) } - fn get_tracker(_host: &crate::Host) -> CostTracker { + fn get_tracker(_host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { CostTracker { iterations: Self::RUN_ITERATIONS, inputs: None, diff --git a/soroban-env-host/src/cost_runner/experimental/mod.rs b/soroban-env-host/src/cost_runner/experimental/mod.rs index 1817f508c..66260672a 100644 --- a/soroban-env-host/src/cost_runner/experimental/mod.rs +++ b/soroban-env-host/src/cost_runner/experimental/mod.rs @@ -1,3 +1,4 @@ +mod bls12_381; mod decode_secp256r1_sig; mod ecdsa_secp256k1_verify; mod ecdsa_secp256r1_recover; @@ -5,6 +6,7 @@ mod ed25519_scalar_mut; mod read_xdr; mod sec1_decode_point_compressed; +pub use bls12_381::*; pub use decode_secp256r1_sig::*; pub use ecdsa_secp256k1_verify::*; pub use ecdsa_secp256r1_recover::*; @@ -23,6 +25,11 @@ pub enum ExperimentalCostType { Sec1DecodePointCompressed, DecodeSecp256r1Signature, EcdsaSecp256k1Verify, + Bls12381G1AffineDeserializeUncompressed, + Bls12381G1AffineSerializeUncompressed, + Bls12381G2AffineDeserializeUncompressed, + Bls12381G2AffineSerializeUncompressed, + Bls12381Fp2DeserializeUncompressed, } impl Name for ExperimentalCostType { @@ -36,6 +43,21 @@ impl Name for ExperimentalCostType { ExperimentalCostType::Sec1DecodePointCompressed => "Sec1DecodePointCompressed", ExperimentalCostType::DecodeSecp256r1Signature => "DecodeSecp256r1Signature", ExperimentalCostType::EcdsaSecp256k1Verify => "EcdsaSecp256k1Verify", + ExperimentalCostType::Bls12381G1AffineDeserializeUncompressed => { + "Bls12381G1AffineDeserializeUncompressed" + } + ExperimentalCostType::Bls12381G1AffineSerializeUncompressed => { + "Bls12381G1AffineSerializeUncompressed" + } + ExperimentalCostType::Bls12381G2AffineDeserializeUncompressed => { + "Bls12381G2AffineDeserializeUncompressed" + } + ExperimentalCostType::Bls12381G2AffineSerializeUncompressed => { + "Bls12381G2AffineSerializeUncompressed" + } + ExperimentalCostType::Bls12381Fp2DeserializeUncompressed => { + "Bls12381Fp2DeserializeUncompressed" + } } } } diff --git a/soroban-env-host/src/cost_runner/experimental/read_xdr.rs b/soroban-env-host/src/cost_runner/experimental/read_xdr.rs index 80639f508..7aeb809cf 100644 --- a/soroban-env-host/src/cost_runner/experimental/read_xdr.rs +++ b/soroban-env-host/src/cost_runner/experimental/read_xdr.rs @@ -32,7 +32,7 @@ impl CostRunner for ReadXdrByteArrayRun { black_box((None, sample)) } - fn get_tracker(host: &crate::Host) -> CostTracker { + fn get_tracker(host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { // internally this is still charged under `ValDeser` host.as_budget().get_tracker(ValDeser).unwrap() } diff --git a/soroban-env-host/src/cost_runner/experimental/sec1_decode_point_compressed.rs b/soroban-env-host/src/cost_runner/experimental/sec1_decode_point_compressed.rs index e5737ed28..036424fd2 100644 --- a/soroban-env-host/src/cost_runner/experimental/sec1_decode_point_compressed.rs +++ b/soroban-env-host/src/cost_runner/experimental/sec1_decode_point_compressed.rs @@ -30,7 +30,7 @@ impl CostRunner for Sec1DecodePointCompressedRun { Sec1DecodePointUncompressedRun::run_iter(host, iter, sample) } - fn get_tracker(_host: &crate::Host) -> CostTracker { + fn get_tracker(_host: &crate::Host, _sample: &Self::SampleType) -> CostTracker { CostTracker { iterations: Self::RUN_ITERATIONS, inputs: None, diff --git a/soroban-env-host/src/cost_runner/runner.rs b/soroban-env-host/src/cost_runner/runner.rs index 6a7e218e5..b673128ea 100644 --- a/soroban-env-host/src/cost_runner/runner.rs +++ b/soroban-env-host/src/cost_runner/runner.rs @@ -70,7 +70,7 @@ pub trait CostRunner: Sized { /// if overridden, there is a risk of the computed input being diverged from the /// actual input from the host's perspective. So use it carefully. This should be /// after the `run`, outside of the CPU-and-memory tracking machineary. - fn get_tracker(host: &Host) -> CostTracker { + fn get_tracker(host: &Host, _sample: &Self::SampleType) -> CostTracker { match Self::COST_TYPE { CostType::Contract(ct) => host.as_budget().get_tracker(ct).unwrap(), CostType::Experimental(_) => { diff --git a/soroban-env-host/src/cost_runner/util.rs b/soroban-env-host/src/cost_runner/util.rs index 0542170ce..90e4eccbf 100644 --- a/soroban-env-host/src/cost_runner/util.rs +++ b/soroban-env-host/src/cost_runner/util.rs @@ -48,3 +48,102 @@ impl Host { )?)) } } + +#[macro_export] +macro_rules! impl_const_cost_runner_for_bls_consume_sample { + ($runner: ident, $cost: ident, $host_fn: ident, $sample: ident, $rt: ty, $($arg: ident),*) => { + impl CostRunner for $runner { + const COST_TYPE: CostType = CostType::Contract($cost); + + const RUN_ITERATIONS: u64 = 1; + + type SampleType = $sample; + + type RecycledType = (Option<$sample>, Option<$rt>); + + fn run_iter(host: &Host, _iter: u64, sample: $sample) -> Self::RecycledType { + let $sample($( $arg ),*) = sample; + let res = host.$host_fn($($arg),*).unwrap(); + black_box((None, Some(res))) + } + + fn run_baseline_iter( + host: &Host, + _iter: u64, + sample: $sample, + ) -> Self::RecycledType { + black_box( + host.charge_budget($cost, None) + .unwrap(), + ); + black_box((Some(sample), None)) + } + } + }; +} + +#[macro_export] +macro_rules! impl_lin_cost_runner_for_bls_deref_sample { + ($runner: ident, $cost: ident, $host_fn: ident, $sample: ident, $rt: ty, $($arg: ident),*) => { + impl CostRunner for $runner { + const COST_TYPE: CostType = CostType::Contract($cost); + + const RUN_ITERATIONS: u64 = 100; + + type SampleType = $sample; + + type RecycledType = ($sample, Option<$rt>); + + fn run_iter(host: &Host, _iter: u64, mut sample: $sample) -> Self::RecycledType { + let $sample($( $arg ),*) = &mut sample; + let res = host.$host_fn($($arg),*).unwrap(); + black_box((sample, Some(res))) + } + + fn run_baseline_iter( + host: &Host, + _iter: u64, + sample: $sample, + ) -> Self::RecycledType { + black_box( + host.charge_budget($cost, Some(1)) + .unwrap(), + ); + black_box((sample, None)) + } + } + }; +} + +#[macro_export] +macro_rules! impl_const_cost_runner_for_bls_deref_sample { + ($runner: ident, $cost: ident, $host_fn: ident, $sample: ident, $rt: ty, $($arg: ident),*) => { + impl CostRunner for $runner { + const COST_TYPE: CostType = CostType::Contract($cost); + + const RUN_ITERATIONS: u64 = 1; + + type SampleType = $sample; + + type RecycledType = (Option<$sample>, Option<$rt>); + + fn run_iter(host: &Host, _iter: u64, mut sample: $sample) -> Self::RecycledType { + let $sample($( $arg ),*) = &mut sample; + let res = host.$host_fn($($arg),*).unwrap(); + black_box((Some(sample), Some(res))) + } + + fn run_baseline_iter( + host: &Host, + _iter: u64, + sample: $sample, + ) -> Self::RecycledType { + black_box( + host.charge_budget($cost, None) + .unwrap(), + ); + black_box((Some(sample), None)) + } + } + }; +}