diff --git a/Cargo.lock b/Cargo.lock index f8532c301..23307ecaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -841,6 +841,7 @@ dependencies = [ "num_cpus", "rayon", "sha2 0.10.8", + "siphasher", "threadpool", ] @@ -1224,7 +1225,6 @@ dependencies = [ "once_cell", "rand", "rayon", - "siphasher", "smallvec", ] diff --git a/arkworks/Cargo.toml b/arkworks/Cargo.toml index 28bf5438e..c73c9671f 100644 --- a/arkworks/Cargo.toml +++ b/arkworks/Cargo.toml @@ -25,7 +25,8 @@ rand = { version = "0.8.5" } [features] default = [ "std", - "rand" + "rand", + "bgmw" ] std = [ "ark-ff/std", "ark-ec/std", "ark-poly/std", "ark-std/std", diff --git a/arkworks/src/eip_4844.rs b/arkworks/src/eip_4844.rs index 6f1ab5efc..fb8c62284 100644 --- a/arkworks/src/eip_4844.rs +++ b/arkworks/src/eip_4844.rs @@ -1,15 +1,15 @@ extern crate alloc; use crate::kzg_proofs::{FFTSettings, KZGSettings}; -use crate::kzg_types::{ArkFr, ArkG1, ArkG2}; +use crate::kzg_types::{ArkFp, ArkFr, ArkG1, ArkG1Affine, ArkG2}; use blst::{blst_fr, blst_p1, blst_p2}; use kzg::common_utils::reverse_bit_order; use kzg::eip_4844::{ blob_to_kzg_commitment_rust, compute_blob_kzg_proof_rust, compute_kzg_proof_rust, load_trusted_setup_rust, verify_blob_kzg_proof_batch_rust, verify_blob_kzg_proof_rust, verify_kzg_proof_rust, Blob, Bytes32, Bytes48, CKZGSettings, KZGCommitment, KZGProof, - BYTES_PER_FIELD_ELEMENT, BYTES_PER_G1, BYTES_PER_G2, C_KZG_RET, C_KZG_RET_BADARGS, - C_KZG_RET_OK, FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G1_POINTS, + PrecomputationTableManager, BYTES_PER_FIELD_ELEMENT, BYTES_PER_G1, BYTES_PER_G2, C_KZG_RET, + C_KZG_RET_BADARGS, C_KZG_RET_OK, FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G1_POINTS, TRUSTED_SETUP_NUM_G2_POINTS, }; use kzg::{cfg_into_iter, Fr, G1}; @@ -28,6 +28,9 @@ use rayon::prelude::*; #[cfg(feature = "std")] use kzg::eip_4844::load_trusted_setup_string; +static mut PRECOMPUTATION_TABLES: PrecomputationTableManager = + PrecomputationTableManager::new(); + #[cfg(feature = "std")] pub fn load_trusted_setup_filename_rust(filepath: &str) -> Result { let mut file = File::open(filepath).map_err(|_| "Unable to open file".to_string())?; @@ -178,9 +181,14 @@ pub unsafe extern "C" fn load_trusted_setup( let g1_bytes = core::slice::from_raw_parts(g1_bytes, n1 * BYTES_PER_G1); let g2_bytes = core::slice::from_raw_parts(g2_bytes, n2 * BYTES_PER_G2); TRUSTED_SETUP_NUM_G1_POINTS = g1_bytes.len() / BYTES_PER_G1; - let settings = handle_ckzg_badargs!(load_trusted_setup_rust(g1_bytes, g2_bytes)); + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust(g1_bytes, g2_bytes)); + + let c_settings = kzg_settings_to_c(&settings); + + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); + + *out = c_settings; - *out = kzg_settings_to_c(&settings); C_KZG_RET_OK } @@ -202,12 +210,17 @@ pub unsafe extern "C" fn load_trusted_setup_file( // deallocate its KZGSettings pointer when no exception is thrown). return C_KZG_RET_BADARGS; } - let settings = handle_ckzg_badargs!(load_trusted_setup_rust( + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust( g1_bytes.as_slice(), g2_bytes.as_slice() )); - *out = kzg_settings_to_c(&settings); + let c_settings = kzg_settings_to_c(&settings); + + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); + + *out = c_settings; + C_KZG_RET_OK } @@ -218,6 +231,8 @@ pub unsafe extern "C" fn free_trusted_setup(s: *mut CKZGSettings) { return; } + PRECOMPUTATION_TABLES.remove_precomputation(&*s); + let max_width = (*s).max_width as usize; let roots = Box::from_raw(core::slice::from_raw_parts_mut( (*s).roots_of_unity, diff --git a/arkworks/src/kzg_proofs.rs b/arkworks/src/kzg_proofs.rs index 9d74277a7..d39b75038 100644 --- a/arkworks/src/kzg_proofs.rs +++ b/arkworks/src/kzg_proofs.rs @@ -1,8 +1,11 @@ #![allow(non_camel_case_types)] + +extern crate alloc; use super::utils::{blst_poly_into_pc_poly, PolyData}; use crate::consts::{G1_GENERATOR, G2_GENERATOR}; use crate::kzg_types::{ArkFp, ArkFr, ArkG1Affine}; use crate::kzg_types::{ArkFr as BlstFr, ArkG1, ArkG2}; +use alloc::sync::Arc; use ark_bls12_381::Bls12_381; use ark_ec::pairing::Pairing; use ark_ec::CurveGroup; @@ -46,7 +49,7 @@ pub struct KZGSettings { pub fs: FFTSettings, pub secret_g1: Vec, pub secret_g2: Vec, - pub precomputation: Option>, + pub precomputation: Option>>, } pub fn generate_trusted_setup(len: usize, secret: [u8; 32usize]) -> (Vec, Vec) { diff --git a/arkworks/src/kzg_types.rs b/arkworks/src/kzg_types.rs index 57e499ea2..1d77111b3 100644 --- a/arkworks/src/kzg_types.rs +++ b/arkworks/src/kzg_types.rs @@ -34,6 +34,9 @@ use kzg::{ }; use std::ops::{AddAssign, Mul, Neg, Sub}; +extern crate alloc; +use alloc::sync::Arc; + fn bytes_be_to_uint64(inp: &[u8]) -> u64 { u64::from_be_bytes(inp.try_into().expect("Input wasn't 8 elements...")) } @@ -630,7 +633,7 @@ impl KZGSettings Option<&PrecomputationTable> { - self.precomputation.as_ref() + self.precomputation.as_ref().map(|v| v.as_ref()) } } diff --git a/blst/Cargo.toml b/blst/Cargo.toml index 7d63d695c..61f8fdc71 100644 --- a/blst/Cargo.toml +++ b/blst/Cargo.toml @@ -12,7 +12,6 @@ rand = { version = "0.8.5", optional = true } rayon = { version = "1.8.0", optional = true } smallvec = { version = "1.11.1", features = ["const_generics"] } hex = { version = "0.4.3", default-features = false, features = ["alloc"] } -siphasher = { version = "1.0.0", default-features = false } [dev-dependencies] criterion = "0.5.1" @@ -23,6 +22,7 @@ rand = "0.8.5" default = [ "std", "rand", + "bgmw" ] std = [ "hex/std", diff --git a/blst/src/eip_4844.rs b/blst/src/eip_4844.rs index 6bd505c4e..b7556bf36 100644 --- a/blst/src/eip_4844.rs +++ b/blst/src/eip_4844.rs @@ -1,23 +1,18 @@ extern crate alloc; use alloc::boxed::Box; -use alloc::collections::BTreeMap; use alloc::string::String; -use alloc::sync::Arc; use alloc::vec::Vec; -use core::hash::{Hash, Hasher}; use core::ptr::null_mut; use kzg::common_utils::reverse_bit_order; use kzg::eip_4844::{ blob_to_kzg_commitment_rust, compute_blob_kzg_proof_rust, compute_kzg_proof_rust, load_trusted_setup_rust, verify_blob_kzg_proof_batch_rust, verify_blob_kzg_proof_rust, - verify_kzg_proof_rust, + verify_kzg_proof_rust, PrecomputationTableManager, }; -use kzg::msm::precompute::PrecomputationTable; use kzg::{cfg_into_iter, Fr, G1}; #[cfg(feature = "std")] use libc::FILE; -use siphasher::sip::SipHasher; #[cfg(feature = "std")] use std::fs::File; #[cfg(feature = "std")] @@ -45,43 +40,8 @@ use crate::types::kzg_settings::FsKZGSettings; #[cfg(feature = "parallel")] use rayon::prelude::*; -struct PrecomputationTableManager { - tables: BTreeMap>>, -} - -impl PrecomputationTableManager { - pub const fn new() -> Self { - Self { - tables: BTreeMap::new(), - } - } - - pub fn save_precomputation(&mut self, settings: &mut FsKZGSettings, c_settings: &CKZGSettings) { - if let Some(precomputation) = settings.precomputation.take() { - self.tables - .insert(Self::get_key(c_settings), precomputation); - } - } - - pub fn remove_precomputation(&mut self, c_settings: &CKZGSettings) { - self.tables.remove(&Self::get_key(c_settings)); - } - - pub fn get_precomputation( - &self, - c_settings: &CKZGSettings, - ) -> Option>> { - self.tables.get(&Self::get_key(c_settings)).cloned() - } - - fn get_key(settings: &CKZGSettings) -> u64 { - let mut hasher = SipHasher::new(); - settings.g1_values.hash(&mut hasher); - hasher.finish() - } -} - -static mut PRECOMPUTATION_TABLES: PrecomputationTableManager = PrecomputationTableManager::new(); +static mut PRECOMPUTATION_TABLES: PrecomputationTableManager = + PrecomputationTableManager::new(); #[cfg(feature = "std")] pub fn load_trusted_setup_filename_rust(filepath: &str) -> Result { @@ -236,7 +196,7 @@ pub unsafe extern "C" fn load_trusted_setup( let c_settings = kzg_settings_to_c(&settings); - PRECOMPUTATION_TABLES.save_precomputation(&mut settings, &c_settings); + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); *out = c_settings; C_KZG_RET_OK @@ -267,7 +227,7 @@ pub unsafe extern "C" fn load_trusted_setup_file( let c_settings = kzg_settings_to_c(&settings); - PRECOMPUTATION_TABLES.save_precomputation(&mut settings, &c_settings); + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); *out = c_settings; diff --git a/constantine/Cargo.toml b/constantine/Cargo.toml index 6078fdaf8..c0b90993e 100644 --- a/constantine/Cargo.toml +++ b/constantine/Cargo.toml @@ -25,6 +25,7 @@ rand = "0.8.5" default = [ "std", "rand", + "bgmw" ] std = [ "hex/std", diff --git a/constantine/src/eip_4844.rs b/constantine/src/eip_4844.rs index 2dd70889f..39535367a 100644 --- a/constantine/src/eip_4844.rs +++ b/constantine/src/eip_4844.rs @@ -22,14 +22,16 @@ use std::io::Read; use kzg::eip_4844::load_trusted_setup_string; use kzg::eip_4844::{ - Blob, Bytes32, Bytes48, CKZGSettings, KZGCommitment, KZGProof, BYTES_PER_FIELD_ELEMENT, - BYTES_PER_G1, BYTES_PER_G2, C_KZG_RET, C_KZG_RET_BADARGS, C_KZG_RET_OK, - FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G1_POINTS, TRUSTED_SETUP_NUM_G2_POINTS, + Blob, Bytes32, Bytes48, CKZGSettings, KZGCommitment, KZGProof, PrecomputationTableManager, + BYTES_PER_FIELD_ELEMENT, BYTES_PER_G1, BYTES_PER_G2, C_KZG_RET, C_KZG_RET_BADARGS, + C_KZG_RET_OK, FIELD_ELEMENTS_PER_BLOB, TRUSTED_SETUP_NUM_G1_POINTS, + TRUSTED_SETUP_NUM_G2_POINTS, }; use crate::types::fft_settings::CtFFTSettings; +use crate::types::fp::CtFp; use crate::types::fr::CtFr; -use crate::types::g1::CtG1; +use crate::types::g1::{CtG1, CtG1Affine}; use crate::types::g2::CtG2; use crate::types::kzg_settings::CtKZGSettings; @@ -37,6 +39,9 @@ use crate::types::kzg_settings::CtKZGSettings; #[cfg(feature = "parallel")] use rayon::prelude::*; +static mut PRECOMPUTATION_TABLES: PrecomputationTableManager = + PrecomputationTableManager::new(); + #[cfg(feature = "std")] pub fn load_trusted_setup_filename_rust(filepath: &str) -> Result { let mut file = File::open(filepath).map_err(|_| "Unable to open file".to_string())?; @@ -186,9 +191,14 @@ pub unsafe extern "C" fn load_trusted_setup( let g1_bytes = core::slice::from_raw_parts(g1_bytes, n1 * BYTES_PER_G1); let g2_bytes = core::slice::from_raw_parts(g2_bytes, n2 * BYTES_PER_G2); TRUSTED_SETUP_NUM_G1_POINTS = g1_bytes.len() / BYTES_PER_G1; - let settings = handle_ckzg_badargs!(load_trusted_setup_rust(g1_bytes, g2_bytes)); + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust(g1_bytes, g2_bytes)); + + let c_settings = kzg_settings_to_c(&settings); + + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); + + *out = c_settings; - *out = kzg_settings_to_c(&settings); C_KZG_RET_OK } @@ -210,12 +220,17 @@ pub unsafe extern "C" fn load_trusted_setup_file( // deallocate its KZGSettings pointer when no exception is thrown). return C_KZG_RET_BADARGS; } - let settings = handle_ckzg_badargs!(load_trusted_setup_rust( + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust( g1_bytes.as_slice(), g2_bytes.as_slice() )); - *out = kzg_settings_to_c(&settings); + let c_settings = kzg_settings_to_c(&settings); + + PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); + + *out = c_settings; + C_KZG_RET_OK } @@ -251,6 +266,8 @@ pub unsafe extern "C" fn free_trusted_setup(s: *mut CKZGSettings) { return; } + PRECOMPUTATION_TABLES.remove_precomputation(&*s); + let max_width = (*s).max_width as usize; let roots = Box::from_raw(core::slice::from_raw_parts_mut( (*s).roots_of_unity, diff --git a/constantine/src/types/kzg_settings.rs b/constantine/src/types/kzg_settings.rs index 0f2ff600d..e0cfc042a 100644 --- a/constantine/src/types/kzg_settings.rs +++ b/constantine/src/types/kzg_settings.rs @@ -1,6 +1,7 @@ extern crate alloc; use alloc::string::String; +use alloc::sync::Arc; use alloc::vec::Vec; use kzg::msm::precompute::{precompute, PrecomputationTable}; @@ -22,7 +23,7 @@ pub struct CtKZGSettings { pub fs: CtFFTSettings, pub secret_g1: Vec, pub secret_g2: Vec, - pub precomputation: Option>, + pub precomputation: Option>>, } impl KZGSettings for CtKZGSettings { @@ -36,7 +37,7 @@ impl KZGSettings for secret_g1: secret_g1.to_vec(), secret_g2: secret_g2.to_vec(), fs: fft_settings.clone(), - precomputation: precompute(secret_g1).ok().flatten(), + precomputation: precompute(secret_g1).ok().flatten().map(Arc::new), }) } @@ -202,6 +203,6 @@ impl KZGSettings for } fn get_precomputation(&self) -> Option<&PrecomputationTable> { - self.precomputation.as_ref() + self.precomputation.as_ref().map(|v| v.as_ref()) } } diff --git a/kzg/Cargo.toml b/kzg/Cargo.toml index 651954747..ad5fb2524 100644 --- a/kzg/Cargo.toml +++ b/kzg/Cargo.toml @@ -9,6 +9,7 @@ sha2 = { version = "0.10.6", default-features = false } num_cpus = { version = "1.16.0", optional = true } rayon = { version = "1.8.0", optional = true } threadpool = { version = "^1.8.1", optional = true } +siphasher = { version = "1.0.0", default-features = false } [features] default = [ @@ -22,7 +23,8 @@ parallel = [ "dep:threadpool" ] std = [ - "sha2/std" + "sha2/std", + "siphasher/std" ] rand = [] arkmsm = [] diff --git a/kzg/src/eip_4844.rs b/kzg/src/eip_4844.rs index 260094985..388f6dbf1 100644 --- a/kzg/src/eip_4844.rs +++ b/kzg/src/eip_4844.rs @@ -1,17 +1,23 @@ #![allow(non_camel_case_types)] extern crate alloc; +use alloc::collections::BTreeMap; use alloc::format; use alloc::string::String; use alloc::string::ToString; +use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; pub use blst::{blst_fr, blst_p1, blst_p2}; use core::ffi::c_uint; +use core::hash::Hash; +use core::hash::Hasher; use sha2::{Digest, Sha256}; +use siphasher::sip::SipHasher; use crate::common_utils::reverse_bit_order; +use crate::msm::precompute::PrecomputationTable; use crate::G1Affine; use crate::G1Fp; use crate::G1GetFp; @@ -98,6 +104,59 @@ pub struct CKZGSettings { pub g2_values: *mut blst_p2, } +pub struct PrecomputationTableManager +where + TFr: Fr, + TG1: G1 + G1Mul + G1GetFp, + TG1Fp: G1Fp, + TG1Affine: G1Affine, +{ + tables: BTreeMap>>, +} + +impl PrecomputationTableManager +where + TFr: Fr, + TG1: G1 + G1Mul + G1GetFp, + TG1Fp: G1Fp, + TG1Affine: G1Affine, +{ + pub const fn new() -> Self { + Self { + tables: BTreeMap::new(), + } + } + + pub fn save_precomputation( + &mut self, + precomputation: Option>>, + c_settings: &CKZGSettings, + ) { + if let Some(precomputation) = precomputation { + self.tables + .insert(Self::get_key(c_settings), precomputation); + } + } + + pub fn remove_precomputation(&mut self, c_settings: &CKZGSettings) { + self.tables.remove(&Self::get_key(c_settings)); + } + + pub fn get_precomputation( + &self, + c_settings: &CKZGSettings, + ) -> Option>> { + self.tables.get(&Self::get_key(c_settings)).cloned() + } + + fn get_key(settings: &CKZGSettings) -> u64 { + let mut hasher = SipHasher::new(); + + settings.g1_values.hash(&mut hasher); + hasher.finish() + } +} + ////////////////////////////// Utility functions for EIP-4844 ////////////////////////////// pub fn load_trusted_setup_string(contents: &str) -> Result<(Vec, Vec), String> { diff --git a/kzg/src/msm/bgmw.rs b/kzg/src/msm/bgmw.rs index 4af667b6d..29fbfcb18 100644 --- a/kzg/src/msm/bgmw.rs +++ b/kzg/src/msm/bgmw.rs @@ -298,7 +298,15 @@ impl< } #[cfg(not(feature = "parallel"))] - pippenger_window_size(npoints) + { + let n_exponent = npoints.trailing_zeros(); + + // TODO: experiment with different q exponents, to find optimal + match n_exponent { + 12 => 13, // this value is picked from https://github.com/LuoGuiwen/MSM_blst/blob/2e098f09f07969ac3191406976be6d1c197100f2/ches_config_files/config_file_n_exp_12.h#L17 + _ => pippenger_window_size(npoints), // default to pippenger window size. This is not optimal window size, but still better than simple pippenger + } + } } }