1use core::ops::Add;
2
3use itertools::{izip, zip_eq, Itertools};
4use num_traits::{One, Zero};
5use serde::{Deserialize, Serialize};
6use std_shims::Vec;
7
8use super::TreeVec;
9use crate::core::circle::CirclePoint;
10use crate::core::constraints::complex_conjugate_line_coeffs;
11use crate::core::fields::cm31::CM31;
12use crate::core::fields::m31::{BaseField, M31};
13use crate::core::fields::qm31::SecureField;
14use crate::core::fields::FieldExpOps;
15use crate::core::fri::{FriProof, FriProofAux};
16use crate::core::pcs::PcsConfig;
17use crate::core::poly::circle::CanonicCoset;
18use crate::core::utils::bit_reverse_index;
19use crate::core::vcs_lifted::merkle_hasher::MerkleHasherLifted;
20use crate::core::vcs_lifted::verifier::{MerkleDecommitmentLifted, MerkleDecommitmentLiftedAux};
21use crate::core::verifier::VerificationError;
22use crate::core::ColumnVec;
23pub type IndexMap<K, V> = indexmap::IndexMap<K, V, core::hash::BuildHasherDefault<fnv::FnvHasher>>;
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct CommitmentSchemeProof<H: MerkleHasherLifted> {
28 pub config: PcsConfig,
29 pub commitments: TreeVec<H::Hash>,
30 pub sampled_values: TreeVec<ColumnVec<Vec<SecureField>>>,
31 pub decommitments: TreeVec<MerkleDecommitmentLifted<H>>,
32 pub queried_values: TreeVec<ColumnVec<Vec<BaseField>>>,
33 pub proof_of_work: u64,
34 pub fri_proof: FriProof<H>,
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
39pub struct CommitmentSchemeProofAux<H: MerkleHasherLifted> {
40 pub unsorted_query_locations: Vec<usize>,
43 pub trace_decommitment: TreeVec<MerkleDecommitmentLiftedAux<H>>,
45 pub fri: FriProofAux<H>,
47}
48
49pub struct ExtendedCommitmentSchemeProof<H: MerkleHasherLifted> {
50 pub proof: CommitmentSchemeProof<H>,
51 pub aux: CommitmentSchemeProofAux<H>,
52}
53
54pub struct ColumnSampleBatch {
56 pub point: CirclePoint<SecureField>,
58 pub cols_vals_randpows: Vec<NumeratorData>,
61}
62
63pub struct NumeratorData {
68 pub column_index: usize,
69 pub sample_value: SecureField,
70 pub random_coeff: SecureField,
71}
72
73impl ColumnSampleBatch {
74 pub fn new_vec(samples_with_rand: &[&Vec<(PointSample, SecureField)>]) -> Vec<Self> {
78 let mut grouped_samples = IndexMap::default();
81 for (column_index, samples) in samples_with_rand.iter().enumerate() {
82 for (sample, rand_pow) in samples.iter() {
83 grouped_samples
84 .entry(sample.point)
85 .or_insert_with(Vec::new)
86 .push(NumeratorData {
87 column_index,
88 sample_value: sample.value,
89 random_coeff: *rand_pow,
90 });
91 }
92 }
93 grouped_samples
94 .into_iter()
95 .map(|(point, cols_vals_randpows)| ColumnSampleBatch {
96 point,
97 cols_vals_randpows,
98 })
99 .collect()
100 }
101}
102
103#[derive(Clone)]
104pub struct PointSample {
105 pub point: CirclePoint<SecureField>,
106 pub value: SecureField,
107}
108
109pub fn fri_answers(
121 column_log_sizes: TreeVec<Vec<u32>>,
122 samples: TreeVec<Vec<Vec<PointSample>>>,
123 random_coeff: SecureField,
124 query_positions: &[usize],
125 queried_values: TreeVec<ColumnVec<Vec<BaseField>>>,
126 lifting_log_size: u32,
127) -> Result<Vec<SecureField>, VerificationError> {
128 let queried_values = queried_values.flatten();
129 assert!(queried_values
130 .iter()
131 .all(|queries_per_col| queries_per_col.len() == query_positions.len()));
132 let samples_with_randomness = build_samples_with_randomness_and_periodicity(
133 &samples,
134 column_log_sizes
135 .0
136 .into_iter()
137 .map(|x| x.into_iter())
138 .collect(),
139 lifting_log_size,
140 random_coeff,
141 );
142 let sample_batches =
143 ColumnSampleBatch::new_vec(&samples_with_randomness.iter().flatten().collect::<Vec<_>>());
144 let lifting_domain = CanonicCoset::new(lifting_log_size).circle_domain();
145 let quotient_constants = quotient_constants(&sample_batches);
147 let mut res = Vec::with_capacity(query_positions.len());
148 for (idx, position) in query_positions.iter().enumerate() {
149 let queried_values_at_row = queried_values.iter().map(|col| col[idx]).collect_vec();
150 let domain_point = lifting_domain.at(bit_reverse_index(*position, lifting_log_size));
151
152 res.push(accumulate_row_quotients(
153 &sample_batches,
154 &queried_values_at_row,
155 "ient_constants,
156 domain_point,
157 ));
158 }
159 Ok(res)
160}
161
162pub fn accumulate_row_quotients(
163 sample_batches: &[ColumnSampleBatch],
164 queried_values_at_row: &[BaseField],
165 quotient_constants: &QuotientConstants,
166 domain_point: CirclePoint<BaseField>,
167) -> SecureField {
168 let sample_points = sample_batches.iter().map(|b| b.point).collect_vec();
169 let denominator_inverses = denominator_inverses(&sample_points, domain_point);
170 let mut row_accumulator = SecureField::zero();
171 for (sample_batch, line_coeffs, denominator_inverse) in izip!(
172 sample_batches,
173 "ient_constants.line_coeffs,
174 denominator_inverses
175 ) {
176 let mut numerator = SecureField::zero();
177 for (NumeratorData { column_index, .. }, (a, b, c)) in
178 zip_eq(&sample_batch.cols_vals_randpows, line_coeffs)
179 {
180 let value = queried_values_at_row[*column_index] * *c;
181 let linear_term = *a * domain_point.y + *b;
188 numerator += value - linear_term;
189 }
190 row_accumulator += numerator.mul_cm31(denominator_inverse);
193 }
194 row_accumulator
195}
196
197pub fn accumulate_row_partial_numerators(
203 batch: &ColumnSampleBatch,
204 queried_values_at_row: &[BaseField],
205 coeffs: &Vec<(SecureField, SecureField, SecureField)>,
206) -> SecureField {
207 let mut numerator = SecureField::zero();
208 for (NumeratorData { column_index, .. }, (_, b, c)) in zip_eq(&batch.cols_vals_randpows, coeffs)
209 {
210 let value = queried_values_at_row[*column_index] * *c;
211 numerator += value - *b;
212 }
213 numerator
214}
215
216pub fn column_line_coeffs(
224 sample_batches: &[ColumnSampleBatch],
225) -> Vec<Vec<(SecureField, SecureField, SecureField)>> {
226 sample_batches
227 .iter()
228 .map(|sample_batch| {
229 sample_batch
230 .cols_vals_randpows
231 .iter()
232 .map(
233 |NumeratorData {
234 column_index: _,
235 sample_value,
236 random_coeff,
237 }| {
238 let sample = PointSample {
239 point: sample_batch.point,
240 value: *sample_value,
241 };
242 complex_conjugate_line_coeffs(&sample, *random_coeff)
243 },
244 )
245 .collect()
246 })
247 .collect()
248}
249
250pub fn denominator_inverses(
254 sample_points: &[CirclePoint<SecureField>],
255 domain_point: CirclePoint<M31>,
256) -> Vec<CM31> {
257 let mut denominators = Vec::new();
258
259 for sample_point in sample_points {
267 let prx = sample_point.x.0;
269 let pry = sample_point.y.0;
270 let pix = sample_point.x.1;
271 let piy = sample_point.y.1;
272 denominators.push((prx - domain_point.x) * piy - (pry - domain_point.y) * pix);
273 }
274
275 CM31::batch_inverse(&denominators)
276}
277
278pub fn quotient_constants(sample_batches: &[ColumnSampleBatch]) -> QuotientConstants {
279 QuotientConstants {
280 line_coeffs: column_line_coeffs(sample_batches),
281 }
282}
283
284pub struct QuotientConstants {
286 pub line_coeffs: Vec<Vec<(SecureField, SecureField, SecureField)>>,
289}
290
291pub fn build_samples_with_randomness_and_periodicity(
292 samples: &TreeVec<Vec<Vec<PointSample>>>,
293 column_log_sizes: Vec<impl Iterator<Item = u32>>,
294 lifting_log_size: u32,
295 random_coeff: SecureField,
296) -> TreeVec<Vec<Vec<(PointSample, SecureField)>>> {
297 let mut random_pows = (0..).scan(SecureField::one(), |acc, _| {
298 let curr = *acc;
299 *acc *= random_coeff;
300 Some(curr)
301 });
302 let mut res: Vec<Vec<Vec<(PointSample, SecureField)>>> = Vec::new();
303 let lifting_domain_generator = CanonicCoset::new(lifting_log_size).step();
304 for (samples_per_tree, sizes_per_tree) in samples.iter().zip(column_log_sizes.into_iter()) {
305 let samples_with_randomness_and_periodicity = samples_per_tree
306 .iter()
307 .zip(sizes_per_tree)
308 .map(|(samples_per_cols, log_size)| {
309 if samples_per_cols.is_empty() {
310 return Vec::new();
311 }
312 let mut new_samples: Vec<(PointSample, SecureField)> = Vec::new();
313 if let [_prev_point_sample, point_sample] = &samples_per_cols[..] {
318 let period_generator = lifting_domain_generator.repeated_double(log_size);
319 new_samples.push((
320 PointSample {
321 point: point_sample.point.add(period_generator.into_ef()),
322 value: point_sample.value,
323 },
324 random_pows.next().unwrap(),
325 ));
326 }
327 for sample in samples_per_cols.iter() {
328 new_samples.push((sample.clone(), random_pows.next().unwrap()));
329 }
330 new_samples
331 })
332 .collect();
333 res.push(samples_with_randomness_and_periodicity);
334 }
335 TreeVec(res)
336}