From 77da6bf4d0278ee18c81d05d9b6fb6d7ad92fa3d Mon Sep 17 00:00:00 2001 From: stuarttimwhite Date: Tue, 10 Dec 2024 15:32:37 -0500 Subject: [PATCH] refactor!: dynamic dory code that has a more generic version --- .../dory/dynamic_dory_helper.rs | 119 +--- .../dynamic_dory_standard_basis_helper.rs | 556 ------------------ .../dory/dynamic_dory_structure.rs | 276 --------- .../src/proof_primitive/dory/mod.rs | 2 - 4 files changed, 8 insertions(+), 945 deletions(-) delete mode 100644 crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_standard_basis_helper.rs delete mode 100644 crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_structure.rs 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 8b3f88ede..3d83c54c9 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 @@ -5,9 +5,7 @@ use super::{ use crate::{ base::{commitment::CommittableColumn, slice_ops::slice_cast}, proof_primitive::{ - dory::{ - dynamic_dory_standard_basis_helper::compute_dynamic_standard_basis_vecs, DoryScalar, - }, + dory::DoryScalar, dynamic_dory_and_hyrax_common_utils::{ standard_basis_helper::fold_dynamic_standard_basis_tensors, structure::row_and_column_from_index, @@ -97,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). @@ -140,7 +115,7 @@ pub(super) fn fold_dynamic_tensors(state: &ExtendedVerifierState) -> (F, F) { - F::ONE }) .collect_vec(); - let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors( + let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors::( &standard_basis_point, &state.alphas, &state.alpha_invs, @@ -150,92 +125,14 @@ pub(super) fn fold_dynamic_tensors(state: &ExtendedVerifierState) -> (F, F) { #[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_dory_and_hyrax_common_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}; @@ -253,7 +150,7 @@ mod tests { .take(nu) .collect_vec(); - let (mut lo_vec, mut hi_vec) = compute_dynamic_vecs(&point); + let (mut lo_vec, mut hi_vec) = compute_dynamic_vecs::(&point); naive_fold(&mut lo_vec, &alphas); naive_fold(&mut hi_vec, &alpha_invs); 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/dynamic_dory_structure.rs b/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_structure.rs deleted file mode 100644 index 03f6ffaa3..000000000 --- a/crates/proof-of-sql/src/proof_primitive/dory/dynamic_dory_structure.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! This module gives some utility functions for determining the position of data within the dynamic dory 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. -//! Aside from the first 3 rows, the pattern is to have 3\*2^n rows of length 4\*2^n. -//! In particular this means that a 2^n by 2^n matrix contains exactly 2^(2\*n-1) data points when n>0. -//! -//! This structure allows for a multilinear point evaluation of the associated MLE to be represented as a -//! relatively simple matrix product. -//! -//! Concretely, if the data being committed to is 0, 1, 2, 3, etc., the matrix is filled as shown below. -//! -//! ```text -//! 0 -//! _, 1 -//! 2, 3 -//! 4, 5, 6, 7 -//! 8, 9, 10, 11 -//! 12, 13, 14, 15 -//! 16, 17, 18, 19, 20, 21, 22, 23 -//! 24, 25, 26, 27, 28, 29, 30, 31 -//! 32, 33, 34, 35, 36, 37, 38, 39 -//! 40, 41, 42, 43, 44, 45, 46, 47 -//! 48, 49, 50, 51, 52, 53, 54, 55 -//! 56, 57, 58, 59, 60, 61, 62, 63 -//! 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79 -//! 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 -//! 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111 -//! 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127 -//! ... -//! ``` - -/// Returns the full width of a row in the matrix. -/// -/// Note: when row = 1, this correctly returns 2, even though no data belongs at position 0. -pub(crate) const fn full_width_of_row(row: usize) -> usize { - ((2 * row + 4) / 3).next_power_of_two() -} - -/// Returns the index that belongs in the first column in a particular row. -/// -/// Note: when row = 1, this correctly returns 0, even though no data belongs there. -#[cfg(any(test, not(feature = "blitzar")))] -pub(crate) const fn row_start_index(row: usize) -> usize { - let width_of_row = full_width_of_row(row); - width_of_row * (row - width_of_row / 2) -} - -/// Returns the (row, column) in the matrix where the data with the given index belongs. -pub(crate) const fn row_and_column_from_index(index: usize) -> (usize, usize) { - let width_of_row = 1 << (((2 * index + 1).ilog2() + 1) / 2); - let row = index / width_of_row + width_of_row / 2; - let column = index % width_of_row; - (row, column) -} - -/// Returns the index of data where the (row, column) belongs. -pub(crate) fn index_from_row_and_column(row: usize, column: usize) -> Option { - let width_of_row = full_width_of_row(row); - (column < width_of_row && (row, column) != (1, 0)) - .then_some(width_of_row * (row - width_of_row / 2) + column) -} - -/// Returns a matrix size, (height, width), that can hold the given number of data points being committed with respect to an offset. -/// -/// Note: when `data_len = 0` and `offset = 0`, this function returns an empty matrix with size (0, 0). -pub(crate) const fn matrix_size(data_len: usize, offset: usize) -> (usize, usize) { - if data_len == 0 && offset == 0 { - return (0, 0); - } - - let (last_row, _) = row_and_column_from_index(offset + data_len - 1); - let width_of_last_row = full_width_of_row(last_row); - (last_row + 1, width_of_last_row) -} - -#[cfg(test)] -mod tests { - use super::*; - /// Creates a 2^nu by 2^nu matrix that is partially filled with the indexes that belong in each position. - fn create_position_matrix(nu: usize) -> Vec>> { - let max_index = 1 << (2 * nu - 1); - let mut matrix = vec![]; - for i in 0..max_index { - let (row, column) = row_and_column_from_index(i); - if matrix.len() <= row { - matrix.resize_with(row + 1, Vec::new); - } - if matrix[row].len() <= column { - matrix[row].resize(column + 1, None); - } - matrix[row][column] = Some(i); - } - matrix - } - #[test] - fn we_can_compute_positions_from_indexes() { - assert_eq!( - create_position_matrix(2), - vec![ - vec![Some(0)], // length 1 - vec![None, Some(1)], // length "1" - vec![Some(2), Some(3)], // length 2 - vec![Some(4), Some(5), Some(6), Some(7)], // length 4 - ], - ); - assert_eq!( - create_position_matrix(4), - vec![ - vec![Some(0)], // length 1 - vec![None, Some(1)], // length "1" - vec![Some(2), Some(3)], // length 2 - vec![Some(4), Some(5), Some(6), Some(7)], // length 4 - vec![Some(8), Some(9), Some(10), Some(11)], // length 4 - vec![Some(12), Some(13), Some(14), Some(15)], // length 4 - (16..=23).map(Some).collect(), // length 8 - (24..=31).map(Some).collect(), // length 8 - (32..=39).map(Some).collect(), // length 8 - (40..=47).map(Some).collect(), // length 8 - (48..=55).map(Some).collect(), // length 8 - (56..=63).map(Some).collect(), // length 8 - (64..=79).map(Some).collect(), // length 16 - (80..=95).map(Some).collect(), // length 16 - (96..=111).map(Some).collect(), // length 16 - (112..=127).map(Some).collect() // length 16 - ], - ); - } - #[test] - fn we_can_fill_matrix_with_no_collisions_and_correct_size_and_row_starts() { - for nu in 1..10 { - let num_vars = nu * 2 - 1; - let matrix = create_position_matrix(nu); - // Every position should be unique. - assert_eq!( - matrix.iter().flatten().filter(|&x| x.is_some()).count(), - 1 << num_vars - ); - // The matrix should have 2^nu rows. - assert_eq!(matrix.len(), 1 << nu); - // The matrix should have 2^nu columns. - assert_eq!(matrix.iter().map(Vec::len).max().unwrap(), 1 << nu); - for (index, row) in matrix.iter().enumerate() { - // The start of each row should match with `row_start_index`. - assert_eq!( - row_start_index(index), - match index { - 1 => 0, // Row 1 starts at 0, even though nothing is put in the 0th position. This is because the 0th index is at position (0, 0) - _ => row[0] - .expect("Every row except 1 should have a value in the 0th position."), - } - ); - } - } - } - #[test] - fn we_can_find_the_full_width_of_row() { - // This corresponds to a matrix with 2^(N+1) rows. - let N = 20; - let mut expected_widths = Vec::new(); - - // First three rows are defined by the dynamic Dory structure. - expected_widths.extend(std::iter::repeat(1).take(1)); - 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 { - 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)); - } - - // Verify the widths. - for (row, width) in expected_widths.iter().enumerate() { - let width_of_row = full_width_of_row(row); - assert_eq!( - width_of_row, *width, - "row: {row} does not produce expected width" - ); - } - } - #[test] - fn we_can_produce_the_correct_matrix_size() { - // NOTE: returned tuple is (height, width). - assert_eq!(matrix_size(0, 0), (0, 0)); - assert_eq!(matrix_size(1, 0), (1, 1)); - assert_eq!(matrix_size(2, 0), (2, 2)); - assert_eq!(matrix_size(3, 0), (3, 2)); - assert_eq!(matrix_size(4, 0), (3, 2)); - assert_eq!(matrix_size(5, 0), (4, 4)); - assert_eq!(matrix_size(6, 0), (4, 4)); - assert_eq!(matrix_size(7, 0), (4, 4)); - assert_eq!(matrix_size(8, 0), (4, 4)); - assert_eq!(matrix_size(9, 0), (5, 4)); - assert_eq!(matrix_size(10, 0), (5, 4)); - assert_eq!(matrix_size(11, 0), (5, 4)); - assert_eq!(matrix_size(12, 0), (5, 4)); - assert_eq!(matrix_size(13, 0), (6, 4)); - assert_eq!(matrix_size(14, 0), (6, 4)); - assert_eq!(matrix_size(15, 0), (6, 4)); - assert_eq!(matrix_size(16, 0), (6, 4)); - assert_eq!(matrix_size(17, 0), (7, 8)); - - assert_eq!(matrix_size(64, 0), (12, 8)); - assert_eq!(matrix_size(71, 0), (13, 16)); - assert_eq!(matrix_size(81, 0), (14, 16)); - assert_eq!(matrix_size(98, 0), (15, 16)); - assert_eq!(matrix_size(115, 0), (16, 16)); - } - #[test] - fn we_can_produce_the_correct_matrix_size_with_offset() { - // NOTE: returned tuple is (height, width). - assert_eq!(matrix_size(0, 0), (0, 0)); - assert_eq!(matrix_size(0, 1), (1, 1)); - assert_eq!(matrix_size(0, 2), (2, 2)); - assert_eq!(matrix_size(1, 1), (2, 2)); - assert_eq!(matrix_size(1, 2), (3, 2)); - assert_eq!(matrix_size(1, 3), (3, 2)); - assert_eq!(matrix_size(1, 4), (4, 4)); - assert_eq!(matrix_size(1, 5), (4, 4)); - assert_eq!(matrix_size(1, 6), (4, 4)); - assert_eq!(matrix_size(1, 7), (4, 4)); - assert_eq!(matrix_size(1, 8), (5, 4)); - assert_eq!(matrix_size(1, 9), (5, 4)); - assert_eq!(matrix_size(1, 10), (5, 4)); - assert_eq!(matrix_size(1, 11), (5, 4)); - assert_eq!(matrix_size(1, 12), (6, 4)); - assert_eq!(matrix_size(1, 13), (6, 4)); - assert_eq!(matrix_size(1, 14), (6, 4)); - assert_eq!(matrix_size(1, 15), (6, 4)); - assert_eq!(matrix_size(1, 16), (7, 8)); - - assert_eq!(matrix_size(1, 63), (12, 8)); - assert_eq!(matrix_size(1, 70), (13, 16)); - assert_eq!(matrix_size(1, 80), (14, 16)); - assert_eq!(matrix_size(1, 97), (15, 16)); - assert_eq!(matrix_size(1, 114), (16, 16)); - } - #[test] - fn we_can_find_the_index_for_row_column_pairs() { - use std::collections::HashSet; - - const MAX_INDEX: usize = 1 << 16; - let mut valid_pairs = HashSet::new(); - - // Collect all valid (row, column) pairs - for i in 0..MAX_INDEX { - let (row, column) = row_and_column_from_index(i); - valid_pairs.insert((row, column)); - } - - let (max_row, max_column) = valid_pairs - .iter() - .fold((0, 0), |(max_row, max_column), &(row, column)| { - (max_row.max(row), max_column.max(column)) - }); - - // Check that all valid pairs are valid and all invalid pairs are invalid - for row in 0..max_row { - for column in 0..max_column { - let index = index_from_row_and_column(row, column); - if valid_pairs.contains(&(row, column)) { - assert!( - index.is_some(), - "Valid pair ({row}, {column}) generated no index" - ); - } else { - assert!( - index.is_none(), - "Invalid pair ({row}, {column}) generated a valid index" - ); - } - } - } - } -} 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")]