use super::{
blitzar_metadata_table::create_blitzar_metadata_tables, ExtendedVerifierState, G1Affine,
ProverSetup, F,
};
use crate::{
base::{commitment::CommittableColumn, slice_ops::slice_cast},
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};
use ark_ff::{AdditiveGroup, Field};
#[cfg(feature = "blitzar")]
use blitzar::compute::ElementP2;
#[cfg(feature = "blitzar")]
use bytemuck::TransparentWrapper;
use itertools::{Itertools, __std_iter::repeat};
pub(super) fn compute_dynamic_v_vec(a: &[F], hi_vec: &[F], nu: usize) -> Vec<F> {
a.iter()
.enumerate()
.fold(vec![F::ZERO; 1 << nu], |mut v_vec, (i, v)| {
let (row, column) = row_and_column_from_index(i);
v_vec[column] += hi_vec[row] * v;
v_vec
})
}
#[cfg(not(feature = "blitzar"))]
pub(super) fn compute_dynamic_T_vec_prime(
a: &[F],
nu: usize,
prover_setup: &ProverSetup,
) -> Vec<G1Affine> {
let mut T_vec_prime = vec![G1Affine::identity(); 1 << nu];
for (i, v) in a.iter().enumerate() {
let (row, column) = row_and_column_from_index(i);
T_vec_prime[row] = (T_vec_prime[row] + prover_setup.Gamma_1[nu][column] * v).into();
}
T_vec_prime
}
#[cfg(feature = "blitzar")]
pub(super) fn compute_dynamic_T_vec_prime(
a: &[F],
nu: usize,
prover_setup: &ProverSetup,
) -> Vec<G1Affine> {
let a_col = CommittableColumn::from(TransparentWrapper::wrap_slice(a) as &[DoryScalar]);
let (blitzar_output_bit_table, blitzar_output_length_table, blitzar_scalars) =
create_blitzar_metadata_tables(&[a_col], 0);
let mut blitzar_sub_commits =
vec![ElementP2::<ark_bls12_381::g1::Config>::default(); blitzar_output_bit_table.len()];
prover_setup.blitzar_vlen_msm(
&mut blitzar_sub_commits,
&blitzar_output_bit_table,
&blitzar_output_length_table,
blitzar_scalars.as_slice(),
);
let all_sub_commits: Vec<G1Affine> = slice_cast(&blitzar_sub_commits);
all_sub_commits
.iter()
.step_by(2)
.chain(repeat(&G1Affine::identity()))
.take(1 << nu)
.copied()
.collect()
}
pub(super) fn compute_dynamic_nu(num_vars: usize) -> usize {
num_vars / 2 + 1
}
pub(super) fn fold_dynamic_tensors(state: &ExtendedVerifierState) -> (F, F) {
let point = &state.s1_tensor;
let nu = point.len() / 2 + 1;
let lo_inv_prod: F = point.iter().take(nu).map(|b| F::ONE - b).product();
let hi_inv_prod: F = 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();
let (lo_fold, hi_fold) = fold_dynamic_standard_basis_tensors(
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.0 * lo_inv_prod, hi_fold.0 * hi_inv_prod)
}
#[cfg(test)]
mod tests {
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_fold_dynamic_tensors() {
use ark_std::{test_rng, UniformRand};
use itertools::Itertools;
let mut rng = test_rng();
for num_vars in 0..10 {
let nu = num_vars / 2 + 1;
let point: Vec<_> = core::iter::repeat_with(|| F::rand(&mut rng))
.take(num_vars)
.collect();
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 (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,
alphas: alphas.clone(),
alpha_invs: alpha_invs.clone(),
E_1: DeferredMSM::new([], []),
E_2: DeferredMSM::new([], []),
base_state: VerifierState {
C: DeferredMSM::new([], []),
D_1: DeferredMSM::new([], []),
D_2: DeferredMSM::new([], []),
nu,
},
s2_tensor: Vec::default(),
};
let (lo_fold, hi_fold) = fold_dynamic_tensors(&state);
assert_eq!(lo_fold, lo_vec[0].0);
assert_eq!(hi_fold, hi_vec[0].0);
}
}
#[test]
fn we_can_compute_dynamic_v_vec() {
let a: Vec<F> = (100..109).map(Into::into).collect();
let hi_vec: Vec<F> = (200..208).map(Into::into).collect();
let nu = 3;
let v_vec = compute_dynamic_v_vec(&a, &hi_vec, nu);
let expected_v_vec: Vec<F> = [
100 * 200 + 102 * 202 + 104 * 203 + 108 * 204,
101 * 201 + 103 * 202 + 105 * 203,
106 * 203,
107 * 203,
0,
0,
0,
0,
]
.into_iter()
.map(Into::into)
.collect();
assert_eq!(v_vec, expected_v_vec);
}
#[test]
fn we_can_compute_dynamic_T_vec_prime() {
let public_parameters = PublicParameters::test_rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let a: Vec<F> = (100..109).map(Into::into).collect();
let nu = 3;
let T_vec_prime = compute_dynamic_T_vec_prime(&a, nu, &prover_setup);
let expected_T_vec_prime = vec![
(prover_setup.Gamma_1[nu][0] * F::from(100)).into(),
(prover_setup.Gamma_1[nu][1] * F::from(101)).into(),
(prover_setup.Gamma_1[nu][0] * F::from(102)
+ prover_setup.Gamma_1[nu][1] * F::from(103))
.into(),
(prover_setup.Gamma_1[nu][0] * F::from(104)
+ prover_setup.Gamma_1[nu][1] * F::from(105)
+ prover_setup.Gamma_1[nu][2] * F::from(106)
+ prover_setup.Gamma_1[nu][3] * F::from(107))
.into(),
(prover_setup.Gamma_1[nu][0] * F::from(108)).into(),
G1Affine::identity(),
G1Affine::identity(),
G1Affine::identity(),
];
assert_eq!(T_vec_prime, expected_T_vec_prime);
}
}