diff --git a/crates/proof-of-sql/src/proof_primitive/dory/blitzar_metadata_table.rs b/crates/proof-of-sql/src/proof_primitive/dory/blitzar_metadata_table.rs index a4a28225d..a957f7546 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/blitzar_metadata_table.rs +++ b/crates/proof-of-sql/src/proof_primitive/dory/blitzar_metadata_table.rs @@ -1,12 +1,12 @@ -use super::{ - dynamic_dory_structure::{ - full_width_of_row, index_from_row_and_column, matrix_size, row_and_column_from_index, - }, - G1Affine, F, -}; +use super::{G1Affine, F}; use crate::{ base::{commitment::CommittableColumn, database::ColumnType, if_rayon}, - proof_primitive::dory::offset_to_bytes::OffsetToBytes, + proof_primitive::{ + dory::offset_to_bytes::OffsetToBytes, + dynamic_matrix_utils::matrix_structure::{ + full_width_of_row, index_from_row_and_column, matrix_size, row_and_column_from_index, + }, + }, }; use alloc::{vec, vec::Vec}; use ark_ec::CurveGroup; diff --git a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_build_vmv_state.rs b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_build_vmv_state.rs index 43ef11cc0..6ca6c47d8 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_build_vmv_state.rs +++ b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_build_vmv_state.rs @@ -1,7 +1,8 @@ use super::{ - dynamic_dory_helper::{compute_dynamic_v_vec, compute_dynamic_vecs}, - DeferredGT, G1Affine, VMVProverState, VMVVerifierState, F, + dynamic_dory_helper::compute_dynamic_v_vec, DeferredGT, DoryScalar, G1Affine, VMVProverState, + VMVVerifierState, F, }; +use crate::proof_primitive::dynamic_matrix_utils::standard_basis_helper::compute_dynamic_vecs; use alloc::vec::Vec; /// Builds a [`VMVProverState`] from the given parameters. @@ -11,13 +12,18 @@ pub(super) fn build_dynamic_vmv_prover_state( T_vec_prime: Vec, nu: usize, ) -> VMVProverState { - let (lo_vec, hi_vec) = compute_dynamic_vecs(b_point); - let v_vec = compute_dynamic_v_vec(a, &hi_vec, nu); + let (lo_vec, hi_vec) = + compute_dynamic_vecs(bytemuck::TransparentWrapper::wrap_slice(b_point) as &[DoryScalar]); + let (lo_vec, hi_vec) = ( + bytemuck::TransparentWrapper::peel_slice(&lo_vec) as &[F], + bytemuck::TransparentWrapper::peel_slice(&hi_vec) as &[F], + ); + let v_vec = compute_dynamic_v_vec(a, hi_vec, nu); VMVProverState { v_vec, T_vec_prime, - L_vec: hi_vec, - R_vec: lo_vec, + L_vec: hi_vec.to_vec(), + R_vec: lo_vec.to_vec(), #[cfg(test)] l_tensor: Vec::with_capacity(0), #[cfg(test)] diff --git a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_cpu.rs b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_cpu.rs index b36e1177d..042645192 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_cpu.rs +++ b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_cpu.rs @@ -1,8 +1,10 @@ -use super::{ - dynamic_dory_structure::{full_width_of_row, row_and_column_from_index, row_start_index}, - pairings, DoryScalar, DynamicDoryCommitment, G1Projective, ProverSetup, GT, +use super::{pairings, DoryScalar, DynamicDoryCommitment, G1Projective, ProverSetup, GT}; +use crate::{ + base::{commitment::CommittableColumn, if_rayon, slice_ops::slice_cast}, + proof_primitive::dynamic_matrix_utils::matrix_structure::{ + full_width_of_row, row_and_column_from_index, row_start_index, + }, }; -use crate::base::{commitment::CommittableColumn, if_rayon, slice_ops::slice_cast}; use alloc::vec::Vec; use ark_ec::VariableBaseMSM; use bytemuck::TransparentWrapper; diff --git a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_gpu.rs b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_gpu.rs index 474b9ce3f..88c6e50c6 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_gpu.rs +++ b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_commitment_helper_gpu.rs @@ -1,9 +1,11 @@ use super::{ blitzar_metadata_table::{create_blitzar_metadata_tables, signed_commits}, - dynamic_dory_structure::row_and_column_from_index, pairings, DynamicDoryCommitment, G1Affine, ProverSetup, }; -use crate::base::{commitment::CommittableColumn, if_rayon, slice_ops::slice_cast}; +use crate::{ + base::{commitment::CommittableColumn, if_rayon, slice_ops::slice_cast}, + proof_primitive::dynamic_matrix_utils::matrix_structure::row_and_column_from_index, +}; use blitzar::compute::ElementP2; #[cfg(feature = "rayon")] use rayon::iter::{IntoParallelIterator, ParallelIterator}; diff --git a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_helper.rs b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_helper.rs index 24bf4054a..63e350a22 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_helper.rs +++ b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_helper.rs @@ -1,13 +1,15 @@ use super::{ - blitzar_metadata_table::create_blitzar_metadata_tables, - dynamic_dory_standard_basis_helper::fold_dynamic_standard_basis_tensors, - dynamic_dory_structure::row_and_column_from_index, ExtendedVerifierState, G1Affine, + blitzar_metadata_table::create_blitzar_metadata_tables, ExtendedVerifierState, G1Affine, ProverSetup, F, }; use crate::{ base::{commitment::CommittableColumn, slice_ops::slice_cast}, - proof_primitive::dory::{ - dynamic_dory_standard_basis_helper::compute_dynamic_standard_basis_vecs, DoryScalar, + proof_primitive::{ + dory::DoryScalar, + dynamic_matrix_utils::{ + matrix_structure::row_and_column_from_index, + standard_basis_helper::fold_dynamic_standard_basis_tensors, + }, }, }; use alloc::{vec, vec::Vec}; @@ -93,29 +95,6 @@ pub(super) fn compute_dynamic_nu(num_vars: usize) -> usize { num_vars / 2 + 1 } -/// Compute the hi and lo vectors (or L and R) that are derived from `point`. -/// L and R are the vectors such that LMR is exactly the evaluation of `a` at the point `point`. -/// # Panics -/// This function requires that `point` has length at least as big as the number of rows in `M` that is created by `a`. -pub(super) fn compute_dynamic_vecs(point: &[F]) -> (Vec, Vec) { - let nu = point.len() / 2 + 1; - let mut lo_vec = vec![F::ZERO; 1 << nu]; - let mut hi_vec = vec![F::ZERO; 1 << nu]; - lo_vec[0] = point.iter().take(nu).map(|b| F::ONE - b).product(); - hi_vec[0] = point.iter().skip(nu).map(|b| F::ONE - b).product(); - let standard_basis_point = point - .iter() - .map(|b| { - (F::ONE - b) - .inverse() - .expect("Values in point cannot be 1.") - - F::ONE - }) - .collect_vec(); - compute_dynamic_standard_basis_vecs(&standard_basis_point, &mut lo_vec, &mut hi_vec); - (lo_vec, hi_vec) -} - /// Folds the `s1` and `s2` tensors: /// /// This is the analogous function of the non-dynamic folding function [`extended_dory_reduce_verify_fold_s_vecs`](super::extended_dory_reduce_helper::extended_dory_reduce_verify_fold_s_vecs). @@ -137,101 +116,21 @@ pub(super) fn fold_dynamic_tensors(state: &ExtendedVerifierState) -> (F, F) { }) .collect_vec(); let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors( - &standard_basis_point, - &state.alphas, - &state.alpha_invs, + bytemuck::TransparentWrapper::wrap_slice(&standard_basis_point) as &[DoryScalar], + bytemuck::TransparentWrapper::wrap_slice(&state.alphas) as &[DoryScalar], + bytemuck::TransparentWrapper::wrap_slice(&state.alpha_invs) as &[DoryScalar], ); - (lo_fold * lo_inv_prod, hi_fold * hi_inv_prod) + (lo_fold.0 * lo_inv_prod, hi_fold.0 * hi_inv_prod) } #[cfg(test)] mod tests { - use super::{super::dynamic_dory_standard_basis_helper::tests::naive_fold, *}; - use crate::{ - base::polynomial::compute_evaluation_vector, - proof_primitive::dory::{ - deferred_msm::DeferredMSM, test_rng, PublicParameters, VerifierState, - }, + use super::*; + use crate::proof_primitive::{ + dory::{deferred_msm::DeferredMSM, test_rng, PublicParameters, VerifierState}, + dynamic_matrix_utils::standard_basis_helper::{compute_dynamic_vecs, tests::naive_fold}, }; - #[test] - fn we_can_compute_dynamic_vecs_for_length_0_point() { - let point = vec![]; - let expected_lo_vec = vec![F::from(1), F::from(0)]; - let expected_hi_vec = vec![F::from(1), F::from(1)]; - let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); - assert_eq!(expected_lo_vec, lo_vec); - assert_eq!(expected_hi_vec, hi_vec); - } - - #[test] - fn we_can_compute_dynamic_vecs_for_length_1_point() { - let point = vec![F::from(2)]; - let expected_lo_vec = vec![F::from(1 - 2), F::from(2)]; - let expected_hi_vec = vec![F::from(1), F::from(1)]; - let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); - assert_eq!(expected_lo_vec, lo_vec); - assert_eq!(expected_hi_vec, hi_vec); - } - - #[test] - fn we_can_compute_dynamic_vecs_for_length_2_point() { - let point = vec![F::from(2), F::from(3)]; - let expected_lo_vec = vec![ - F::from((1 - 2) * (1 - 3)), - F::from(2 * (1 - 3)), - F::from((1 - 2) * 3), - F::from(2 * 3), - ]; - let expected_hi_vec = vec![ - F::from(1), - F::from(1), - F::from(3) / F::from(1 - 3), - F::from(0), - ]; - let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); - assert_eq!(expected_lo_vec, lo_vec); - assert_eq!(expected_hi_vec, hi_vec); - } - - #[test] - fn we_can_compute_dynamic_vecs_for_length_3_point() { - let point = vec![F::from(2), F::from(3), F::from(5)]; - let expected_lo_vec = vec![ - F::from((1 - 2) * (1 - 3)), - F::from(2 * (1 - 3)), - F::from((1 - 2) * 3), - F::from(2 * 3), - ]; - let expected_hi_vec = vec![ - F::from(1 - 5), - F::from(1 - 5), - F::from((1 - 5) * 3) / F::from(1 - 3), - F::from(5), - ]; - let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); - assert_eq!(expected_lo_vec, lo_vec); - assert_eq!(expected_hi_vec, hi_vec); - } - - #[test] - fn we_can_compute_dynamic_vecs_that_matches_evaluation_vec() { - use ark_std::UniformRand; - let mut rng = ark_std::test_rng(); - for num_vars in 0..20 { - let point: Vec<_> = core::iter::repeat_with(|| F::rand(&mut rng)) - .take(num_vars) - .collect(); - let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); - let mut eval_vec = vec![F::ZERO; 1 << num_vars]; - compute_evaluation_vector(&mut eval_vec, &point); - for (i, val) in eval_vec.into_iter().enumerate() { - let (row, column) = row_and_column_from_index(i); - assert_eq!(hi_vec[row] * lo_vec[column], val); - } - } - } - #[test] fn we_can_fold_dynamic_tensors() { use ark_std::{test_rng, UniformRand}; @@ -249,9 +148,17 @@ mod tests { .take(nu) .collect_vec(); - let (mut lo_vec, mut hi_vec) = compute_dynamic_vecs(&point); - naive_fold(&mut lo_vec, &alphas); - naive_fold(&mut hi_vec, &alpha_invs); + let (mut lo_vec, mut hi_vec) = compute_dynamic_vecs( + bytemuck::TransparentWrapper::wrap_slice(&point) as &[DoryScalar], + ); + naive_fold( + &mut lo_vec, + bytemuck::TransparentWrapper::wrap_slice(&alphas) as &[DoryScalar], + ); + naive_fold( + &mut hi_vec, + bytemuck::TransparentWrapper::wrap_slice(&alpha_invs) as &[DoryScalar], + ); let state = ExtendedVerifierState { s1_tensor: point, @@ -270,8 +177,8 @@ mod tests { }; let (lo_fold, hi_fold) = fold_dynamic_tensors(&state); - assert_eq!(lo_fold, lo_vec[0]); - assert_eq!(hi_fold, hi_vec[0]); + assert_eq!(lo_fold, lo_vec[0].0); + assert_eq!(hi_fold, hi_vec[0].0); } } diff --git a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_standard_basis_helper.rs b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_standard_basis_helper.rs deleted file mode 100644 index c46308b54..000000000 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_standard_basis_helper.rs +++ /dev/null @@ -1,556 +0,0 @@ -//! This module provides the `build_standard_basis_vecs` method, which is used in converting a point to a -//! vector used in a Vector-Matrix-Vector product in the dynamic dory scheme. - -use super::F; -use ark_ff::{AdditiveGroup, Field}; - -#[allow(dead_code)] -/// This method produces evaluation vectors from a point. This is a helper method for generating a Vector-Matrix-Vector product in the dynamic dory scheme. -/// -/// The ith element of the `lo_vec` is essentially the ith monomial basis element (lexicographically). -/// The ith element of the `hi_vec` is essentially the jth monomial basis element where `j = row_start_index(i)`. -/// -/// NOTE: the `lo_vec` and `hi_vec` are scaled by `lo_vec[0]` and `hi_vec[0]` respectively. -/// NOTE: `lo_vec` and `hi_vec` should otherwise consist entirely of zeros in order to ensure correct output. -pub(super) fn compute_dynamic_standard_basis_vecs(point: &[F], lo_vec: &mut [F], hi_vec: &mut [F]) { - let nu = point.len() / 2 + 1; - debug_assert_eq!(lo_vec.len(), 1 << nu); - debug_assert_eq!(hi_vec.len(), 1 << nu); - for i in 1..nu { - build_partial_second_half_standard_basis_vecs( - &point[..2 * i - 1], - &mut lo_vec[..1 << i], - &mut hi_vec[..1 << i], - true, - ); - } - // Note: if we don't have the "full" point, we shouldn't fill up the last quarter because it should be all zeros. - build_partial_second_half_standard_basis_vecs(point, lo_vec, hi_vec, point.len() % 2 == 1); - // Add the most significant variable, which was not included before in order to allow simple copying to work. - point.iter().skip(1).enumerate().for_each(|(i, v)| { - let p = i / 2; - let o = 2 + i % 2; - (o << p..(o + 1) << p).for_each(|k| hi_vec[k] *= v); - }); -} - -fn build_partial_second_half_standard_basis_vecs( - point: &[F], - lo_vec: &mut [F], - hi_vec: &mut [F], - add_last_quarter: bool, -) { - let nu = point.len() / 2 + 1; - debug_assert_eq!(lo_vec.len(), 1 << nu); - debug_assert_eq!(hi_vec.len(), 1 << nu); - if nu == 1 { - lo_vec[1] = if point.is_empty() { - F::ZERO - } else { - lo_vec[0] * point[0] - }; - hi_vec[1] = hi_vec[0]; - } else { - let (lo_half0, lo_half1) = lo_vec.split_at_mut(1 << (nu - 1)); - lo_half0 - .iter() - .zip(lo_half1) - .for_each(|(l, h)| *h = *l * point[nu - 1]); - if nu == 2 { - hi_vec[2] = hi_vec[0]; - if add_last_quarter { - hi_vec[3] = hi_vec[1]; - } - } else { - let (hi_half0, hi_half1) = hi_vec.split_at_mut(1 << (nu - 1)); - let (_, hi_quarter1) = hi_half0.split_at(1 << (nu - 2)); - let (hi_quarter2, hi_quarter3) = hi_half1.split_at_mut(1 << (nu - 2)); - let (_, hi_eighth3) = hi_quarter1.split_at(1 << (nu - 3)); - let (hi_eighth4, hi_eighth5) = hi_quarter2.split_at_mut(1 << (nu - 3)); - let (hi_eighth6, hi_eighth7) = hi_quarter3.split_at_mut(1 << (nu - 3)); - // Fill up quarter #2 (from 2/4..3/4). - hi_eighth3 - .iter() - .zip(hi_eighth4.iter_mut().zip(hi_eighth5)) - .for_each(|(&source, (target_lo, target_hi))| { - // Copy eighth #3 (from 3/8..4/8) to eighth #4 (4/8..5/8). - *target_lo = source; - // Copy eighth #3 (from 3/8..4/8) to eighth #5 (5/8..6/8) - // and multiply by the third from the last element in point. - *target_hi = source * point[2 * nu - 4]; - }); - if add_last_quarter { - // Fill up quarter #4 (from 3/4..4/4). - hi_quarter2 - .iter() - .step_by(2) - .zip(hi_eighth6.iter_mut().zip(hi_eighth7)) - .for_each(|(&source, (target_lo, target_hi))| { - // Copy every other in quarter #2 (from 2/4..3/4) to eighth #6 (6/8..7/8). - *target_lo = source; - // Copy every other in quarter #2 (from 2/4..3/4) to eighth #6 (7/8..8/8). - // and multiply by the second from the last element in point. - *target_hi = source * point[2 * nu - 3]; - }); - } - } - } -} - -#[allow(dead_code)] -pub(super) fn fold_dynamic_standard_basis_tensors( - point: &[F], - alphas: &[F], - alpha_invs: &[F], -) -> (F, F) { - let nu = point.len() / 2 + 1; - debug_assert_eq!(alphas.len(), nu); - debug_assert_eq!(alpha_invs.len(), nu); - let lo_fold = if point.is_empty() { - alphas[0] - } else { - point.iter().zip(alphas).map(|(v, a)| v + a).product() - }; - let hi_fold = point - .iter() - .enumerate() - .fold( - (alpha_invs[0] + F::ONE, F::ZERO), - |(acc, prev_partial), (i, &p)| { - if i == 0 { - (acc, F::ZERO) - } else if i == 1 { - (acc * alpha_invs[1] + p * alpha_invs[0], F::ZERO) - } else if i % 2 == 0 { - let partial = (i / 2 + 1..i) - .zip(alpha_invs) - .map(|(k, a)| point[k] + a) - .product(); - (acc + p * partial, partial) - } else { - ( - acc * alpha_invs[i / 2 + 1] - + p * alpha_invs[i / 2] - * (point[i - 1] + alpha_invs[i / 2 - 1]) - * prev_partial, - F::ZERO, - ) - } - }, - ) - .0; - (lo_fold, hi_fold) -} - -#[cfg(test)] -pub(super) mod tests { - use super::{super::dynamic_dory_structure::row_start_index, *}; - - #[test] - fn we_can_compute_dynamic_standard_basis_vecs_from_length_0_point() { - let mut lo_vec = vec![F::ZERO; 2]; - let mut hi_vec = vec![F::ZERO; 2]; - lo_vec[0] = F::from(2); - hi_vec[0] = F::from(3); - let point = vec![]; - let lo_vec_expected = vec![F::from(2), F::ZERO]; - let hi_vec_expected = vec![F::from(3), F::from(3)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - assert_eq!(lo_vec, lo_vec_expected); - assert_eq!(hi_vec, hi_vec_expected); - } - #[test] - fn we_can_compute_dynamic_standard_basis_vecs_from_length_1_point() { - let mut lo_vec = vec![F::ZERO; 2]; - let mut hi_vec = vec![F::ZERO; 2]; - lo_vec[0] = F::from(2); - hi_vec[0] = F::from(3); - let point = vec![F::from(5)]; - let lo_vec_expected = vec![F::from(2), F::from(2 * 5)]; - let hi_vec_expected = vec![F::from(3), F::from(3)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - assert_eq!(lo_vec, lo_vec_expected); - assert_eq!(hi_vec, hi_vec_expected); - } - #[test] - fn we_can_compute_dynamic_standard_basis_vecs_from_length_2_point() { - let mut lo_vec = vec![F::ZERO; 4]; - let mut hi_vec = vec![F::ZERO; 4]; - lo_vec[0] = F::from(2); - hi_vec[0] = F::from(3); - let point = vec![F::from(5), F::from(7)]; - let lo_vec_expected = vec![ - F::from(2), - F::from(2 * 5), - F::from(2 * 7), - F::from(2 * 5 * 7), - ]; - let hi_vec_expected = vec![F::from(3), F::from(3), F::from(3 * 7), F::ZERO]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - assert_eq!(lo_vec, lo_vec_expected); - assert_eq!(hi_vec, hi_vec_expected); - } - #[test] - fn we_can_compute_dynamic_standard_basis_vecs_from_length_3_point() { - let mut lo_vec = vec![F::ZERO; 4]; - let mut hi_vec = vec![F::ZERO; 4]; - lo_vec[0] = F::from(2); - hi_vec[0] = F::from(3); - let point = vec![F::from(5), F::from(7), F::from(11)]; - let lo_vec_expected = vec![ - F::from(2), - F::from(2 * 5), - F::from(2 * 7), - F::from(2 * 5 * 7), - ]; - let hi_vec_expected = vec![F::from(3), F::from(3), F::from(3 * 7), F::from(3 * 11)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - assert_eq!(lo_vec, lo_vec_expected); - assert_eq!(hi_vec, hi_vec_expected); - } - #[test] - fn we_can_compute_dynamic_standard_basis_vecs_from_length_4_point() { - let mut lo_vec = vec![F::ZERO; 8]; - let mut hi_vec = vec![F::ZERO; 8]; - lo_vec[0] = F::from(2); - hi_vec[0] = F::from(3); - let point = vec![F::from(5), F::from(7), F::from(11), F::from(13)]; - let lo_vec_expected = vec![ - F::from(2), - F::from(2 * 5), - F::from(2 * 7), - F::from(2 * 5 * 7), - F::from(2 * 11), - F::from(2 * 5 * 11), - F::from(2 * 7 * 11), - F::from(2 * 5 * 7 * 11), - ]; - let hi_vec_expected = vec![ - F::from(3), - F::from(3), - F::from(3 * 7), - F::from(3 * 11), - F::from(3 * 13), - F::from(3 * 11 * 13), - F::ZERO, - F::ZERO, - ]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - assert_eq!(lo_vec, lo_vec_expected); - assert_eq!(hi_vec, hi_vec_expected); - } - #[test] - fn we_can_compute_dynamic_standard_basis_vecs_from_length_5_point() { - let mut lo_vec = vec![F::ZERO; 8]; - let mut hi_vec = vec![F::ZERO; 8]; - lo_vec[0] = F::from(2); - hi_vec[0] = F::from(3); - let point = vec![ - F::from(5), - F::from(7), - F::from(11), - F::from(13), - F::from(17), - ]; - let lo_vec_expected = vec![ - F::from(2), - F::from(2 * 5), - F::from(2 * 7), - F::from(2 * 5 * 7), - F::from(2 * 11), - F::from(2 * 5 * 11), - F::from(2 * 7 * 11), - F::from(2 * 5 * 7 * 11), - ]; - let hi_vec_expected = vec![ - F::from(3), - F::from(3), - F::from(3 * 7), - F::from(3 * 11), - F::from(3 * 13), - F::from(3 * 11 * 13), - F::from(3 * 17), - F::from(3 * 13 * 17), - ]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - assert_eq!(lo_vec, lo_vec_expected); - assert_eq!(hi_vec, hi_vec_expected); - } - - /// Computes the evaluation of a basis monomial at the given point. - /// - /// In other words, the result is `prod point[i]^(b[i])` where - /// `index = sum 2^i*b[i]` and `b[i]` is `0` or `1`. (i.e. `b` is the binary representation of `index`.) - /// Note: `point` is padded with zeros as needed. - /// - /// This method is primarily to test the `build_standard_basis_vecs` method. - fn get_binary_eval(index: usize, point: &[F]) -> F { - core::iter::successors(Some(index), |&k| match k >> 1 { - 0 => None, - k => Some(k), - }) - .enumerate() - .filter_map(|(i, b)| { - if b % 2 == 0 { - None - } else { - Some(point.get(i).copied().unwrap_or(F::ZERO)) - } - }) - .product() - } - - #[test] - fn we_can_compute_dynamic_random_standard_basis_vecs() { - use ark_std::{test_rng, UniformRand}; - use itertools::Itertools; - let mut rng = test_rng(); - for num_vars in 0..10 { - let point = core::iter::repeat_with(|| F::rand(&mut rng)) - .take(num_vars) - .collect_vec(); - let alpha = F::rand(&mut rng); - let beta = F::rand(&mut rng); - let nu = point.len() / 2 + 1; - let mut lo_vec = vec![F::ZERO; 1 << nu]; - let mut hi_vec = vec![F::ZERO; 1 << nu]; - lo_vec[0] = alpha; - hi_vec[0] = beta; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - for i in 0..1 << nu { - assert_eq!(lo_vec[i], alpha * get_binary_eval(i, &point)); - assert_eq!( - hi_vec[i], - beta * get_binary_eval(row_start_index(i), &point) - ); - } - } - } - - #[test] - fn we_can_fold_dynamic_standard_basis_tensors_of_length_0_point() { - let mut lo_vec = vec![F::ZERO; 2]; - let mut hi_vec = vec![F::ZERO; 2]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - let point = vec![]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = vec![F::from(200)]; - let alpha_invs = vec![F::from(300)]; - let lo_fold_expected = lo_vec[0] * F::from(200) + lo_vec[1]; - let hi_fold_expected = hi_vec[0] * F::from(300) + hi_vec[1]; - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - assert_eq!(lo_fold, lo_fold_expected); - assert_eq!(hi_fold, hi_fold_expected); - } - #[test] - fn we_can_fold_dynamic_standard_basis_tensors_of_length_1_point() { - let mut lo_vec = vec![F::ZERO; 2]; - let mut hi_vec = vec![F::ZERO; 2]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - let point = vec![F::from(5)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = vec![F::from(200)]; - let alpha_invs = vec![F::from(300)]; - let lo_fold_expected = lo_vec[0] * F::from(200) + lo_vec[1]; - let hi_fold_expected = hi_vec[0] * F::from(300) + hi_vec[1]; - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - assert_eq!(lo_fold, lo_fold_expected); - assert_eq!(hi_fold, hi_fold_expected); - } - #[test] - fn we_can_fold_dynamic_standard_basis_tensors_of_length_2_point() { - let mut lo_vec = vec![F::ZERO; 4]; - let mut hi_vec = vec![F::ZERO; 4]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - let point = vec![F::from(5), F::from(7)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = vec![F::from(200), F::from(201)]; - let alpha_invs = vec![F::from(300), F::from(301)]; - let lo_fold_expected = lo_vec[0] * F::from(200 * 201) - + lo_vec[1] * F::from(201) - + lo_vec[2] * F::from(200) - + lo_vec[3]; - let hi_fold_expected = hi_vec[0] * F::from(300 * 301) - + hi_vec[1] * F::from(301) - + hi_vec[2] * F::from(300) - + hi_vec[3]; - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - assert_eq!(lo_fold, lo_fold_expected); - assert_eq!(hi_fold, hi_fold_expected); - } - #[test] - fn we_can_fold_dynamic_standard_basis_tensors_of_length_3_point() { - let mut lo_vec = vec![F::ZERO; 4]; - let mut hi_vec = vec![F::ZERO; 4]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - let point = vec![F::from(5), F::from(7), F::from(11)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = vec![F::from(200), F::from(201)]; - let alpha_invs = vec![F::from(300), F::from(301)]; - let lo_fold_expected = lo_vec[0] * F::from(200 * 201) - + lo_vec[1] * F::from(201) - + lo_vec[2] * F::from(200) - + lo_vec[3]; - let hi_fold_expected = hi_vec[0] * F::from(300 * 301) - + hi_vec[1] * F::from(301) - + hi_vec[2] * F::from(300) - + hi_vec[3]; - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - assert_eq!(lo_fold, lo_fold_expected); - assert_eq!(hi_fold, hi_fold_expected); - } - #[test] - fn we_can_fold_dynamic_standard_basis_tensors_of_length_4_point() { - let mut lo_vec = vec![F::ZERO; 8]; - let mut hi_vec = vec![F::ZERO; 8]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - let point = vec![F::from(5), F::from(7), F::from(11), F::from(13)]; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = vec![F::from(200), F::from(201), F::from(202)]; - let alpha_invs = vec![F::from(300), F::from(301), F::from(302)]; - let lo_fold_expected = lo_vec[0] * F::from(200 * 201 * 202) - + lo_vec[1] * F::from(201 * 202) - + lo_vec[2] * F::from(200 * 202) - + lo_vec[3] * F::from(202) - + lo_vec[4] * F::from(200 * 201) - + lo_vec[5] * F::from(201) - + lo_vec[6] * F::from(200) - + lo_vec[7]; - let hi_fold_expected = hi_vec[0] * F::from(300 * 301 * 302) - + hi_vec[1] * F::from(301 * 302) - + hi_vec[2] * F::from(300 * 302) - + hi_vec[3] * F::from(302) - + hi_vec[4] * F::from(300 * 301) - + hi_vec[5] * F::from(301) - + hi_vec[6] * F::from(300) - + hi_vec[7]; - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - assert_eq!(lo_fold, lo_fold_expected); - assert_eq!(hi_fold, hi_fold_expected); - } - #[test] - fn we_can_fold_dynamic_standard_basis_tensors_of_length_5_point() { - let mut lo_vec = vec![F::ZERO; 8]; - let mut hi_vec = vec![F::ZERO; 8]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - let point = [5, 7, 11, 13, 17].map(F::from); - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = vec![F::from(200), F::from(201), F::from(202)]; - let alpha_invs = vec![F::from(300), F::from(301), F::from(302)]; - let lo_fold_expected = lo_vec[0] * F::from(200 * 201 * 202) - + lo_vec[1] * F::from(201 * 202) - + lo_vec[2] * F::from(200 * 202) - + lo_vec[3] * F::from(202) - + lo_vec[4] * F::from(200 * 201) - + lo_vec[5] * F::from(201) - + lo_vec[6] * F::from(200) - + lo_vec[7]; - let hi_fold_expected = hi_vec[0] * F::from(300 * 301 * 302) - + hi_vec[1] * F::from(301 * 302) - + hi_vec[2] * F::from(300 * 302) - + hi_vec[3] * F::from(302) - + hi_vec[4] * F::from(300 * 301) - + hi_vec[5] * F::from(301) - + hi_vec[6] * F::from(300) - + hi_vec[7]; - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - assert_eq!(lo_fold, lo_fold_expected); - assert_eq!(hi_fold, hi_fold_expected); - } - - pub fn naive_fold(mut vec: &mut [F], fold_factors: &[F]) { - let nu = fold_factors.len(); - assert_eq!(vec.len(), 1 << fold_factors.len()); - for i in (0..nu).rev() { - let (lo, hi) = vec.split_at_mut(vec.len() / 2); - lo.iter_mut().zip(hi).for_each(|(l, h)| { - *l *= fold_factors[i]; - *l += h; - }); - vec = lo; - } - } - #[test] - fn we_can_naive_fold_length_0_fold_factors() { - let fold_factors = vec![]; - let mut vec = vec![F::from(100)]; - naive_fold(&mut vec, &fold_factors); - assert_eq!(vec[0], F::from(100)); - } - #[test] - fn we_can_naive_fold_length_1_fold_factors() { - let fold_factors = vec![F::from(2)]; - let mut vec = vec![F::from(100), F::from(101)]; - naive_fold(&mut vec, &fold_factors); - assert_eq!(vec[0], F::from(100 * 2 + 101)); - } - #[test] - fn we_can_naive_fold_length_2_fold_factors() { - let fold_factors = vec![F::from(2), F::from(3)]; - let mut vec = vec![F::from(100), F::from(101), F::from(102), F::from(103)]; - naive_fold(&mut vec, &fold_factors); - assert_eq!(vec[0], F::from(100 * 2 * 3 + 101 * 3 + 102 * 2 + 103)); - } - #[test] - fn we_can_naive_fold_length_3_fold_factors() { - let fold_factors = vec![F::from(2), F::from(3), F::from(5)]; - let mut vec = [100, 101, 102, 103, 104, 105, 106, 107].map(F::from); - naive_fold(&mut vec, &fold_factors); - assert_eq!( - vec[0], - F::from( - 100 * 2 * 3 * 5 - + 101 * 3 * 5 - + 102 * 2 * 5 - + 103 * 5 - + 104 * 2 * 3 - + 105 * 3 - + 106 * 2 - + 107 - ) - ); - } - - #[test] - fn we_can_fold_dynamic_random_standard_basis_tensors() { - use ark_std::{test_rng, UniformRand}; - use itertools::Itertools; - let mut rng = test_rng(); - for num_vars in 0..10 { - let point = core::iter::repeat_with(|| F::rand(&mut rng)) - .take(num_vars) - .collect_vec(); - let nu = point.len() / 2 + 1; - let mut lo_vec = vec![F::ZERO; 1 << nu]; - let mut hi_vec = vec![F::ZERO; 1 << nu]; - lo_vec[0] = F::ONE; - hi_vec[0] = F::ONE; - compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); - - let alphas = core::iter::repeat_with(|| F::rand(&mut rng)) - .take(nu) - .collect_vec(); - let alpha_invs = core::iter::repeat_with(|| F::rand(&mut rng)) - .take(nu) - .collect_vec(); - let (lo_fold, hi_fold) = - fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); - naive_fold(&mut lo_vec, &alphas); - naive_fold(&mut hi_vec, &alpha_invs); - assert_eq!(lo_fold, lo_vec[0]); - assert_eq!(hi_fold, hi_vec[0]); - } - } -} diff --git a/crates/proof-of-sql/src/proof_primitive/dory/mod.rs b/crates/proof-of-sql/src/proof_primitive/dory/mod.rs index f0175c50e..0041fa57b 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/mod.rs +++ b/crates/proof-of-sql/src/proof_primitive/dory/mod.rs @@ -150,8 +150,6 @@ mod dynamic_dory_commitment_helper_cpu; #[cfg(feature = "blitzar")] mod dynamic_dory_commitment_helper_gpu; mod dynamic_dory_helper; -mod dynamic_dory_standard_basis_helper; -mod dynamic_dory_structure; #[cfg(not(feature = "blitzar"))] use dynamic_dory_commitment_helper_cpu::compute_dynamic_dory_commitments; #[cfg(feature = "blitzar")] diff --git a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_structure.rs b/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/matrix_structure.rs similarity index 99% rename from crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_structure.rs rename to crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/matrix_structure.rs index 03f6ffaa3..35487144a 100644 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_structure.rs +++ b/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/matrix_structure.rs @@ -1,4 +1,4 @@ -//! This module gives some utility functions for determining the position of data within the dynamic dory matrix +//! This module gives some utility functions for determining the position of data within the dynamic dory/hyrax matrix //! //! In general, the data is filled in such a way that the new data is always in the last row, and the row size //! (and consequently, the matrix size) is strictly increasing. @@ -156,7 +156,7 @@ mod tests { #[test] fn we_can_find_the_full_width_of_row() { // This corresponds to a matrix with 2^(N+1) rows. - let N = 20; + let n = 20; let mut expected_widths = Vec::new(); // First three rows are defined by the dynamic Dory structure. @@ -164,7 +164,7 @@ mod tests { expected_widths.extend(std::iter::repeat(2).take(2)); // The rest of the rows are defined by the pattern 3*2^n rows of length 4*2^n. - for n in 0..N { + for n in 0..n { let repeat_count = 3 * 2_usize.pow(n); let value = 4 * 2_usize.pow(n); expected_widths.extend(std::iter::repeat(value).take(repeat_count)); diff --git a/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/mod.rs b/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/mod.rs new file mode 100644 index 000000000..7922bbac0 --- /dev/null +++ b/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/mod.rs @@ -0,0 +1,4 @@ +/// Code for working with the structure of the dynamic matrix. +pub mod matrix_structure; +/// Code for working with vectors that interface with the dynamic matrix. +pub mod standard_basis_helper; diff --git a/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/standard_basis_helper.rs b/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/standard_basis_helper.rs new file mode 100644 index 000000000..93a2c4fa1 --- /dev/null +++ b/crates/proof-of-sql/src/proof_primitive/dynamic_matrix_utils/standard_basis_helper.rs @@ -0,0 +1,726 @@ +use crate::base::scalar::Scalar; +use alloc::{vec, vec::Vec}; + +/// Compute the hi and lo vectors (or L and R) that are derived from `point`. +/// L and R are the vectors such that LMR is exactly the evaluation of `a` at the point `point`. +/// # Panics +/// This function requires that `point` has length at least as big as the number of rows in `M` that is created by `a`. +pub(crate) fn compute_dynamic_vecs(point: &[S]) -> (Vec, Vec) { + let nu = point.len() / 2 + 1; + let mut lo_vec = vec![S::ZERO; 1 << nu]; + let mut hi_vec = vec![S::ZERO; 1 << nu]; + lo_vec[0] = point.iter().take(nu).map(|b| S::ONE - *b).product(); + hi_vec[0] = point.iter().skip(nu).map(|b| S::ONE - *b).product(); + let standard_basis_point: Vec = point + .iter() + .map(|b| (S::ONE - *b).inv().expect("Values in point cannot be 1.") - S::ONE) + .collect(); + compute_dynamic_standard_basis_vecs(&standard_basis_point, &mut lo_vec, &mut hi_vec); + (lo_vec, hi_vec) +} + +/// This method produces evaluation vectors from a point. This is a helper method for generating a Vector-Matrix-Vector product in the dynamic dory and hyrax schemes. +/// +/// The ith element of the `lo_vec` is essentially the ith monomial basis element (lexicographically). +/// The ith element of the `hi_vec` is essentially the jth monomial basis element where `j = row_start_index(i)`. +/// +/// NOTE: the `lo_vec` and `hi_vec` are scaled by `lo_vec[0]` and `hi_vec[0]` respectively. +/// NOTE: `lo_vec` and `hi_vec` should otherwise consist entirely of zeros in order to ensure correct output. +fn compute_dynamic_standard_basis_vecs(point: &[S], lo_vec: &mut [S], hi_vec: &mut [S]) { + let nu = point.len() / 2 + 1; + debug_assert_eq!(lo_vec.len(), 1 << nu); + debug_assert_eq!(hi_vec.len(), 1 << nu); + for i in 1..nu { + build_partial_second_half_standard_basis_vecs( + &point[..2 * i - 1], + &mut lo_vec[..1 << i], + &mut hi_vec[..1 << i], + true, + ); + } + // Note: if we don't have the "full" point, we shouldn't fill up the last quarter because it should be all zeros. + build_partial_second_half_standard_basis_vecs(point, lo_vec, hi_vec, point.len() % 2 == 1); + // Add the most significant variable, which was not included before in order to allow simple copying to work. + point.iter().skip(1).enumerate().for_each(|(i, v)| { + let p = i / 2; + let o = 2 + i % 2; + (o << p..(o + 1) << p).for_each(|k| hi_vec[k] *= *v); + }); +} + +fn build_partial_second_half_standard_basis_vecs( + point: &[S], + lo_vec: &mut [S], + hi_vec: &mut [S], + add_last_quarter: bool, +) { + let nu = point.len() / 2 + 1; + debug_assert_eq!(lo_vec.len(), 1 << nu); + debug_assert_eq!(hi_vec.len(), 1 << nu); + if nu == 1 { + lo_vec[1] = if point.is_empty() { + S::ZERO + } else { + lo_vec[0] * point[0] + }; + hi_vec[1] = hi_vec[0]; + } else { + let (lo_half0, lo_half1) = lo_vec.split_at_mut(1 << (nu - 1)); + lo_half0 + .iter() + .zip(lo_half1) + .for_each(|(l, h)| *h = *l * point[nu - 1]); + if nu == 2 { + hi_vec[2] = hi_vec[0]; + if add_last_quarter { + hi_vec[3] = hi_vec[1]; + } + } else { + let (hi_half0, hi_half1) = hi_vec.split_at_mut(1 << (nu - 1)); + let (_, hi_quarter1) = hi_half0.split_at(1 << (nu - 2)); + let (hi_quarter2, hi_quarter3) = hi_half1.split_at_mut(1 << (nu - 2)); + let (_, hi_eighth3) = hi_quarter1.split_at(1 << (nu - 3)); + let (hi_eighth4, hi_eighth5) = hi_quarter2.split_at_mut(1 << (nu - 3)); + let (hi_eighth6, hi_eighth7) = hi_quarter3.split_at_mut(1 << (nu - 3)); + // Fill up quarter #2 (from 2/4..3/4). + hi_eighth3 + .iter() + .zip(hi_eighth4.iter_mut().zip(hi_eighth5)) + .for_each(|(&source, (target_lo, target_hi))| { + // Copy eighth #3 (from 3/8..4/8) to eighth #4 (4/8..5/8). + *target_lo = source; + // Copy eighth #3 (from 3/8..4/8) to eighth #5 (5/8..6/8) + // and multiply by the third from the last element in point. + *target_hi = source * point[2 * nu - 4]; + }); + if add_last_quarter { + // Fill up quarter #4 (from 3/4..4/4). + hi_quarter2 + .iter() + .step_by(2) + .zip(hi_eighth6.iter_mut().zip(hi_eighth7)) + .for_each(|(&source, (target_lo, target_hi))| { + // Copy every other in quarter #2 (from 2/4..3/4) to eighth #6 (6/8..7/8). + *target_lo = source; + // Copy every other in quarter #2 (from 2/4..3/4) to eighth #6 (7/8..8/8). + // and multiply by the second from the last element in point. + *target_hi = source * point[2 * nu - 3]; + }); + } + } + } +} + +pub(crate) fn fold_dynamic_standard_basis_tensors( + point: &[S], + alphas: &[S], + alpha_invs: &[S], +) -> (S, S) { + let nu = point.len() / 2 + 1; + debug_assert_eq!(alphas.len(), nu); + debug_assert_eq!(alpha_invs.len(), nu); + let lo_fold = if point.is_empty() { + alphas[0] + } else { + point.iter().zip(alphas).map(|(v, a)| *v + *a).product() + }; + let hi_fold = point + .iter() + .enumerate() + .fold( + (alpha_invs[0] + S::ONE, S::ZERO), + |(acc, prev_partial), (i, &p)| { + if i == 0 { + (acc, S::ZERO) + } else if i == 1 { + (acc * alpha_invs[1] + p * alpha_invs[0], S::ZERO) + } else if i % 2 == 0 { + let partial = (i / 2 + 1..i) + .zip(alpha_invs) + .map(|(k, a)| point[k] + *a) + .product(); + (acc + p * partial, partial) + } else { + ( + acc * alpha_invs[i / 2 + 1] + + p * alpha_invs[i / 2] + * (point[i - 1] + alpha_invs[i / 2 - 1]) + * prev_partial, + S::ZERO, + ) + } + }, + ) + .0; + (lo_fold, hi_fold) +} + +#[cfg(test)] +pub(crate) mod tests { + + use super::*; + use crate::{ + base::{polynomial::compute_evaluation_vector, scalar::MontScalar}, + proof_primitive::{ + dory::DoryScalar, + dynamic_matrix_utils::{ + matrix_structure::{row_and_column_from_index, row_start_index}, + standard_basis_helper::{ + compute_dynamic_standard_basis_vecs, fold_dynamic_standard_basis_tensors, + }, + }, + }, + }; + use ark_bls12_381::Fr as F; + use ark_ff::AdditiveGroup; + + pub fn naive_fold(mut vec: &mut [S], fold_factors: &[S]) { + let nu = fold_factors.len(); + assert_eq!(vec.len(), 1 << fold_factors.len()); + for i in (0..nu).rev() { + let (lo, hi) = vec.split_at_mut(vec.len() / 2); + lo.iter_mut().zip(hi).for_each(|(l, h)| { + *l *= fold_factors[i]; + *l += *h; + }); + vec = lo; + } + } + + #[test] + fn we_can_compute_dynamic_standard_basis_vecs_from_length_0_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 2]; + let mut hi_vec = vec![DoryScalar::ZERO; 2]; + lo_vec[0] = DoryScalar::from(2); + hi_vec[0] = DoryScalar::from(3); + let point = vec![]; + let lo_vec_expected = vec![DoryScalar::from(2), DoryScalar::ZERO]; + let hi_vec_expected = vec![DoryScalar::from(3), DoryScalar::from(3)]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + assert_eq!(lo_vec, lo_vec_expected); + assert_eq!(hi_vec, hi_vec_expected); + } + #[test] + fn we_can_compute_dynamic_standard_basis_vecs_from_length_1_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 2]; + let mut hi_vec = vec![DoryScalar::ZERO; 2]; + lo_vec[0] = DoryScalar::from(2); + hi_vec[0] = DoryScalar::from(3); + let point = vec![DoryScalar::from(5)]; + let lo_vec_expected = vec![DoryScalar::from(2), DoryScalar::from(2 * 5)]; + let hi_vec_expected = vec![DoryScalar::from(3), DoryScalar::from(3)]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + assert_eq!(lo_vec, lo_vec_expected); + assert_eq!(hi_vec, hi_vec_expected); + } + #[test] + fn we_can_compute_dynamic_standard_basis_vecs_from_length_2_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 4]; + let mut hi_vec = vec![DoryScalar::ZERO; 4]; + lo_vec[0] = DoryScalar::from(2); + hi_vec[0] = DoryScalar::from(3); + let point = vec![DoryScalar::from(5), DoryScalar::from(7)]; + let lo_vec_expected = vec![ + DoryScalar::from(2), + DoryScalar::from(2 * 5), + DoryScalar::from(2 * 7), + DoryScalar::from(2 * 5 * 7), + ]; + let hi_vec_expected = vec![ + DoryScalar::from(3), + DoryScalar::from(3), + DoryScalar::from(3 * 7), + DoryScalar::ZERO, + ]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + assert_eq!(lo_vec, lo_vec_expected); + assert_eq!(hi_vec, hi_vec_expected); + } + #[test] + fn we_can_compute_dynamic_standard_basis_vecs_from_length_3_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 4]; + let mut hi_vec = vec![DoryScalar::ZERO; 4]; + lo_vec[0] = DoryScalar::from(2); + hi_vec[0] = DoryScalar::from(3); + let point = vec![ + DoryScalar::from(5), + DoryScalar::from(7), + DoryScalar::from(11), + ]; + let lo_vec_expected = vec![ + DoryScalar::from(2), + DoryScalar::from(2 * 5), + DoryScalar::from(2 * 7), + DoryScalar::from(2 * 5 * 7), + ]; + let hi_vec_expected = vec![ + DoryScalar::from(3), + DoryScalar::from(3), + DoryScalar::from(3 * 7), + DoryScalar::from(3 * 11), + ]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + assert_eq!(lo_vec, lo_vec_expected); + assert_eq!(hi_vec, hi_vec_expected); + } + #[test] + fn we_can_compute_dynamic_standard_basis_vecs_from_length_4_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 8]; + let mut hi_vec = vec![DoryScalar::ZERO; 8]; + lo_vec[0] = DoryScalar::from(2); + hi_vec[0] = DoryScalar::from(3); + let point = vec![ + DoryScalar::from(5), + DoryScalar::from(7), + DoryScalar::from(11), + DoryScalar::from(13), + ]; + let lo_vec_expected = vec![ + DoryScalar::from(2), + DoryScalar::from(2 * 5), + DoryScalar::from(2 * 7), + DoryScalar::from(2 * 5 * 7), + DoryScalar::from(2 * 11), + DoryScalar::from(2 * 5 * 11), + DoryScalar::from(2 * 7 * 11), + DoryScalar::from(2 * 5 * 7 * 11), + ]; + let hi_vec_expected = vec![ + DoryScalar::from(3), + DoryScalar::from(3), + DoryScalar::from(3 * 7), + DoryScalar::from(3 * 11), + DoryScalar::from(3 * 13), + DoryScalar::from(3 * 11 * 13), + DoryScalar::ZERO, + DoryScalar::ZERO, + ]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + assert_eq!(lo_vec, lo_vec_expected); + assert_eq!(hi_vec, hi_vec_expected); + } + #[test] + fn we_can_compute_dynamic_standard_basis_vecs_from_length_5_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 8]; + let mut hi_vec = vec![DoryScalar::ZERO; 8]; + lo_vec[0] = DoryScalar::from(2); + hi_vec[0] = DoryScalar::from(3); + let point = vec![ + DoryScalar::from(5), + DoryScalar::from(7), + DoryScalar::from(11), + DoryScalar::from(13), + DoryScalar::from(17), + ]; + let lo_vec_expected = vec![ + DoryScalar::from(2), + DoryScalar::from(2 * 5), + DoryScalar::from(2 * 7), + DoryScalar::from(2 * 5 * 7), + DoryScalar::from(2 * 11), + DoryScalar::from(2 * 5 * 11), + DoryScalar::from(2 * 7 * 11), + DoryScalar::from(2 * 5 * 7 * 11), + ]; + let hi_vec_expected = vec![ + DoryScalar::from(3), + DoryScalar::from(3), + DoryScalar::from(3 * 7), + DoryScalar::from(3 * 11), + DoryScalar::from(3 * 13), + DoryScalar::from(3 * 11 * 13), + DoryScalar::from(3 * 17), + DoryScalar::from(3 * 13 * 17), + ]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + assert_eq!(lo_vec, lo_vec_expected); + assert_eq!(hi_vec, hi_vec_expected); + } + + /// Computes the evaluation of a basis monomial at the given point. + /// + /// In other words, the result is `prod point[i]^(b[i])` where + /// `index = sum 2^i*b[i]` and `b[i]` is `0` or `1`. (i.e. `b` is the binary representation of `index`.) + /// Note: `point` is padded with zeros as needed. + /// + /// This method is primarily to test the `build_standard_basis_vecs` method. + fn get_binary_eval(index: usize, point: &[F]) -> F { + core::iter::successors(Some(index), |&k| match k >> 1 { + 0 => None, + k => Some(k), + }) + .enumerate() + .filter_map(|(i, b)| { + if b % 2 == 0 { + None + } else { + Some(point.get(i).copied().unwrap_or(F::ZERO)) + } + }) + .product() + } + + #[test] + fn we_can_compute_dynamic_random_standard_basis_vecs() { + use ark_std::{test_rng, UniformRand}; + use itertools::Itertools; + let mut rng = test_rng(); + for num_vars in 0..10 { + let point = core::iter::repeat_with(|| F::rand(&mut rng)) + .take(num_vars) + .collect_vec(); + let alpha = MontScalar(F::rand(&mut rng)); + let beta = MontScalar(F::rand(&mut rng)); + let nu = point.len() / 2 + 1; + let mut lo_vec = vec![DoryScalar::ZERO; 1 << nu]; + let mut hi_vec = vec![DoryScalar::ZERO; 1 << nu]; + lo_vec[0] = alpha; + hi_vec[0] = beta; + compute_dynamic_standard_basis_vecs( + bytemuck::TransparentWrapper::wrap_slice(&point) as &[DoryScalar], + &mut lo_vec, + &mut hi_vec, + ); + for i in 0..1 << nu { + assert_eq!(lo_vec[i], alpha * MontScalar(get_binary_eval(i, &point))); + assert_eq!( + hi_vec[i], + beta * MontScalar(get_binary_eval(row_start_index(i), &point)) + ); + } + } + } + + #[test] + fn we_can_fold_dynamic_standard_basis_tensors_of_length_0_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 2]; + let mut hi_vec = vec![DoryScalar::ZERO; 2]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + let point = vec![]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = vec![DoryScalar::from(200)]; + let alpha_invs = vec![DoryScalar::from(300)]; + let lo_fold_expected = lo_vec[0] * DoryScalar::from(200) + lo_vec[1]; + let hi_fold_expected = hi_vec[0] * DoryScalar::from(300) + hi_vec[1]; + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + assert_eq!(lo_fold, lo_fold_expected); + assert_eq!(hi_fold, hi_fold_expected); + } + #[test] + fn we_can_fold_dynamic_standard_basis_tensors_of_length_1_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 2]; + let mut hi_vec = vec![DoryScalar::ZERO; 2]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + let point = vec![DoryScalar::from(5)]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = vec![DoryScalar::from(200)]; + let alpha_invs = vec![DoryScalar::from(300)]; + let lo_fold_expected = lo_vec[0] * DoryScalar::from(200) + lo_vec[1]; + let hi_fold_expected = hi_vec[0] * DoryScalar::from(300) + hi_vec[1]; + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + assert_eq!(lo_fold, lo_fold_expected); + assert_eq!(hi_fold, hi_fold_expected); + } + #[test] + fn we_can_fold_dynamic_standard_basis_tensors_of_length_2_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 4]; + let mut hi_vec = vec![DoryScalar::ZERO; 4]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + let point = vec![DoryScalar::from(5), DoryScalar::from(7)]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = vec![DoryScalar::from(200), DoryScalar::from(201)]; + let alpha_invs = vec![DoryScalar::from(300), DoryScalar::from(301)]; + let lo_fold_expected = lo_vec[0] * DoryScalar::from(200 * 201) + + lo_vec[1] * DoryScalar::from(201) + + lo_vec[2] * DoryScalar::from(200) + + lo_vec[3]; + let hi_fold_expected = hi_vec[0] * DoryScalar::from(300 * 301) + + hi_vec[1] * DoryScalar::from(301) + + hi_vec[2] * DoryScalar::from(300) + + hi_vec[3]; + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + assert_eq!(lo_fold, lo_fold_expected); + assert_eq!(hi_fold, hi_fold_expected); + } + #[test] + fn we_can_fold_dynamic_standard_basis_tensors_of_length_3_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 4]; + let mut hi_vec = vec![DoryScalar::ZERO; 4]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + let point = vec![ + DoryScalar::from(5), + DoryScalar::from(7), + DoryScalar::from(11), + ]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = vec![DoryScalar::from(200), DoryScalar::from(201)]; + let alpha_invs = vec![DoryScalar::from(300), DoryScalar::from(301)]; + let lo_fold_expected = lo_vec[0] * DoryScalar::from(200 * 201) + + lo_vec[1] * DoryScalar::from(201) + + lo_vec[2] * DoryScalar::from(200) + + lo_vec[3]; + let hi_fold_expected = hi_vec[0] * DoryScalar::from(300 * 301) + + hi_vec[1] * DoryScalar::from(301) + + hi_vec[2] * DoryScalar::from(300) + + hi_vec[3]; + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + assert_eq!(lo_fold, lo_fold_expected); + assert_eq!(hi_fold, hi_fold_expected); + } + #[test] + fn we_can_fold_dynamic_standard_basis_tensors_of_length_4_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 8]; + let mut hi_vec = vec![DoryScalar::ZERO; 8]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + let point = vec![ + DoryScalar::from(5), + DoryScalar::from(7), + DoryScalar::from(11), + DoryScalar::from(13), + ]; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = vec![ + DoryScalar::from(200), + DoryScalar::from(201), + DoryScalar::from(202), + ]; + let alpha_invs = vec![ + DoryScalar::from(300), + DoryScalar::from(301), + DoryScalar::from(302), + ]; + let lo_fold_expected = lo_vec[0] * DoryScalar::from(200 * 201 * 202) + + lo_vec[1] * DoryScalar::from(201 * 202) + + lo_vec[2] * DoryScalar::from(200 * 202) + + lo_vec[3] * DoryScalar::from(202) + + lo_vec[4] * DoryScalar::from(200 * 201) + + lo_vec[5] * DoryScalar::from(201) + + lo_vec[6] * DoryScalar::from(200) + + lo_vec[7]; + let hi_fold_expected = hi_vec[0] * DoryScalar::from(300 * 301 * 302) + + hi_vec[1] * DoryScalar::from(301 * 302) + + hi_vec[2] * DoryScalar::from(300 * 302) + + hi_vec[3] * DoryScalar::from(302) + + hi_vec[4] * DoryScalar::from(300 * 301) + + hi_vec[5] * DoryScalar::from(301) + + hi_vec[6] * DoryScalar::from(300) + + hi_vec[7]; + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + assert_eq!(lo_fold, lo_fold_expected); + assert_eq!(hi_fold, hi_fold_expected); + } + #[test] + fn we_can_fold_dynamic_standard_basis_tensors_of_length_5_point() { + let mut lo_vec = vec![DoryScalar::ZERO; 8]; + let mut hi_vec = vec![DoryScalar::ZERO; 8]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + let point = [5, 7, 11, 13, 17].map(DoryScalar::from); + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = vec![ + DoryScalar::from(200), + DoryScalar::from(201), + DoryScalar::from(202), + ]; + let alpha_invs = vec![ + DoryScalar::from(300), + DoryScalar::from(301), + DoryScalar::from(302), + ]; + let lo_fold_expected = lo_vec[0] * DoryScalar::from(200 * 201 * 202) + + lo_vec[1] * DoryScalar::from(201 * 202) + + lo_vec[2] * DoryScalar::from(200 * 202) + + lo_vec[3] * DoryScalar::from(202) + + lo_vec[4] * DoryScalar::from(200 * 201) + + lo_vec[5] * DoryScalar::from(201) + + lo_vec[6] * DoryScalar::from(200) + + lo_vec[7]; + let hi_fold_expected = hi_vec[0] * DoryScalar::from(300 * 301 * 302) + + hi_vec[1] * DoryScalar::from(301 * 302) + + hi_vec[2] * DoryScalar::from(300 * 302) + + hi_vec[3] * DoryScalar::from(302) + + hi_vec[4] * DoryScalar::from(300 * 301) + + hi_vec[5] * DoryScalar::from(301) + + hi_vec[6] * DoryScalar::from(300) + + hi_vec[7]; + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + assert_eq!(lo_fold, lo_fold_expected); + assert_eq!(hi_fold, hi_fold_expected); + } + #[test] + fn we_can_naive_fold_length_0_fold_factors() { + let fold_factors = vec![]; + let mut vec = vec![DoryScalar::from(100)]; + naive_fold(&mut vec, &fold_factors); + assert_eq!(vec[0], DoryScalar::from(100)); + } + #[test] + fn we_can_naive_fold_length_1_fold_factors() { + let fold_factors = vec![DoryScalar::from(2)]; + let mut vec = vec![DoryScalar::from(100), DoryScalar::from(101)]; + naive_fold(&mut vec, &fold_factors); + assert_eq!(vec[0], DoryScalar::from(100 * 2 + 101)); + } + #[test] + fn we_can_naive_fold_length_2_fold_factors() { + let fold_factors = vec![DoryScalar::from(2), DoryScalar::from(3)]; + let mut vec = vec![ + DoryScalar::from(100), + DoryScalar::from(101), + DoryScalar::from(102), + DoryScalar::from(103), + ]; + naive_fold(&mut vec, &fold_factors); + assert_eq!( + vec[0], + DoryScalar::from(100 * 2 * 3 + 101 * 3 + 102 * 2 + 103) + ); + } + #[test] + fn we_can_naive_fold_length_3_fold_factors() { + let fold_factors = vec![ + DoryScalar::from(2), + DoryScalar::from(3), + DoryScalar::from(5), + ]; + let mut vec = [100, 101, 102, 103, 104, 105, 106, 107].map(DoryScalar::from); + naive_fold(&mut vec, &fold_factors); + assert_eq!( + vec[0], + DoryScalar::from( + 100 * 2 * 3 * 5 + + 101 * 3 * 5 + + 102 * 2 * 5 + + 103 * 5 + + 104 * 2 * 3 + + 105 * 3 + + 106 * 2 + + 107 + ) + ); + } + + #[test] + fn we_can_fold_dynamic_random_standard_basis_tensors() { + use ark_std::{test_rng, UniformRand}; + use itertools::Itertools; + let mut rng = test_rng(); + for num_vars in 0..10 { + let point = core::iter::repeat_with(|| MontScalar(F::rand(&mut rng))) + .take(num_vars) + .collect_vec(); + let nu = point.len() / 2 + 1; + let mut lo_vec = vec![DoryScalar::ZERO; 1 << nu]; + let mut hi_vec = vec![DoryScalar::ZERO; 1 << nu]; + lo_vec[0] = DoryScalar::ONE; + hi_vec[0] = DoryScalar::ONE; + compute_dynamic_standard_basis_vecs(&point, &mut lo_vec, &mut hi_vec); + + let alphas = core::iter::repeat_with(|| MontScalar(F::rand(&mut rng))) + .take(nu) + .collect_vec(); + let alpha_invs = core::iter::repeat_with(|| MontScalar(F::rand(&mut rng))) + .take(nu) + .collect_vec(); + let (lo_fold, hi_fold) = + fold_dynamic_standard_basis_tensors(&point, &alphas, &alpha_invs); + naive_fold(&mut lo_vec, &alphas); + naive_fold(&mut hi_vec, &alpha_invs); + assert_eq!(lo_fold, lo_vec[0]); + assert_eq!(hi_fold, hi_vec[0]); + } + } + + #[test] + fn we_can_compute_dynamic_vecs_for_length_0_point() { + let point = vec![]; + let expected_lo_vec = vec![DoryScalar::from(1), DoryScalar::from(0)]; + let expected_hi_vec = vec![DoryScalar::from(1), DoryScalar::from(1)]; + let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); + assert_eq!(expected_lo_vec, lo_vec); + assert_eq!(expected_hi_vec, hi_vec); + } + + #[test] + fn we_can_compute_dynamic_vecs_for_length_1_point() { + let point = vec![DoryScalar::from(2)]; + let expected_lo_vec = vec![DoryScalar::from(1 - 2), DoryScalar::from(2)]; + let expected_hi_vec = vec![DoryScalar::from(1), DoryScalar::from(1)]; + let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); + assert_eq!(expected_lo_vec, lo_vec); + assert_eq!(expected_hi_vec, hi_vec); + } + + #[test] + fn we_can_compute_dynamic_vecs_for_length_2_point() { + let point = vec![DoryScalar::from(2), DoryScalar::from(3)]; + let expected_lo_vec = vec![ + DoryScalar::from((1 - 2) * (1 - 3)), + DoryScalar::from(2 * (1 - 3)), + DoryScalar::from((1 - 2) * 3), + DoryScalar::from(2 * 3), + ]; + let expected_hi_vec = vec![ + DoryScalar::from(1), + DoryScalar::from(1), + MontScalar(F::from(3) / F::from(1 - 3)), + DoryScalar::from(0), + ]; + let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); + assert_eq!(expected_lo_vec, lo_vec); + assert_eq!(expected_hi_vec, hi_vec); + } + + #[test] + fn we_can_compute_dynamic_vecs_for_length_3_point() { + let point = vec![ + DoryScalar::from(2), + DoryScalar::from(3), + DoryScalar::from(5), + ]; + let expected_lo_vec = vec![ + DoryScalar::from((1 - 2) * (1 - 3)), + DoryScalar::from(2 * (1 - 3)), + DoryScalar::from((1 - 2) * 3), + DoryScalar::from(2 * 3), + ]; + let expected_hi_vec = vec![ + DoryScalar::from(1 - 5), + DoryScalar::from(1 - 5), + MontScalar(F::from((1 - 5) * 3) / F::from(1 - 3)), + DoryScalar::from(5), + ]; + let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); + assert_eq!(expected_lo_vec, lo_vec); + assert_eq!(expected_hi_vec, hi_vec); + } + + #[test] + fn we_can_compute_dynamic_vecs_that_matches_evaluation_vec() { + use ark_std::UniformRand; + let mut rng = ark_std::test_rng(); + for num_vars in 0..20 { + let point: Vec<_> = core::iter::repeat_with(|| MontScalar(F::rand(&mut rng))) + .take(num_vars) + .collect(); + let (lo_vec, hi_vec) = compute_dynamic_vecs(&point); + let mut eval_vec = vec![DoryScalar::ZERO; 1 << num_vars]; + compute_evaluation_vector(&mut eval_vec, &point); + for (i, val) in eval_vec.into_iter().enumerate() { + let (row, column) = row_and_column_from_index(i); + assert_eq!(hi_vec[row] * lo_vec[column], val); + } + } + } +} diff --git a/crates/proof-of-sql/src/proof_primitive/mod.rs b/crates/proof-of-sql/src/proof_primitive/mod.rs index 61791180e..35514b959 100644 --- a/crates/proof-of-sql/src/proof_primitive/mod.rs +++ b/crates/proof-of-sql/src/proof_primitive/mod.rs @@ -1,4 +1,6 @@ //! TODO: add docs pub mod dory; +/// Central location for any code that requires the use of a dynamic matrix (for now, hyrax and dynamic dory). +pub(super) mod dynamic_matrix_utils; /// TODO: add docs pub(crate) mod sumcheck;