From e14713caa0296db1a3691df5a98d818d81f52a08 Mon Sep 17 00:00:00 2001 From: Aleksandras Sukelovic Date: Sat, 12 Oct 2024 19:19:44 +0300 Subject: [PATCH 1/2] Implemented eip_7594 in constantine crate --- blst/src/utils.rs | 2 +- constantine/benches/eip_4844.rs | 5 +- constantine/src/data_availability_sampling.rs | 4 +- constantine/src/eip_4844.rs | 244 +++++++----------- constantine/src/eip_7594.rs | 38 +++ constantine/src/fft_fr.rs | 2 +- constantine/src/fft_g1.rs | 2 +- constantine/src/lib.rs | 1 + .../src/mixed_kzg/mixed_kzg_settings.rs | 57 ++-- constantine/src/types/fft_settings.rs | 36 +-- constantine/src/types/fk20_multi_settings.rs | 2 +- constantine/src/types/fk20_single_settings.rs | 2 +- constantine/src/types/g1.rs | 7 +- constantine/src/types/kzg_settings.rs | 108 ++++++-- constantine/src/utils.rs | 205 ++++++++++++++- constantine/src/zero_poly.rs | 4 +- constantine/tests/eip_7594.rs | 40 +++ constantine/tests/fk20_proofs.rs | 6 + constantine/tests/kzg_proofs.rs | 4 + constantine/tests/local_tests/local_consts.rs | 8 +- kzg-bench/src/tests/eip_7594.rs | 2 +- .../valid_short_hex/trusted_setup_fixture.txt | 2 +- kzg/src/eip_4844.rs | 1 - kzg/src/eip_7594.rs | 2 +- 24 files changed, 549 insertions(+), 235 deletions(-) create mode 100644 constantine/src/eip_7594.rs create mode 100644 constantine/tests/eip_7594.rs diff --git a/blst/src/utils.rs b/blst/src/utils.rs index e2c3ea558..b1263c55b 100644 --- a/blst/src/utils.rs +++ b/blst/src/utils.rs @@ -99,7 +99,7 @@ pub(crate) fn fft_settings_to_rust( Ok(FsFFTSettings { max_width: FIELD_ELEMENTS_PER_EXT_BLOB, - root_of_unity: roots_of_unity[0], + root_of_unity: roots_of_unity[1], roots_of_unity, brp_roots_of_unity, reverse_roots_of_unity, diff --git a/constantine/benches/eip_4844.rs b/constantine/benches/eip_4844.rs index a9d940e01..cad3bd228 100644 --- a/constantine/benches/eip_4844.rs +++ b/constantine/benches/eip_4844.rs @@ -1,8 +1,8 @@ use criterion::{criterion_group, criterion_main, Criterion}; use kzg::eip_4844::{ blob_to_kzg_commitment_rust, bytes_to_blob, compute_blob_kzg_proof_rust, - compute_cells_and_kzg_proofs_rust, compute_kzg_proof_rust, verify_blob_kzg_proof_batch_rust, - verify_blob_kzg_proof_rust, verify_kzg_proof_rust, + compute_kzg_proof_rust, verify_blob_kzg_proof_batch_rust, verify_blob_kzg_proof_rust, + verify_kzg_proof_rust, }; use kzg_bench::benches::eip_4844::bench_eip_4844; use rust_kzg_constantine::{ @@ -27,7 +27,6 @@ fn bench_eip_4844_(c: &mut Criterion) { &compute_kzg_proof_rust, &verify_kzg_proof_rust, &compute_blob_kzg_proof_rust, - &compute_cells_and_kzg_proofs_rust, &verify_blob_kzg_proof_rust, &verify_blob_kzg_proof_batch_rust, ); diff --git a/constantine/src/data_availability_sampling.rs b/constantine/src/data_availability_sampling.rs index afad1efbe..8d6659b3e 100644 --- a/constantine/src/data_availability_sampling.rs +++ b/constantine/src/data_availability_sampling.rs @@ -20,7 +20,7 @@ impl CtFFTSettings { Ordering::Equal => { let x = evens[0].add(&evens[1]); let y = evens[0].sub(&evens[1]); - let y_times_root = y.mul(&self.expanded_roots_of_unity[stride]); + let y_times_root = y.mul(&self.roots_of_unity[stride]); evens[0] = x.add(&y_times_root); evens[1] = x.sub(&y_times_root); @@ -64,7 +64,7 @@ impl CtFFTSettings { for i in 0..half { let x = evens[i]; let y = evens[half + i]; - let y_times_root: CtFr = y.mul(&self.expanded_roots_of_unity[(1 + 2 * i) * stride]); + let y_times_root: CtFr = y.mul(&self.roots_of_unity[(1 + 2 * i) * stride]); evens[i] = x.add(&y_times_root); evens[half + i] = x.sub(&y_times_root); diff --git a/constantine/src/eip_4844.rs b/constantine/src/eip_4844.rs index 39535367a..f4972fc13 100644 --- a/constantine/src/eip_4844.rs +++ b/constantine/src/eip_4844.rs @@ -3,12 +3,11 @@ extern crate alloc; use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; -use core::ptr::null_mut; -use kzg::common_utils::reverse_bit_order; +use core::ptr::{self}; 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, FIELD_ELEMENTS_PER_CELL, FIELD_ELEMENTS_PER_EXT_BLOB, }; use kzg::{cfg_into_iter, Fr, G1}; #[cfg(feature = "std")] @@ -23,18 +22,15 @@ use kzg::eip_4844::load_trusted_setup_string; use kzg::eip_4844::{ 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, + BYTES_PER_G1, 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, CtG1Affine}; -use crate::types::g2::CtG2; -use crate::types::kzg_settings::CtKZGSettings; +use crate::utils::{deserialize_blob, kzg_settings_to_c, kzg_settings_to_rust}; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -43,111 +39,17 @@ static mut PRECOMPUTATION_TABLES: PrecomputationTableManager Result { +pub fn load_trusted_setup_filename_rust( + filepath: &str, +) -> Result { let mut file = File::open(filepath).map_err(|_| "Unable to open file".to_string())?; let mut contents = String::new(); file.read_to_string(&mut contents) .map_err(|_| "Unable to read file".to_string())?; - let (g1_bytes, g2_bytes) = load_trusted_setup_string(&contents)?; - load_trusted_setup_rust(g1_bytes.as_slice(), g2_bytes.as_slice()) -} - -fn fft_settings_to_rust(c_settings: *const CKZGSettings) -> Result { - let settings = unsafe { &*c_settings }; - - let roots_of_unity = unsafe { - core::slice::from_raw_parts(settings.roots_of_unity, settings.max_width as usize) - .iter() - .map(|r| CtFr::from_blst_fr(*r)) - .collect::>() - }; - let mut expanded_roots_of_unity = roots_of_unity.clone(); - reverse_bit_order(&mut expanded_roots_of_unity)?; - expanded_roots_of_unity.push(CtFr::one()); - let mut reverse_roots_of_unity = expanded_roots_of_unity.clone(); - reverse_roots_of_unity.reverse(); - - let mut first_root = expanded_roots_of_unity[1]; - let first_root_arr = [first_root; 1]; - first_root = first_root_arr[0]; - - Ok(CtFFTSettings { - max_width: settings.max_width as usize, - root_of_unity: first_root, - expanded_roots_of_unity, - reverse_roots_of_unity, - roots_of_unity, - }) -} - -fn kzg_settings_to_rust(c_settings: &CKZGSettings) -> Result { - let secret_g1 = unsafe { - core::slice::from_raw_parts(c_settings.g1_values, TRUSTED_SETUP_NUM_G1_POINTS) - .iter() - .map(|r| CtG1::from_blst_p1(*r)) - .collect::>() - }; - Ok(CtKZGSettings { - fs: fft_settings_to_rust(c_settings)?, - secret_g1, - secret_g2: unsafe { - core::slice::from_raw_parts(c_settings.g2_values, TRUSTED_SETUP_NUM_G2_POINTS) - .iter() - .map(|r| CtG2::from_blst_p2(*r)) - .collect::>() - }, - precomputation: None, - }) -} - -fn kzg_settings_to_c(rust_settings: &CtKZGSettings) -> CKZGSettings { - let g1_val = rust_settings - .secret_g1 - .iter() - .map(|r| r.to_blst_p1()) - .collect::>(); - let g1_val = Box::new(g1_val); - let g2_val = rust_settings - .secret_g2 - .iter() - .map(|r| r.to_blst_p2()) - .collect::>(); - let x = g2_val.into_boxed_slice(); - let stat_ref = Box::leak(x); - let v = Box::into_raw(g1_val); - - let roots_of_unity = Box::new( - rust_settings - .fs - .roots_of_unity - .iter() - .map(|r| r.to_blst_fr()) - .collect::>(), - ); - - CKZGSettings { - max_width: rust_settings.fs.max_width as u64, - roots_of_unity: unsafe { (*Box::into_raw(roots_of_unity)).as_mut_ptr() }, - g1_values: unsafe { (*v).as_mut_ptr() }, - g2_values: stat_ref.as_mut_ptr(), - } -} - -unsafe fn deserialize_blob(blob: *const Blob) -> Result, C_KZG_RET> { - (*blob) - .bytes - .chunks(BYTES_PER_FIELD_ELEMENT) - .map(|chunk| { - let mut bytes = [0u8; BYTES_PER_FIELD_ELEMENT]; - bytes.copy_from_slice(chunk); - if let Ok(result) = CtFr::from_bytes(&bytes) { - Ok(result) - } else { - Err(C_KZG_RET_BADARGS) - } - }) - .collect::, C_KZG_RET>>() + let (g1_monomial_bytes, g1_lagrange_bytes, g2_monomial_bytes) = + load_trusted_setup_string(&contents)?; + load_trusted_setup_rust(&g1_monomial_bytes, &g1_lagrange_bytes, &g2_monomial_bytes) } macro_rules! handle_ckzg_badargs { @@ -183,22 +85,32 @@ pub unsafe extern "C" fn blob_to_kzg_commitment( #[no_mangle] pub unsafe extern "C" fn load_trusted_setup( out: *mut CKZGSettings, - g1_bytes: *const u8, - n1: usize, - g2_bytes: *const u8, - n2: usize, + g1_monomial_bytes: *const u8, + num_g1_monomial_bytes: u64, + g1_lagrange_bytes: *const u8, + num_g1_lagrange_bytes: u64, + g2_monomial_bytes: *const u8, + num_g2_monomial_bytes: u64, + _precompute: u64, ) -> C_KZG_RET { - 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 mut settings = handle_ckzg_badargs!(load_trusted_setup_rust(g1_bytes, g2_bytes)); + let g1_monomial_bytes = + core::slice::from_raw_parts(g1_monomial_bytes, num_g1_monomial_bytes as usize); + let g1_lagrange_bytes = + core::slice::from_raw_parts(g1_lagrange_bytes, num_g1_lagrange_bytes as usize); + let g2_monomial_bytes = + core::slice::from_raw_parts(g2_monomial_bytes, num_g2_monomial_bytes as usize); + TRUSTED_SETUP_NUM_G1_POINTS = num_g1_monomial_bytes as usize / BYTES_PER_G1; + let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust( + g1_monomial_bytes, + g1_lagrange_bytes, + g2_monomial_bytes + )); let c_settings = kzg_settings_to_c(&settings); PRECOMPUTATION_TABLES.save_precomputation(settings.precomputation.take(), &c_settings); *out = c_settings; - C_KZG_RET_OK } @@ -212,8 +124,9 @@ pub unsafe extern "C" fn load_trusted_setup_file( let mut buf = vec![0u8; 1024 * 1024]; let len: usize = libc::fread(buf.as_mut_ptr() as *mut libc::c_void, 1, buf.len(), in_); let s = handle_ckzg_badargs!(String::from_utf8(buf[..len].to_vec())); - let (g1_bytes, g2_bytes) = handle_ckzg_badargs!(load_trusted_setup_string(&s)); - TRUSTED_SETUP_NUM_G1_POINTS = g1_bytes.len() / BYTES_PER_G1; + let (g1_monomial_bytes, g1_lagrange_bytes, g2_monomial_bytes) = + handle_ckzg_badargs!(load_trusted_setup_string(&s)); + TRUSTED_SETUP_NUM_G1_POINTS = g1_monomial_bytes.len() / BYTES_PER_G1; if TRUSTED_SETUP_NUM_G1_POINTS != FIELD_ELEMENTS_PER_BLOB { // Helps pass the Java test "shouldThrowExceptionOnIncorrectTrustedSetupFromFile", // as well as 5 others that pass only if this one passes (likely because Java doesn't @@ -221,8 +134,9 @@ pub unsafe extern "C" fn load_trusted_setup_file( return C_KZG_RET_BADARGS; } let mut settings = handle_ckzg_badargs!(load_trusted_setup_rust( - g1_bytes.as_slice(), - g2_bytes.as_slice() + &g1_monomial_bytes, + &g1_lagrange_bytes, + &g2_monomial_bytes )); let c_settings = kzg_settings_to_c(&settings); @@ -266,30 +180,70 @@ pub unsafe extern "C" fn free_trusted_setup(s: *mut CKZGSettings) { return; } - PRECOMPUTATION_TABLES.remove_precomputation(&*s); + if !(*s).g1_values_monomial.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).g1_values_monomial, + FIELD_ELEMENTS_PER_BLOB, + )); + drop(v); + (*s).g1_values_monomial = ptr::null_mut(); + } - let max_width = (*s).max_width as usize; - let roots = Box::from_raw(core::slice::from_raw_parts_mut( - (*s).roots_of_unity, - max_width, - )); - drop(roots); - (*s).roots_of_unity = null_mut(); + if !(*s).g1_values_lagrange_brp.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).g1_values_lagrange_brp, + FIELD_ELEMENTS_PER_BLOB, + )); + drop(v); + (*s).g1_values_lagrange_brp = ptr::null_mut(); + } - let g1 = Box::from_raw(core::slice::from_raw_parts_mut( - (*s).g1_values, - TRUSTED_SETUP_NUM_G1_POINTS, - )); - drop(g1); - (*s).g1_values = null_mut(); + if !(*s).g2_values_monomial.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).g2_values_monomial, + TRUSTED_SETUP_NUM_G2_POINTS, + )); + drop(v); + (*s).g2_values_monomial = ptr::null_mut(); + } - let g2 = Box::from_raw(core::slice::from_raw_parts_mut( - (*s).g2_values, - TRUSTED_SETUP_NUM_G2_POINTS, - )); - drop(g2); - (*s).g2_values = null_mut(); - (*s).max_width = 0; + if !(*s).x_ext_fft_columns.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).x_ext_fft_columns, + 2 * ((FIELD_ELEMENTS_PER_EXT_BLOB / 2) / FIELD_ELEMENTS_PER_CELL), + )); + drop(v); + (*s).x_ext_fft_columns = ptr::null_mut(); + } + + if !(*s).roots_of_unity.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).roots_of_unity, + FIELD_ELEMENTS_PER_EXT_BLOB + 1, + )); + drop(v); + (*s).roots_of_unity = ptr::null_mut(); + } + + if !(*s).reverse_roots_of_unity.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).reverse_roots_of_unity, + FIELD_ELEMENTS_PER_EXT_BLOB + 1, + )); + drop(v); + (*s).reverse_roots_of_unity = ptr::null_mut(); + } + + if !(*s).brp_roots_of_unity.is_null() { + let v = Box::from_raw(core::slice::from_raw_parts_mut( + (*s).brp_roots_of_unity, + FIELD_ELEMENTS_PER_EXT_BLOB, + )); + drop(v); + (*s).brp_roots_of_unity = ptr::null_mut(); + } + + PRECOMPUTATION_TABLES.remove_precomputation(&*s); } /// # Safety @@ -459,8 +413,8 @@ mod tests { converted_settings.fs.roots_of_unity ); assert_eq!( - settings.fs.expanded_roots_of_unity, - converted_settings.fs.expanded_roots_of_unity + settings.fs.brp_roots_of_unity, + converted_settings.fs.brp_roots_of_unity ); assert_eq!( settings.fs.reverse_roots_of_unity, diff --git a/constantine/src/eip_7594.rs b/constantine/src/eip_7594.rs new file mode 100644 index 000000000..8a05ece40 --- /dev/null +++ b/constantine/src/eip_7594.rs @@ -0,0 +1,38 @@ +use kzg::eip_4844::FIELD_ELEMENTS_PER_CELL; + +use crate::types::{fr::CtFr, g1::CtG1, kzg_settings::CtKZGSettings}; + +pub fn compute_cells_and_kzg_proofs_rust( + cells: Option<&mut [[CtFr; FIELD_ELEMENTS_PER_CELL]]>, + proofs: Option<&mut [CtG1]>, + blob: &[CtFr], + s: &CtKZGSettings, +) -> Result<(), String> { + kzg::eip_7594::compute_cells_and_kzg_proofs(cells, proofs, blob, s) +} + +pub fn recover_cells_and_kzg_proofs_rust( + recovered_cells: &mut [[CtFr; FIELD_ELEMENTS_PER_CELL]], + recovered_proofs: Option<&mut [CtG1]>, + cell_indicies: &[usize], + cells: &[[CtFr; FIELD_ELEMENTS_PER_CELL]], + s: &CtKZGSettings, +) -> Result<(), String> { + kzg::eip_7594::recover_cells_and_kzg_proofs( + recovered_cells, + recovered_proofs, + cell_indicies, + cells, + s, + ) +} + +pub fn verify_cell_kzg_proof_batch_rust( + commitments: &[CtG1], + cell_indices: &[usize], + cells: &[[CtFr; FIELD_ELEMENTS_PER_CELL]], + proofs: &[CtG1], + s: &CtKZGSettings, +) -> Result { + kzg::eip_7594::verify_cell_kzg_proof_batch(commitments, cell_indices, cells, proofs, s) +} diff --git a/constantine/src/fft_fr.rs b/constantine/src/fft_fr.rs index 0341eef52..9ec212978 100644 --- a/constantine/src/fft_fr.rs +++ b/constantine/src/fft_fr.rs @@ -98,7 +98,7 @@ impl CtFFTSettings { let roots = if inverse { &self.reverse_roots_of_unity } else { - &self.expanded_roots_of_unity + &self.roots_of_unity }; fft_fr_fast(output, data, 1, roots, stride); diff --git a/constantine/src/fft_g1.rs b/constantine/src/fft_g1.rs index a5c180106..ff1d227cd 100644 --- a/constantine/src/fft_g1.rs +++ b/constantine/src/fft_g1.rs @@ -66,7 +66,7 @@ impl FFTG1 for CtFFTSettings { let roots = if inverse { &self.reverse_roots_of_unity } else { - &self.expanded_roots_of_unity + &self.roots_of_unity }; fft_g1_fast(&mut ret, data, 1, roots, stride); diff --git a/constantine/src/lib.rs b/constantine/src/lib.rs index 265cc11d2..824c12786 100644 --- a/constantine/src/lib.rs +++ b/constantine/src/lib.rs @@ -3,6 +3,7 @@ pub mod consts; pub mod data_availability_sampling; pub mod eip_4844; +pub mod eip_7594; pub mod fft_fr; pub mod fft_g1; pub mod fk20_proofs; diff --git a/constantine/src/mixed_kzg/mixed_kzg_settings.rs b/constantine/src/mixed_kzg/mixed_kzg_settings.rs index 3bff3a1cc..86869e6d7 100644 --- a/constantine/src/mixed_kzg/mixed_kzg_settings.rs +++ b/constantine/src/mixed_kzg/mixed_kzg_settings.rs @@ -73,12 +73,12 @@ impl LocalToStr for ctt_eth_kzg_status { impl MixedKzgSettings { pub fn new( - secret_g1: &[CtG1], - secret_g2: &[CtG2], - length: usize, + g1_monomial: &[CtG1], + g1_lagrange_brp: &[CtG1], + g2_monomial: &[CtG2], fft_settings: &CtFFTSettings, ) -> Result { - let res = GenericContext::new(secret_g1, secret_g2, length, fft_settings); + let res = GenericContext::new(g1_monomial, g1_lagrange_brp, g2_monomial, fft_settings); match res { Ok(generic_context) => Ok(Self::Generic(generic_context)), Err(x) => Err(x), @@ -115,12 +115,12 @@ impl Clone for MixedKzgSettings { // Allow using MixedKzgSettings as KZGSettings stand-in impl KZGSettings for MixedKzgSettings { fn new( - secret_g1: &[CtG1], - secret_g2: &[CtG2], - length: usize, - fs: &CtFFTSettings, + g1_monomial: &[CtG1], + g1_lagrange_brp: &[CtG1], + g2_monomial: &[CtG2], + fft_settings: &CtFFTSettings, ) -> Result { - MixedKzgSettings::new(secret_g1, secret_g2, length, fs) + MixedKzgSettings::new(g1_monomial, g1_lagrange_brp, g2_monomial, fft_settings) } fn commit_to_poly(&self, p: &CtPoly) -> Result { @@ -174,61 +174,70 @@ impl KZGSettings for } } - fn get_expanded_roots_of_unity_at(&self, i: usize) -> CtFr { + fn get_roots_of_unity_at(&self, i: usize) -> CtFr { match self { MixedKzgSettings::Constantine(_) => { panic!("Context not in generic format") } - MixedKzgSettings::Generic(generic_context) => { - generic_context.get_expanded_roots_of_unity_at(i) + MixedKzgSettings::Generic(generic_context) => generic_context.get_roots_of_unity_at(i), + } + } + + fn get_fft_settings(&self) -> &CtFFTSettings { + match self { + MixedKzgSettings::Constantine(_) => { + panic!("Context not in generic format") } + MixedKzgSettings::Generic(generic_context) => generic_context.get_fft_settings(), } } - fn get_roots_of_unity_at(&self, i: usize) -> CtFr { + fn get_precomputation( + &self, + ) -> Option<&kzg::msm::precompute::PrecomputationTable> { match self { MixedKzgSettings::Constantine(_) => { panic!("Context not in generic format") } - MixedKzgSettings::Generic(generic_context) => generic_context.get_roots_of_unity_at(i), + MixedKzgSettings::Generic(generic_context) => generic_context.get_precomputation(), } } - fn get_fft_settings(&self) -> &CtFFTSettings { + fn get_g1_monomial(&self) -> &[CtG1] { match self { MixedKzgSettings::Constantine(_) => { panic!("Context not in generic format") } - MixedKzgSettings::Generic(generic_context) => generic_context.get_fft_settings(), + MixedKzgSettings::Generic(generic_context) => generic_context.get_g1_monomial(), } } - fn get_g1_secret(&self) -> &[CtG1] { + fn get_g1_lagrange_brp(&self) -> &[CtG1] { match self { MixedKzgSettings::Constantine(_) => { panic!("Context not in generic format") } - MixedKzgSettings::Generic(generic_context) => generic_context.get_g1_secret(), + MixedKzgSettings::Generic(generic_context) => generic_context.get_g1_lagrange_brp(), } } - fn get_g2_secret(&self) -> &[CtG2] { + fn get_g2_monomial(&self) -> &[CtG2] { match self { MixedKzgSettings::Constantine(_) => { panic!("Context not in generic format") } - MixedKzgSettings::Generic(generic_context) => generic_context.get_g2_secret(), + MixedKzgSettings::Generic(generic_context) => generic_context.get_g2_monomial(), } } - fn get_precomputation( - &self, - ) -> Option<&kzg::msm::precompute::PrecomputationTable> { + fn get_x_ext_fft_column(&self, index: usize) -> &[CtG1] { match self { MixedKzgSettings::Constantine(_) => { panic!("Context not in generic format") } - MixedKzgSettings::Generic(generic_context) => generic_context.get_precomputation(), + MixedKzgSettings::Generic(generic_context) => { + generic_context.get_x_ext_fft_column(index) + } } } } diff --git a/constantine/src/types/fft_settings.rs b/constantine/src/types/fft_settings.rs index 596815159..2f3c0a086 100644 --- a/constantine/src/types/fft_settings.rs +++ b/constantine/src/types/fft_settings.rs @@ -14,9 +14,9 @@ use crate::types::fr::CtFr; pub struct CtFFTSettings { pub max_width: usize, pub root_of_unity: CtFr, - pub expanded_roots_of_unity: Vec, - pub reverse_roots_of_unity: Vec, pub roots_of_unity: Vec, + pub brp_roots_of_unity: Vec, + pub reverse_roots_of_unity: Vec, } impl Default for CtFFTSettings { @@ -39,21 +39,21 @@ impl FFTSettings for CtFFTSettings { let root_of_unity = CtFr::from_u64_arr(&SCALE2_ROOT_OF_UNITY[scale]); // create max_width of roots & store them reversed as well - let expanded_roots_of_unity = expand_root_of_unity(&root_of_unity, max_width)?; - let mut reverse_roots_of_unity = expanded_roots_of_unity.clone(); - reverse_roots_of_unity.reverse(); + let roots_of_unity = expand_root_of_unity(&root_of_unity, max_width)?; - // Permute the roots of unity - let mut roots_of_unity = expanded_roots_of_unity.clone(); - roots_of_unity.pop(); - reverse_bit_order(&mut roots_of_unity)?; + let mut brp_roots_of_unity = roots_of_unity.clone(); + brp_roots_of_unity.pop(); + reverse_bit_order(&mut brp_roots_of_unity)?; + + let mut reverse_roots_of_unity = roots_of_unity.clone(); + reverse_roots_of_unity.reverse(); Ok(CtFFTSettings { max_width, root_of_unity, - expanded_roots_of_unity, reverse_roots_of_unity, roots_of_unity, + brp_roots_of_unity, }) } @@ -61,14 +61,6 @@ impl FFTSettings for CtFFTSettings { self.max_width } - fn get_expanded_roots_of_unity_at(&self, i: usize) -> CtFr { - self.expanded_roots_of_unity[i] - } - - fn get_expanded_roots_of_unity(&self) -> &[CtFr] { - &self.expanded_roots_of_unity - } - fn get_reverse_roots_of_unity_at(&self, i: usize) -> CtFr { self.reverse_roots_of_unity[i] } @@ -84,6 +76,14 @@ impl FFTSettings for CtFFTSettings { fn get_roots_of_unity(&self) -> &[CtFr] { &self.roots_of_unity } + + fn get_brp_roots_of_unity(&self) -> &[CtFr] { + &self.brp_roots_of_unity + } + + fn get_brp_roots_of_unity_at(&self, i: usize) -> CtFr { + self.brp_roots_of_unity[i] + } } /// Multiply a given root of unity by itself until it results in a 1 and result all multiplication values in a vector diff --git a/constantine/src/types/fk20_multi_settings.rs b/constantine/src/types/fk20_multi_settings.rs index 8465308a3..e8740626c 100644 --- a/constantine/src/types/fk20_multi_settings.rs +++ b/constantine/src/types/fk20_multi_settings.rs @@ -78,7 +78,7 @@ impl FK20MultiSettings bool { unsafe { - constantine::ctt_bls12_381_validate_g1(&CtG1Affine::into_affine(self).0) - == ctt_codec_ecc_status::cttCodecEcc_Success + matches!( + constantine::ctt_bls12_381_validate_g1(&CtG1Affine::into_affine(self).0), + ctt_codec_ecc_status::cttCodecEcc_Success + | ctt_codec_ecc_status::cttCodecEcc_PointAtInfinity + ) } } diff --git a/constantine/src/types/kzg_settings.rs b/constantine/src/types/kzg_settings.rs index e0cfc042a..d5ca664db 100644 --- a/constantine/src/types/kzg_settings.rs +++ b/constantine/src/types/kzg_settings.rs @@ -4,10 +4,15 @@ use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; +use kzg::eip_4844::{ + FIELD_ELEMENTS_PER_BLOB, FIELD_ELEMENTS_PER_CELL, FIELD_ELEMENTS_PER_EXT_BLOB, + TRUSTED_SETUP_NUM_G2_POINTS, +}; use kzg::msm::precompute::{precompute, PrecomputationTable}; use kzg::{FFTFr, FFTSettings, Fr, G1Mul, G2Mul, KZGSettings, Poly, G1, G2}; use crate::consts::{G1_GENERATOR, G2_GENERATOR}; +use crate::fft_g1::fft_g1_fast; use crate::kzg_proofs::{g1_linear_combination, pairings_verify}; use crate::types::fft_settings::CtFFTSettings; use crate::types::fr::CtFr; @@ -21,35 +26,93 @@ use super::g1::CtG1Affine; #[derive(Clone, Default)] pub struct CtKZGSettings { pub fs: CtFFTSettings, - pub secret_g1: Vec, - pub secret_g2: Vec, + pub g1_values_monomial: Vec, + pub g1_values_lagrange_brp: Vec, + pub g2_values_monomial: Vec, pub precomputation: Option>>, + pub x_ext_fft_columns: Vec>, +} + +fn g1_fft(output: &mut [CtG1], input: &[CtG1], s: &CtFFTSettings) -> Result<(), String> { + /* Ensure the length is valid */ + if input.len() > FIELD_ELEMENTS_PER_EXT_BLOB || !input.len().is_power_of_two() { + return Err("Invalid input size".to_string()); + } + + let roots_stride = FIELD_ELEMENTS_PER_EXT_BLOB / input.len(); + fft_g1_fast(output, input, 1, &s.roots_of_unity, roots_stride); + + Ok(()) +} + +fn toeplitz_part_1(output: &mut [CtG1], x: &[CtG1], s: &CtFFTSettings) -> Result<(), String> { + let n = x.len(); + let n2 = n * 2; + let mut x_ext = vec![CtG1::identity(); n2]; + + x_ext[..n].copy_from_slice(x); + + g1_fft(output, &x_ext, s)?; + + Ok(()) } impl KZGSettings for CtKZGSettings { fn new( - secret_g1: &[CtG1], - secret_g2: &[CtG2], - _length: usize, + g1_monomial: &[CtG1], + g1_lagrange_brp: &[CtG1], + g2_monomial: &[CtG2], fft_settings: &CtFFTSettings, ) -> Result { + if g1_monomial.len() != FIELD_ELEMENTS_PER_BLOB + || g1_lagrange_brp.len() != FIELD_ELEMENTS_PER_BLOB + || g2_monomial.len() != TRUSTED_SETUP_NUM_G2_POINTS + { + return Err("Length does not match FIELD_ELEMENTS_PER_BLOB".to_string()); + } + + let n = FIELD_ELEMENTS_PER_EXT_BLOB / 2; + let k = n / FIELD_ELEMENTS_PER_CELL; + let k2 = 2 * k; + + let mut points = vec![CtG1::default(); k2]; + let mut x = vec![CtG1::default(); k]; + let mut x_ext_fft_columns = vec![vec![CtG1::default(); FIELD_ELEMENTS_PER_CELL]; k2]; + + for offset in 0..FIELD_ELEMENTS_PER_CELL { + let start = n - FIELD_ELEMENTS_PER_CELL - 1 - offset; + for (i, p) in x.iter_mut().enumerate().take(k - 1) { + let j = start - i * FIELD_ELEMENTS_PER_CELL; + *p = g1_monomial[j]; + } + x[k - 1] = CtG1::identity(); + + toeplitz_part_1(&mut points, &x, fft_settings)?; + + for row in 0..k2 { + x_ext_fft_columns[row][offset] = points[row]; + } + } + Ok(Self { - secret_g1: secret_g1.to_vec(), - secret_g2: secret_g2.to_vec(), + g1_values_monomial: g1_monomial.to_vec(), + g1_values_lagrange_brp: g1_lagrange_brp.to_vec(), + g2_values_monomial: g2_monomial.to_vec(), fs: fft_settings.clone(), - precomputation: precompute(secret_g1).ok().flatten().map(Arc::new), + x_ext_fft_columns, + precomputation: precompute(g1_lagrange_brp).ok().flatten().map(Arc::new), }) } fn commit_to_poly(&self, poly: &CtPoly) -> Result { - if poly.coeffs.len() > self.secret_g1.len() { + if poly.coeffs.len() > self.g1_values_lagrange_brp.len() { return Err(String::from("Polynomial is longer than secret g1")); } let mut out = CtG1::default(); g1_linear_combination( &mut out, - &self.secret_g1, + &self.g1_values_lagrange_brp, &poly.coeffs, poly.coeffs.len(), self.get_precomputation(), @@ -89,7 +152,7 @@ impl KZGSettings for y: &CtFr, ) -> Result { let x_g2: CtG2 = G2_GENERATOR.mul(x); - let s_minus_x: CtG2 = self.secret_g2[1].sub(&x_g2); + let s_minus_x: CtG2 = self.g2_values_monomial[1].sub(&x_g2); let y_g1 = G1_GENERATOR.mul(y); let commitment_minus_y: CtG1 = com.sub(&y_g1); @@ -100,7 +163,6 @@ impl KZGSettings for &s_minus_x, )) } - fn compute_proof_multi(&self, p: &CtPoly, x0: &CtFr, n: usize) -> Result { if p.coeffs.is_empty() { return Err(String::from("Polynomial must not be empty")); @@ -169,7 +231,7 @@ impl KZGSettings for let xn2 = G2_GENERATOR.mul(&x_pow); // [s^n - x^n]_2 - let xn_minus_yn = self.secret_g2[n].sub(&xn2); + let xn_minus_yn = self.g2_values_monomial[n].sub(&xn2); // [interpolation_polynomial(s)]_1 let is1 = self.commit_to_poly(&interp).unwrap(); @@ -182,10 +244,6 @@ impl KZGSettings for Ok(ret) } - fn get_expanded_roots_of_unity_at(&self, i: usize) -> CtFr { - self.fs.get_expanded_roots_of_unity_at(i) - } - fn get_roots_of_unity_at(&self, i: usize) -> CtFr { self.fs.get_roots_of_unity_at(i) } @@ -194,15 +252,23 @@ impl KZGSettings for &self.fs } - fn get_g1_secret(&self) -> &[CtG1] { - &self.secret_g1 + fn get_g1_lagrange_brp(&self) -> &[CtG1] { + &self.g1_values_lagrange_brp + } + + fn get_g1_monomial(&self) -> &[CtG1] { + &self.g1_values_monomial } - fn get_g2_secret(&self) -> &[CtG2] { - &self.secret_g2 + fn get_g2_monomial(&self) -> &[CtG2] { + &self.g2_values_monomial } fn get_precomputation(&self) -> Option<&PrecomputationTable> { self.precomputation.as_ref().map(|v| v.as_ref()) } + + fn get_x_ext_fft_column(&self, index: usize) -> &[CtG1] { + &self.x_ext_fft_columns[index] + } } diff --git a/constantine/src/utils.rs b/constantine/src/utils.rs index a4ab9e8ea..b27b14454 100644 --- a/constantine/src/utils.rs +++ b/constantine/src/utils.rs @@ -2,28 +2,41 @@ extern crate alloc; use alloc::vec::Vec; -use kzg::eip_4844::hash_to_bls_field; +use kzg::eip_4844::{ + hash_to_bls_field, Blob, CKZGSettings, PrecomputationTableManager, BYTES_PER_FIELD_ELEMENT, + C_KZG_RET, C_KZG_RET_BADARGS, FIELD_ELEMENTS_PER_BLOB, FIELD_ELEMENTS_PER_CELL, + FIELD_ELEMENTS_PER_EXT_BLOB, TRUSTED_SETUP_NUM_G2_POINTS, +}; use kzg::{Fr, G1Mul, G2Mul}; use crate::consts::{G1_GENERATOR, G2_GENERATOR}; -use crate::types::g1::CtG1; +use crate::types::fft_settings::CtFFTSettings; +use crate::types::fp::CtFp; +use crate::types::fr::CtFr; +use crate::types::g1::{CtG1, CtG1Affine}; use crate::types::g2::CtG2; +use crate::types::kzg_settings::CtKZGSettings; -pub fn generate_trusted_setup(n: usize, secret: [u8; 32usize]) -> (Vec, Vec) { +pub fn generate_trusted_setup( + n: usize, + secret: [u8; 32usize], +) -> (Vec, Vec, Vec) { let s = hash_to_bls_field(&secret); let mut s_pow = Fr::one(); let mut s1 = Vec::with_capacity(n); let mut s2 = Vec::with_capacity(n); + let mut s3 = Vec::with_capacity(n); for _ in 0..n { s1.push(G1_GENERATOR.mul(&s_pow)); - s2.push(G2_GENERATOR.mul(&s_pow)); + s2.push(G1_GENERATOR); // TODO: this should be lagrange form + s3.push(G2_GENERATOR.mul(&s_pow)); s_pow = s_pow.mul(&s); } - (s1, s2) + (s1, s2, s3) } pub fn ptr_transmute(t: &T) -> *const U { @@ -37,3 +50,185 @@ pub fn ptr_transmute_mut(t: &mut T) -> *mut U { t as *mut T as *mut U } + +pub(crate) unsafe fn deserialize_blob(blob: *const Blob) -> Result, C_KZG_RET> { + (*blob) + .bytes + .chunks(BYTES_PER_FIELD_ELEMENT) + .map(|chunk| { + let mut bytes = [0u8; BYTES_PER_FIELD_ELEMENT]; + bytes.copy_from_slice(chunk); + if let Ok(result) = CtFr::from_bytes(&bytes) { + Ok(result) + } else { + Err(C_KZG_RET_BADARGS) + } + }) + .collect::, C_KZG_RET>>() +} + +pub(crate) fn fft_settings_to_rust( + c_settings: *const CKZGSettings, +) -> Result { + let settings = unsafe { &*c_settings }; + + let roots_of_unity = unsafe { + core::slice::from_raw_parts(settings.roots_of_unity, FIELD_ELEMENTS_PER_EXT_BLOB + 1) + .iter() + .map(|r| CtFr::from_blst_fr(*r)) + .collect::>() + }; + + let brp_roots_of_unity = unsafe { + core::slice::from_raw_parts(settings.brp_roots_of_unity, FIELD_ELEMENTS_PER_EXT_BLOB) + .iter() + .map(|r| CtFr::from_blst_fr(*r)) + .collect::>() + }; + + let reverse_roots_of_unity = unsafe { + core::slice::from_raw_parts( + settings.reverse_roots_of_unity, + FIELD_ELEMENTS_PER_EXT_BLOB + 1, + ) + .iter() + .map(|r| CtFr::from_blst_fr(*r)) + .collect::>() + }; + + Ok(CtFFTSettings { + max_width: FIELD_ELEMENTS_PER_EXT_BLOB, + root_of_unity: roots_of_unity[1], + roots_of_unity, + brp_roots_of_unity, + reverse_roots_of_unity, + }) +} + +pub(crate) static mut PRECOMPUTATION_TABLES: PrecomputationTableManager< + CtFr, + CtG1, + CtFp, + CtG1Affine, +> = PrecomputationTableManager::new(); + +pub(crate) fn kzg_settings_to_rust(c_settings: &CKZGSettings) -> Result { + Ok(CtKZGSettings { + fs: fft_settings_to_rust(c_settings)?, + g1_values_monomial: unsafe { + core::slice::from_raw_parts(c_settings.g1_values_monomial, FIELD_ELEMENTS_PER_BLOB) + } + .iter() + .map(|r| CtG1::from_blst_p1(*r)) + .collect::>(), + g1_values_lagrange_brp: unsafe { + core::slice::from_raw_parts(c_settings.g1_values_lagrange_brp, FIELD_ELEMENTS_PER_BLOB) + } + .iter() + .map(|r| CtG1::from_blst_p1(*r)) + .collect::>(), + g2_values_monomial: unsafe { + core::slice::from_raw_parts(c_settings.g2_values_monomial, TRUSTED_SETUP_NUM_G2_POINTS) + } + .iter() + .map(|r| CtG2::from_blst_p2(*r)) + .collect::>(), + x_ext_fft_columns: unsafe { + core::slice::from_raw_parts( + c_settings.x_ext_fft_columns, + 2 * ((FIELD_ELEMENTS_PER_EXT_BLOB / 2) / FIELD_ELEMENTS_PER_CELL), + ) + } + .iter() + .map(|it| { + unsafe { core::slice::from_raw_parts(*it, FIELD_ELEMENTS_PER_CELL) } + .iter() + .map(|it| CtG1::from_blst_p1(*it)) + .collect::>() + }) + .collect::>(), + precomputation: unsafe { PRECOMPUTATION_TABLES.get_precomputation(c_settings) }, + }) +} + +pub(crate) fn kzg_settings_to_c(rust_settings: &CtKZGSettings) -> CKZGSettings { + CKZGSettings { + roots_of_unity: Box::leak( + rust_settings + .fs + .roots_of_unity + .iter() + .map(|r| r.to_blst_fr()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + brp_roots_of_unity: Box::leak( + rust_settings + .fs + .brp_roots_of_unity + .iter() + .map(|r| r.to_blst_fr()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + reverse_roots_of_unity: Box::leak( + rust_settings + .fs + .reverse_roots_of_unity + .iter() + .map(|r| r.to_blst_fr()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + g1_values_monomial: Box::leak( + rust_settings + .g1_values_monomial + .iter() + .map(|r| r.to_blst_p1()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + g1_values_lagrange_brp: Box::leak( + rust_settings + .g1_values_lagrange_brp + .iter() + .map(|r| r.to_blst_p1()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + g2_values_monomial: Box::leak( + rust_settings + .g2_values_monomial + .iter() + .map(|r| r.to_blst_p2()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + x_ext_fft_columns: Box::leak( + rust_settings + .x_ext_fft_columns + .iter() + .map(|r| { + Box::leak( + r.iter() + .map(|it| it.to_blst_p1()) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr() + }) + .collect::>() + .into_boxed_slice(), + ) + .as_mut_ptr(), + tables: core::ptr::null_mut(), + wbits: 0, + scratch_size: 0, + } +} diff --git a/constantine/src/zero_poly.rs b/constantine/src/zero_poly.rs index 713058e8f..6114ef068 100644 --- a/constantine/src/zero_poly.rs +++ b/constantine/src/zero_poly.rs @@ -66,11 +66,11 @@ impl CtFFTSettings { let mut coeffs = SmallVec::<[CtFr; DEGREE_OF_PARTIAL]>::new(); // For the first member, store -w_0 as constant term - coeffs.push(self.expanded_roots_of_unity[idxs[0] * stride].negate()); + coeffs.push(self.roots_of_unity[idxs[0] * stride].negate()); for (i, idx) in idxs.iter().copied().enumerate().skip(1) { // For member (x - w_i) take coefficient as -(w_i + w_{i-1} + ...) - let neg_di = self.expanded_roots_of_unity[idx * stride].negate(); + let neg_di = self.roots_of_unity[idx * stride].negate(); coeffs.push(neg_di.add(&coeffs[i - 1])); // Multiply all previous members by (x - w_i) diff --git a/constantine/tests/eip_7594.rs b/constantine/tests/eip_7594.rs new file mode 100644 index 000000000..f7bf1f16d --- /dev/null +++ b/constantine/tests/eip_7594.rs @@ -0,0 +1,40 @@ +#[cfg(test)] +mod tests { + use kzg::eip_4844::bytes_to_blob; + use kzg_bench::tests::eip_7594::{ + test_vectors_compute_cells_and_kzg_proofs, test_vectors_recover_cells_and_kzg_proofs, + test_vectors_verify_cell_kzg_proof_batch, + }; + use rust_kzg_constantine::{ + eip_4844::load_trusted_setup_filename_rust, + eip_7594::{ + compute_cells_and_kzg_proofs_rust, recover_cells_and_kzg_proofs_rust, + verify_cell_kzg_proof_batch_rust, + }, + }; + + #[test] + pub fn test_vectors_compute_cells_and_kzg_proofs_() { + test_vectors_compute_cells_and_kzg_proofs( + &load_trusted_setup_filename_rust, + &compute_cells_and_kzg_proofs_rust, + &bytes_to_blob, + ); + } + + #[test] + pub fn test_vectors_recover_cells_and_kzg_proofs_() { + test_vectors_recover_cells_and_kzg_proofs( + &load_trusted_setup_filename_rust, + &recover_cells_and_kzg_proofs_rust, + ); + } + + #[test] + pub fn test_vectors_verify_cell_kzg_proof_batch_() { + test_vectors_verify_cell_kzg_proof_batch( + &load_trusted_setup_filename_rust, + &verify_cell_kzg_proof_batch_rust, + ); + } +} diff --git a/constantine/tests/fk20_proofs.rs b/constantine/tests/fk20_proofs.rs index 6e138c90b..d1692ae18 100644 --- a/constantine/tests/fk20_proofs.rs +++ b/constantine/tests/fk20_proofs.rs @@ -12,6 +12,7 @@ mod tests { use rust_kzg_constantine::types::poly::CtPoly; use rust_kzg_constantine::utils::generate_trusted_setup; + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] fn test_fk_single() { fk_single::< @@ -27,6 +28,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] fn test_fk_single_strided() { fk_single_strided::< @@ -42,6 +44,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] fn test_fk_multi_settings() { fk_multi_settings::< @@ -57,6 +60,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] fn test_fk_multi_chunk_len_1_512() { fk_multi_chunk_len_1_512::< @@ -72,6 +76,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] fn test_fk_multi_chunk_len_16_512() { fk_multi_chunk_len_16_512::< @@ -87,6 +92,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] fn test_fk_multi_chunk_len_16_16() { fk_multi_chunk_len_16_16::< diff --git a/constantine/tests/kzg_proofs.rs b/constantine/tests/kzg_proofs.rs index e7f32d159..a102bdd58 100644 --- a/constantine/tests/kzg_proofs.rs +++ b/constantine/tests/kzg_proofs.rs @@ -14,6 +14,7 @@ mod tests { use rust_kzg_constantine::types::poly::CtPoly; use rust_kzg_constantine::utils::generate_trusted_setup; + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] pub fn test_proof_single() { proof_single::( @@ -21,6 +22,7 @@ mod tests { ); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] pub fn test_commit_to_nil_poly() { commit_to_nil_poly::< @@ -35,6 +37,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] pub fn test_commit_to_too_long_poly() { commit_to_too_long_poly_returns_err::< @@ -49,6 +52,7 @@ mod tests { >(&generate_trusted_setup); } + #[ignore = "KZG settings loading doesn't support trusted setup sizes other than FIELD_ELEMENTS_PER_BLOB (4096 points)"] #[test] pub fn test_proof_multi() { proof_multi::( diff --git a/constantine/tests/local_tests/local_consts.rs b/constantine/tests/local_tests/local_consts.rs index 450d8c765..1bf7c775f 100644 --- a/constantine/tests/local_tests/local_consts.rs +++ b/constantine/tests/local_tests/local_consts.rs @@ -7,10 +7,10 @@ pub fn roots_of_unity_repeat_at_stride>( for i in 0..fs1.get_max_width() { assert!(fs1 - .get_expanded_roots_of_unity_at(i) - .equals(&fs2.get_expanded_roots_of_unity_at(i * 2))); + .get_roots_of_unity_at(i) + .equals(&fs2.get_roots_of_unity_at(i * 2))); assert!(fs1 - .get_expanded_roots_of_unity_at(i) - .equals(&fs3.get_expanded_roots_of_unity_at(i * 4))); + .get_roots_of_unity_at(i) + .equals(&fs3.get_roots_of_unity_at(i * 4))); } } diff --git a/kzg-bench/src/tests/eip_7594.rs b/kzg-bench/src/tests/eip_7594.rs index 8b3b884f0..7703db3c6 100644 --- a/kzg-bench/src/tests/eip_7594.rs +++ b/kzg-bench/src/tests/eip_7594.rs @@ -348,7 +348,7 @@ pub fn test_vectors_verify_cell_kzg_proof_batch< &proofs, &settings, ) { - Err(err) => assert!(test.get_output().is_none(), "Should correctly recover cells, but failed with error {err:?}, for test vector {test_file:?}"), + Err(err) => assert!(test.get_output().is_none(), "Should correctly verify cells, but failed with error {err:?}, for test vector {test_file:?}"), Ok(value) => { let test_output = test.get_output(); diff --git a/kzg-bench/src/tests/fixtures/valid_short_hex/trusted_setup_fixture.txt b/kzg-bench/src/tests/fixtures/valid_short_hex/trusted_setup_fixture.txt index 83a3faf5c..a3fedacbd 100644 --- a/kzg-bench/src/tests/fixtures/valid_short_hex/trusted_setup_fixture.txt +++ b/kzg-bench/src/tests/fixtures/valid_short_hex/trusted_setup_fixture.txt @@ -1,7 +1,7 @@ 4096 65 a0 41 3c d ca fe c6 db c9 f4 7d 66 78 5c f1 e8 c9 81 4 4f 7d 13 cf e3 e4 fc bb 71 b5 40 8d fd e6 31 24 93 cb 3c 1d 30 51 6c b3 ca 88 c0 36 54 -8b997fb25730d661918371bb41f2a6e899cac23f 4fc536580 b75433c a953250 e15e7a98fb5c a5cc56 a8cd34c2 c57 +8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57 83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99 a759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83 967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127 diff --git a/kzg/src/eip_4844.rs b/kzg/src/eip_4844.rs index ec58c260a..6f40d8441 100644 --- a/kzg/src/eip_4844.rs +++ b/kzg/src/eip_4844.rs @@ -968,7 +968,6 @@ pub fn load_trusted_setup_rust< if num_g1_points != FIELD_ELEMENTS_PER_BLOB { return Err(String::from("Invalid number of G1 points")); } - if g1_lagrange_bytes.len() / BYTES_PER_G1 != FIELD_ELEMENTS_PER_BLOB { return Err(String::from("Invalid number of G1 points")); } diff --git a/kzg/src/eip_7594.rs b/kzg/src/eip_7594.rs index bbb267e14..3473511f0 100644 --- a/kzg/src/eip_7594.rs +++ b/kzg/src/eip_7594.rs @@ -770,7 +770,7 @@ fn compute_commitment_to_aggregated_interpolation_poly< // TODO: maybe pass precomputation here? Ok(TG1::g1_lincomb( - &s.get_g1_monomial(), + s.get_g1_monomial(), &aggregated_interpolation_poly, FIELD_ELEMENTS_PER_CELL, None, From b413d310d1808c48ec0f5725394bec1a05994067 Mon Sep 17 00:00:00 2001 From: Aleksandras Sukelovic Date: Sat, 12 Oct 2024 19:34:42 +0300 Subject: [PATCH 2/2] Added C bindings in eip-7594 --- constantine/src/eip_7594.rs | 243 +++++++++++++++++++++++++++++++++++- 1 file changed, 241 insertions(+), 2 deletions(-) diff --git a/constantine/src/eip_7594.rs b/constantine/src/eip_7594.rs index 8a05ece40..796106419 100644 --- a/constantine/src/eip_7594.rs +++ b/constantine/src/eip_7594.rs @@ -1,6 +1,15 @@ -use kzg::eip_4844::FIELD_ELEMENTS_PER_CELL; +use kzg::{ + eip_4844::{ + Blob, Bytes48, CKZGSettings, Cell, KZGProof, BYTES_PER_FIELD_ELEMENT, CELLS_PER_EXT_BLOB, + C_KZG_RET, C_KZG_RET_BADARGS, C_KZG_RET_OK, FIELD_ELEMENTS_PER_CELL, + }, + Fr, G1, +}; -use crate::types::{fr::CtFr, g1::CtG1, kzg_settings::CtKZGSettings}; +use crate::{ + types::{fr::CtFr, g1::CtG1, kzg_settings::CtKZGSettings}, + utils::{deserialize_blob, kzg_settings_to_rust}, +}; pub fn compute_cells_and_kzg_proofs_rust( cells: Option<&mut [[CtFr; FIELD_ELEMENTS_PER_CELL]]>, @@ -36,3 +45,233 @@ pub fn verify_cell_kzg_proof_batch_rust( ) -> Result { kzg::eip_7594::verify_cell_kzg_proof_batch(commitments, cell_indices, cells, proofs, s) } + +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn compute_cells_and_kzg_proofs( + cells: *mut Cell, + proofs: *mut KZGProof, + blob: *const Blob, + settings: *const CKZGSettings, +) -> C_KZG_RET { + unsafe fn inner( + cells: *mut Cell, + proofs: *mut KZGProof, + blob: *const Blob, + settings: *const CKZGSettings, + ) -> Result<(), String> { + let mut cells_rs = if cells.is_null() { + None + } else { + Some(vec![ + [CtFr::default(); FIELD_ELEMENTS_PER_CELL]; + CELLS_PER_EXT_BLOB + ]) + }; + let mut proofs_rs = if proofs.is_null() { + None + } else { + Some(vec![CtG1::default(); CELLS_PER_EXT_BLOB]) + }; + + let blob = deserialize_blob(blob).map_err(|_| "Invalid blob".to_string())?; + let settings = kzg_settings_to_rust(&*settings)?; + + compute_cells_and_kzg_proofs_rust( + cells_rs.as_deref_mut(), + proofs_rs.as_deref_mut(), + &blob, + &settings, + )?; + + if let Some(cells_rs) = cells_rs { + let cells = core::slice::from_raw_parts_mut(cells, CELLS_PER_EXT_BLOB); + for (cell_index, cell) in cells_rs.iter().enumerate() { + for (fr_index, fr) in cell.iter().enumerate() { + cells[cell_index].bytes[(fr_index * BYTES_PER_FIELD_ELEMENT) + ..((fr_index + 1) * BYTES_PER_FIELD_ELEMENT)] + .copy_from_slice(&fr.to_bytes()); + } + } + } + + if let Some(proofs_rs) = proofs_rs { + let proofs = core::slice::from_raw_parts_mut(proofs, CELLS_PER_EXT_BLOB); + for (proof_index, proof) in proofs_rs.iter().enumerate() { + proofs[proof_index].bytes.copy_from_slice(&proof.to_bytes()); + } + } + + Ok(()) + } + + match inner(cells, proofs, blob, settings) { + Ok(()) => C_KZG_RET_OK, + Err(_) => C_KZG_RET_BADARGS, + } +} + +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn recover_cells_and_kzg_proofs( + recovered_cells: *mut Cell, + recovered_proofs: *mut KZGProof, + cell_indices: *const u64, + cells: *const Cell, + num_cells: u64, + s: *const CKZGSettings, +) -> C_KZG_RET { + unsafe fn inner( + recovered_cells: *mut Cell, + recovered_proofs: *mut KZGProof, + cell_indices: *const u64, + cells: *const Cell, + num_cells: u64, + s: *const CKZGSettings, + ) -> Result<(), String> { + let mut recovered_cells_rs = + vec![[CtFr::default(); FIELD_ELEMENTS_PER_CELL]; CELLS_PER_EXT_BLOB]; + + let mut recovered_proofs_rs = if recovered_proofs.is_null() { + None + } else { + Some(vec![CtG1::default(); CELLS_PER_EXT_BLOB]) + }; + + let cell_indicies = core::slice::from_raw_parts(cell_indices, num_cells as usize) + .iter() + .map(|it| *it as usize) + .collect::>(); + let cells = core::slice::from_raw_parts(cells, num_cells as usize) + .iter() + .map(|it| -> Result<[CtFr; FIELD_ELEMENTS_PER_CELL], String> { + it.bytes + .chunks(BYTES_PER_FIELD_ELEMENT) + .map(CtFr::from_bytes) + .collect::, String>>() + .and_then(|frs| { + frs.try_into() + .map_err(|_| "Invalid field element count per cell".to_string()) + }) + }) + .collect::, String>>()?; + let settings = kzg_settings_to_rust(&*s)?; + + recover_cells_and_kzg_proofs_rust( + &mut recovered_cells_rs, + recovered_proofs_rs.as_deref_mut(), + &cell_indicies, + &cells, + &settings, + )?; + + let recovered_cells = core::slice::from_raw_parts_mut(recovered_cells, CELLS_PER_EXT_BLOB); + for (cell_c, cell_rs) in recovered_cells.iter_mut().zip(recovered_cells_rs.iter()) { + cell_c.bytes.copy_from_slice( + &cell_rs + .iter() + .flat_map(|fr| fr.to_bytes()) + .collect::>(), + ); + } + + if let Some(recovered_proofs_rs) = recovered_proofs_rs { + let recovered_proofs = + core::slice::from_raw_parts_mut(recovered_proofs, CELLS_PER_EXT_BLOB); + + for (proof_c, proof_rs) in recovered_proofs.iter_mut().zip(recovered_proofs_rs.iter()) { + proof_c.bytes = proof_rs.to_bytes(); + } + } + + Ok(()) + } + + match inner( + recovered_cells, + recovered_proofs, + cell_indices, + cells, + num_cells, + s, + ) { + Ok(()) => C_KZG_RET_OK, + Err(_) => C_KZG_RET_BADARGS, + } +} + +/// # Safety +#[no_mangle] +pub unsafe extern "C" fn verify_cell_kzg_proof_batch( + ok: *mut bool, + commitments_bytes: *const Bytes48, + cell_indices: *const u64, + cells: *const Cell, + proofs_bytes: *const Bytes48, + num_cells: u64, + s: *const CKZGSettings, +) -> C_KZG_RET { + unsafe fn inner( + ok: *mut bool, + commitments_bytes: *const Bytes48, + cell_indices: *const u64, + cells: *const Cell, + proofs_bytes: *const Bytes48, + num_cells: u64, + s: *const CKZGSettings, + ) -> Result<(), String> { + let commitments = core::slice::from_raw_parts(commitments_bytes, num_cells as usize) + .iter() + .map(|bytes| CtG1::from_bytes(&bytes.bytes)) + .collect::, String>>()?; + + let cell_indices = core::slice::from_raw_parts(cell_indices, num_cells as usize) + .iter() + .map(|it| *it as usize) + .collect::>(); + + let cells = core::slice::from_raw_parts(cells, num_cells as usize) + .iter() + .map(|it| -> Result<[CtFr; FIELD_ELEMENTS_PER_CELL], String> { + it.bytes + .chunks(BYTES_PER_FIELD_ELEMENT) + .map(CtFr::from_bytes) + .collect::, String>>() + .and_then(|frs| { + frs.try_into() + .map_err(|_| "Invalid field element count per cell".to_string()) + }) + }) + .collect::, String>>()?; + + let proofs = core::slice::from_raw_parts(proofs_bytes, num_cells as usize) + .iter() + .map(|bytes| CtG1::from_bytes(&bytes.bytes)) + .collect::, String>>()?; + + let settings = kzg_settings_to_rust(&*s)?; + + *ok = verify_cell_kzg_proof_batch_rust( + &commitments, + &cell_indices, + &cells, + &proofs, + &settings, + )?; + + Ok(()) + } + + match inner( + ok, + commitments_bytes, + cell_indices, + cells, + proofs_bytes, + num_cells, + s, + ) { + Ok(()) => C_KZG_RET_OK, + Err(_) => C_KZG_RET_BADARGS, + } +}