Skip to content

Commit

Permalink
feat: dynamic dory verifier folding helper (#71)
Browse files Browse the repository at this point in the history
# Rationale for this change

This PR adds the verifier folding method for the dynamic dory commitment
scheme.

# What changes are included in this PR?

* The `fold_dynamic_standard_basis_tensors` is added and implemented.
This method is the verifier's equivalent of
`compute_dynamic_standard_basis_vecs`. Ultimately, there is still
wrapper code needed to use this method.

# Are these changes tested?

Yes

---------

Co-authored-by: tlovell-sxt <[email protected]>
  • Loading branch information
JayWhite2357 and tlovell-sxt authored Aug 1, 2024
1 parent 5ef39ac commit 40afb7f
Showing 1 changed file with 272 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,51 @@ fn build_partial_second_half_standard_basis_vecs(
}
}

#[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)]
mod tests {
use super::{super::dynamic_dory_structure::row_start_index, *};
Expand Down Expand Up @@ -278,4 +323,231 @@ mod tests {
}
}
}

#[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);
}

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]);
}
}
}

0 comments on commit 40afb7f

Please sign in to comment.