1use crate::core::{env_params::EnvironmentParameters, statement::Statement};
2use crate::prover::{Challenges, Witness};
3use crate::ring::poly::{PolyRing, PolyVector, ZqVector};
4
5pub struct AggregationOne {
7 pub a_ct_aggr: Vec<Vec<PolyVector>>,
9 pub phi_ct_aggr: Vec<Vec<PolyVector>>,
11 pub b_ct_aggr: PolyVector,
13}
14
15impl AggregationOne {
16 pub fn new(
17 witness: &Witness,
18 st: &Statement,
19 ep: &EnvironmentParameters,
20 tr: &Challenges,
21 ) -> Self {
22 Self::aggregate(witness, st, ep, tr)
23 }
24
25 fn aggregate(
26 witness: &Witness,
27 st: &Statement,
28 ep: &EnvironmentParameters,
29 tr: &Challenges,
30 ) -> Self {
31 let a_ct_aggr: Vec<Vec<PolyVector>> = Self::get_a_ct_aggr(&tr.psi, &st.a_ct, ep);
33
34 let phi_ct_aggr: Vec<Vec<PolyVector>> =
36 Self::get_phi_ct_aggr(&st.phi_ct, &tr.pi, &tr.psi, &tr.omega, ep);
37
38 let b_ct_aggr: PolyVector = Self::get_b_ct_aggr(&a_ct_aggr, &phi_ct_aggr, witness, ep);
40
41 Self {
42 a_ct_aggr,
43 phi_ct_aggr,
44 b_ct_aggr,
45 }
46 }
47
48 pub fn get_a_ct_aggr(
49 psi: &[ZqVector],
50 a_ct: &[Vec<PolyVector>],
51 ep: &EnvironmentParameters,
52 ) -> Vec<Vec<PolyVector>> {
53 calculate_aggr_ct_a(psi, a_ct, ep)
54 }
55
56 pub fn get_phi_ct_aggr(
57 phi_ct: &[Vec<PolyVector>],
58 pi: &[Vec<ZqVector>],
59 psi: &[ZqVector],
60 omega: &[ZqVector],
61 ep: &EnvironmentParameters,
62 ) -> Vec<Vec<PolyVector>> {
63 calculate_aggr_ct_phi(phi_ct, pi, psi, omega, ep)
64 }
65
66 pub fn get_b_ct_aggr(
67 a_ct_aggr: &[Vec<PolyVector>],
68 phi_ct_aggr: &[Vec<PolyVector>],
69 witness: &Witness,
70 ep: &EnvironmentParameters,
71 ) -> PolyVector {
72 calculate_aggr_ct_b(a_ct_aggr, phi_ct_aggr, &witness.s, ep)
73 }
74}
75
76pub struct AggregationTwo {
78 pub a_i: Vec<PolyVector>,
80 pub phi_i: Vec<PolyVector>,
82 pub b_i: PolyRing,
84}
85
86impl AggregationTwo {
87 pub fn new(
88 aggr_one: &AggregationOne,
89 st: &Statement,
90 ep: &EnvironmentParameters,
91 tr: &Challenges,
92 ) -> Self {
93 Self::aggregate(aggr_one, st, ep, tr)
94 }
95
96 fn aggregate(
97 aggr_one: &AggregationOne,
98 st: &Statement,
99 ep: &EnvironmentParameters,
100 tr: &Challenges,
101 ) -> Self {
102 let a_i = Self::get_a_i(
104 &st.a_constraint,
105 &aggr_one.a_ct_aggr,
106 &tr.random_alpha,
107 &tr.random_beta,
108 ep,
109 );
110
111 let phi_i = Self::get_phi_i(
113 &st.phi_constraint,
114 &aggr_one.phi_ct_aggr,
115 &tr.random_alpha,
116 &tr.random_beta,
117 ep,
118 );
119
120 let b_i = Self::get_b_i(
122 &st.b_constraint,
123 &aggr_one.b_ct_aggr,
124 &tr.random_alpha,
125 &tr.random_beta,
126 ep,
127 );
128
129 Self { a_i, phi_i, b_i }
130 }
131
132 pub fn get_a_i(
133 a_constraint: &[Vec<PolyVector>],
134 a_ct_aggr: &[Vec<PolyVector>],
135 random_alpha: &PolyVector,
136 random_beta: &PolyVector,
137 ep: &EnvironmentParameters,
138 ) -> Vec<PolyVector> {
139 calculate_aggr_a(a_constraint, a_ct_aggr, random_alpha, random_beta, ep)
140 }
141
142 pub fn get_phi_i(
143 phi_constraint: &[Vec<PolyVector>],
144 phi_ct_aggr: &[Vec<PolyVector>],
145 random_alpha: &PolyVector,
146 random_beta: &PolyVector,
147 ep: &EnvironmentParameters,
148 ) -> Vec<PolyVector> {
149 calculate_aggr_phi(phi_constraint, phi_ct_aggr, random_alpha, random_beta, ep)
150 }
151
152 pub fn get_b_i(
153 b_constraint: &PolyVector,
154 b_ct_aggr: &PolyVector,
155 random_alpha: &PolyVector,
156 random_beta: &PolyVector,
157 ep: &EnvironmentParameters,
158 ) -> PolyRing {
159 calculate_aggr_b(b_constraint, b_ct_aggr, random_alpha, random_beta, ep)
160 }
161}
162
163#[rustfmt::skip]
171fn calculate_aggr_ct_a(
172 random_psi: &[ZqVector],
173 a_ct: &[Vec<PolyVector>],
174 ep: &EnvironmentParameters,
175) -> Vec<Vec<PolyVector>> {
176 let aprimes: Vec<Vec<PolyVector>> = (0..ep.k).map(|k| {
177 let psi_k = &random_psi[k];
178 (0..ep.r).map(|i| {
179 (0..ep.r).map(|j| {
180 (0..ep.constraint_l).map(|l| {
182 &a_ct[l][i].get_elements()[j]
183 * &psi_k.get_coeffs()[l]
184 })
185 .fold(
186 PolyRing::zero_poly(),
188 |acc, val| &acc + &val,
189 )
190 }).collect::<PolyVector>()
191 }).collect::<Vec<PolyVector>>()
192 }).collect();
193
194 aprimes
195}
196
197fn calculate_aggr_ct_phi(
209 phi_ct: &[Vec<PolyVector>],
210 pi: &[Vec<ZqVector>],
211 random_psi: &[ZqVector],
212 random_omega: &[ZqVector],
213 ep: &EnvironmentParameters,
214) -> Vec<Vec<PolyVector>> {
215 let phi_ct_aggr: Vec<Vec<PolyVector>> = (0..ep.k)
216 .map(|k| {
217 (0..ep.r)
218 .map(|i| {
219 let left_side: PolyVector = (0..ep.constraint_l)
221 .map(|l| {
222 phi_ct[l][i]
223 .iter()
224 .map(|phi| phi * &random_psi[k].get_coeffs()[l])
225 .collect::<PolyVector>()
226 })
227 .fold(
228 PolyVector::new(vec![PolyRing::zero_poly(); ep.n]),
229 |acc, val| acc.iter().zip(val.iter()).map(|(a, b)| a + b).collect(),
230 );
231
232 let right_side: PolyVector = (0..ep.lambda2)
235 .map(|j| {
236 let omega_j = random_omega[k].get_coeffs()[j];
237
238 let poly_vec: PolyVector = (0..ep.n)
239 .map(|chunk_index| {
240 let start = chunk_index * ep.deg_bound_d;
241 let end = start + ep.deg_bound_d;
242
243 let pi_poly =
244 PolyRing::new(pi[i][j].get_coeffs()[start..end].to_vec());
245 let pi_poly_conjugate = pi_poly.conjugate_automorphism();
246 &pi_poly_conjugate * &omega_j
247 })
248 .collect::<PolyVector>();
249
250 poly_vec
251 })
252 .fold(
253 PolyVector::new(vec![PolyRing::zero_poly(); ep.n]),
254 |acc, val| acc.iter().zip(val.iter()).map(|(a, b)| a + b).collect(),
255 );
256
257 &left_side + &right_side
258 })
259 .collect::<Vec<PolyVector>>()
260 })
261 .collect::<Vec<Vec<PolyVector>>>();
262
263 phi_ct_aggr
264}
265
266#[rustfmt::skip]
275fn calculate_aggr_ct_b(
276 a_ct_aggr: &[Vec<PolyVector>],
277 phi_ct_aggr: &[Vec<PolyVector>],
278 witness: &[PolyVector],
279 ep: &EnvironmentParameters,
280) -> PolyVector {
281 (0..ep.k).map(|k| {
282 (0..ep.r).map(|i| {
283 &(0..ep.r).map(|j| {
284 &a_ct_aggr[k][i].get_elements()[j]
286 * &witness[i].inner_product_poly_vector(&witness[j])
287 })
288 .fold(
289 PolyRing::zero_poly(),
291 |acc, val| &acc + &val,
292 )
293 + &phi_ct_aggr[k][i].inner_product_poly_vector(&witness[i])
295 }) .fold(PolyRing::zero_poly(), |acc, val| {
297 &acc + &val
298 })
299 }).collect()
300}
301
302fn calculate_aggr_a(
313 a_constraint: &[Vec<PolyVector>],
314 a_ct_aggr: &[Vec<PolyVector>],
315 random_alpha: &PolyVector,
316 random_beta: &PolyVector,
317 ep: &EnvironmentParameters,
318) -> Vec<PolyVector> {
319 let a_i: Vec<PolyVector> = (0..ep.r)
320 .map(|i| {
321 (0..ep.r)
322 .map(|j| {
323 let left_side = (0..ep.constraint_k)
325 .map(|k| {
326 &a_constraint[k][i].get_elements()[j] * &random_alpha.get_elements()[k]
327 })
328 .fold(PolyRing::zero_poly(), |acc, val| &acc + &val);
329
330 let right_side = (0..ep.k)
332 .map(|k| {
333 &a_ct_aggr[k][i].get_elements()[j] * &random_beta.get_elements()[k]
334 })
335 .fold(PolyRing::zero_poly(), |acc, val| &acc + &val);
336
337 &left_side + &right_side
338 })
339 .collect::<PolyVector>()
340 })
341 .collect::<Vec<PolyVector>>();
342
343 a_i
344}
345
346fn calculate_aggr_phi(
357 phi_constraint: &[Vec<PolyVector>],
358 phi_ct_aggr: &[Vec<PolyVector>],
359 random_alpha: &PolyVector,
360 random_beta: &PolyVector,
361 ep: &EnvironmentParameters,
362) -> Vec<PolyVector> {
363 let phi_i: Vec<PolyVector> = (0..ep.r)
364 .map(|i| {
365 let left_side: PolyVector = (0..ep.constraint_k)
367 .map(|k| {
368 phi_constraint[k][i]
369 .iter()
370 .map(|phi| phi * &random_alpha.get_elements()[k])
371 .collect::<PolyVector>()
372 })
373 .fold(
374 PolyVector::new(vec![PolyRing::zero_poly(); ep.n]),
375 |acc, val| acc.iter().zip(val.iter()).map(|(a, b)| a + b).collect(),
376 );
377
378 let right_side: PolyVector = (0..ep.k)
380 .map(|k| {
381 phi_ct_aggr[k][i]
382 .iter()
383 .map(|phi| phi * &random_beta.get_elements()[k])
384 .collect::<PolyVector>()
385 })
386 .fold(
387 PolyVector::new(vec![PolyRing::zero_poly(); ep.n]),
388 |acc, val| acc.iter().zip(val.iter()).map(|(a, b)| a + b).collect(),
389 );
390
391 &left_side + &right_side
392 })
393 .collect::<Vec<PolyVector>>();
394
395 phi_i
396}
397
398fn calculate_aggr_b(
409 b_constraint: &PolyVector,
410 b_ct_aggr: &PolyVector,
411 random_alpha: &PolyVector,
412 random_beta: &PolyVector,
413 ep: &EnvironmentParameters,
414) -> PolyRing {
415 let left_side = (0..ep.constraint_k)
416 .map(|k| &b_constraint.get_elements()[k] * &random_alpha.get_elements()[k])
417 .fold(PolyRing::zero_poly(), |acc, val| &acc + &val);
418
419 let right_side = (0..ep.k)
420 .map(|k| &b_ct_aggr.get_elements()[k] * &random_beta.get_elements()[k])
421 .fold(PolyRing::zero_poly(), |acc, val| &acc + &val);
422
423 &left_side + &right_side
424}
425
426pub fn calculate_hij(
434 phi_i: &[PolyVector],
435 s: &[PolyVector],
436 ep: &EnvironmentParameters,
437) -> Vec<PolyVector> {
438 (0..ep.r)
439 .map(|i| {
440 (0..ep.r)
441 .map(|j| {
442 let left_side = &phi_i[i].inner_product_poly_vector(&s[j]);
443 let right_side = &phi_i[j].inner_product_poly_vector(&s[i]);
444 left_side + right_side
445 })
446 .collect()
447 })
448 .collect()
449}
450
451pub fn calculate_gij(s: &[PolyVector], r: usize) -> Vec<PolyVector> {
459 (0..r)
460 .map(|i| {
461 (0..r)
462 .map(|j| s[i].inner_product_poly_vector(&s[j]))
463 .collect()
464 })
465 .collect()
466}
467
468pub fn calculate_z(x: &[PolyVector], random_c: &PolyVector) -> PolyVector {
476 x.iter()
477 .zip(random_c.iter())
478 .map(|(s_row, c_element)| s_row * c_element)
479 .fold(
480 PolyVector::new(vec![PolyRing::zero_poly(); x[0].len()]),
481 |acc, x| &acc + &x,
482 )
483}
484
485pub fn calculate_u_1(
487 b: &[Vec<Vec<PolyVector>>],
488 c: &[Vec<Vec<Vec<PolyVector>>>],
489 t_i: &[Vec<PolyVector>],
490 g_ij: &[Vec<PolyVector>],
491 ep: &EnvironmentParameters,
492) -> PolyVector {
493 let mut u_1 = vec![PolyRing::zero(ep.r); ep.k_1];
494 for i in 0..ep.r {
496 for k in 0..ep.t_1 {
497 let b_ik_t_ik = &t_i[i][k] * &b[i][k];
498 u_1 = u_1
499 .iter()
500 .zip(b_ik_t_ik.iter())
501 .map(|(a, b)| a + b)
502 .collect();
503 }
504 }
505 for i in 0..ep.r {
507 for j in i..ep.r {
508 for k in 0..ep.t_2 {
509 let c_ijk_g_ij = &g_ij[i][j] * &c[i][j][k];
510 u_1 = u_1
511 .iter()
512 .zip(c_ijk_g_ij.iter())
513 .map(|(a, b)| a + b)
514 .collect();
515 }
516 }
517 }
518
519 PolyVector::new(u_1)
520}
521
522pub fn calculate_u_2(
524 d: &[Vec<Vec<Vec<PolyVector>>>],
525 h_ij: &[Vec<PolyVector>],
526 ep: &EnvironmentParameters,
527) -> PolyVector {
528 let flat_vec: Vec<(usize, usize, usize)> = (0..ep.r)
530 .flat_map(|i| (i..ep.r).flat_map(move |j| (0..ep.t_2).map(move |k| (i, j, k))))
531 .collect();
532
533 flat_vec.into_iter().fold(
534 PolyVector::new(vec![PolyRing::zero_poly(); ep.n]),
535 |acc, (i, j, k)| {
536 let d_ijk_h_ij = &h_ij[i][j] * &d[i][j][k];
537 acc.iter()
538 .zip(d_ijk_h_ij.iter())
539 .map(|(a, b)| a + b)
540 .collect::<PolyVector>()
541 },
542 )
543}
544
545#[cfg(test)]
546mod tests {
547 use super::*;
548 use crate::prover::Challenges;
549 use crate::verifier::LabradorVerifier;
550 #[test]
551 fn test_check_relation_full() {
552 let ep = EnvironmentParameters::default();
554 let witness_1 = Witness::new(&ep);
556 let st: Statement = Statement::new(&witness_1, &ep);
558 let tr = Challenges::new(&ep);
560 let aggr_1 = AggregationOne::new(&witness_1, &st, &ep, &tr);
562 let aggr_2 = AggregationTwo::new(&aggr_1, &st, &ep, &tr);
564
565 let g: Vec<PolyVector> = (0..ep.r)
567 .map(|i| {
568 (0..ep.r)
569 .map(|j| witness_1.s[i].inner_product_poly_vector(&witness_1.s[j]))
570 .collect()
571 })
572 .collect();
573
574 let h: Vec<PolyVector> = (0..ep.r)
576 .map(|i| {
577 (0..ep.r)
578 .map(|j| {
579 let inner_phii_sj =
580 aggr_2.phi_i[i].inner_product_poly_vector(&witness_1.s[j]);
581 let inner_phij_si =
582 aggr_2.phi_i[j].inner_product_poly_vector(&witness_1.s[i]);
583 &inner_phii_sj + &inner_phij_si
584 })
585 .collect()
586 })
587 .collect();
588
589 let relation = LabradorVerifier::check_relation(&aggr_2.a_i, &aggr_2.b_i, &g, &h);
591
592 assert!(relation);
593 }
594}