1use crate::relation::env_params::EnvironmentParameters;
2use crate::ring::rq::Rq;
3use crate::ring::rq_matrix::RqMatrix;
4use crate::ring::rq_vector::RqVector;
5use crate::ring::zq::Zq;
6
7use super::inner_product;
8
9pub struct ZeroConstantFunctionsAggregation<'a> {
11 ep: &'a EnvironmentParameters,
12 a_double_prime: Vec<RqMatrix>,
13 phi_double_prime: Vec<Vec<RqVector>>,
14}
15
16impl<'a> ZeroConstantFunctionsAggregation<'a> {
17 pub fn new(parameters: &'a EnvironmentParameters) -> Self {
18 Self {
19 ep: parameters,
20 a_double_prime: vec![
21 RqMatrix::symmetric_zero(parameters.multiplicity);
22 parameters.const_agg_length
23 ],
24 phi_double_prime: vec![
25 vec![RqVector::zero(parameters.rank); parameters.multiplicity];
26 parameters.const_agg_length
27 ],
28 }
29 }
30
31 pub fn calculate_agg_a_double_prime(&mut self, vector_psi: &[Vec<Zq>], a_prime: &[RqMatrix]) {
38 for i in 0..self.ep.multiplicity {
39 for j in 0..i + 1 {
40 let a_prime_l_vector: Vec<&Rq> =
41 a_prime.iter().map(|matrix| matrix.get_cell(i, j)).collect();
42
43 for (k, matrix) in self.a_double_prime.iter_mut().enumerate() {
44 matrix.set_cell(
45 i,
46 j,
47 inner_product::compute_linear_combination(
48 &a_prime_l_vector,
49 &vector_psi[k],
50 ),
51 );
52 }
53 }
54 }
55 }
56
57 pub fn calculate_agg_phi_double_prime(
67 &mut self,
68 phi_prime: &[Vec<RqVector>],
69 conjugated_pi: &[RqMatrix],
70 vector_psi: &[Vec<Zq>],
71 vector_omega: &[Vec<Zq>],
72 ) {
73 for i in 0..self.ep.multiplicity {
74 let phi_prime_l_vector: Vec<&RqVector> =
75 phi_prime.iter().map(|elems| &elems[i]).collect();
76 for (k, phi_k) in self.phi_double_prime.iter_mut().enumerate() {
77 phi_k[i] =
78 inner_product::compute_linear_combination(&phi_prime_l_vector, &vector_psi[k]);
79 }
80 }
81
82 for (i, pi_i) in conjugated_pi.iter().enumerate() {
83 for (k, phi_k) in self.phi_double_prime.iter_mut().enumerate() {
84 phi_k[i] = &phi_k[i]
85 + &inner_product::compute_linear_combination(
86 pi_i.get_elements(),
87 &vector_omega[k],
88 );
89 }
90 }
91 }
92
93 pub fn calculate_agg_b_double_prime(&mut self, witness: &[RqVector]) -> RqVector {
101 (0..self.ep.kappa)
102 .map(|k| {
103 (0..self.ep.multiplicity)
104 .map(|i| {
105 &(0..self.ep.multiplicity).map(|j| {
106 self.a_double_prime[k].get_cell(i, j)
108 * &inner_product::compute_linear_combination(witness[i].get_elements(), witness[j].get_elements())
109 })
110 .fold(
111 Rq::zero(),
113 |acc, val| &acc + &val,
114 )
115 + &inner_product::compute_linear_combination(self.phi_double_prime[k][i].get_elements(), witness[i].get_elements())
117 }) .fold(Rq::zero(), |acc, val| &acc + &val)
119 })
120 .collect()
121 }
122
123 pub fn get_alpha_double_prime(&self) -> &[RqMatrix] {
124 &self.a_double_prime
125 }
126
127 pub fn get_phi_double_prime(&self) -> &[Vec<RqVector>] {
128 &self.phi_double_prime
129 }
130}
131
132pub struct FunctionsAggregation<'a> {
133 ep: &'a EnvironmentParameters,
134 aggregated_a: RqMatrix,
135 aggregated_phi: Vec<RqVector>,
136 aggregated_b: Rq,
137}
138
139impl<'a> FunctionsAggregation<'a> {
140 pub fn new(parameters: &'a EnvironmentParameters) -> Self {
141 Self {
142 ep: parameters,
143 aggregated_a: RqMatrix::symmetric_zero(parameters.multiplicity),
144 aggregated_phi: vec![RqVector::zero(parameters.rank); parameters.multiplicity],
145 aggregated_b: Rq::zero(),
146 }
147 }
148
149 pub fn calculate_agg_a(
160 &mut self,
161 a_constraint: &[RqMatrix],
162 a_double_prime: &[RqMatrix],
163 vector_alpha: &RqVector,
164 vector_beta: &RqVector,
165 ) {
166 for i in 0..self.ep.multiplicity {
167 for j in 0..i + 1 {
168 let a_constraint_k: Vec<&Rq> = a_constraint
169 .iter()
170 .map(|matrix| matrix.get_cell(i, j))
171 .collect();
172 let a_double_prime_k: Vec<&Rq> = a_double_prime
173 .iter()
174 .map(|matrix| matrix.get_cell(i, j))
175 .collect();
176 self.aggregated_a.set_cell(
177 i,
178 j,
179 &inner_product::compute_linear_combination::<&Rq, Rq, Rq>(
180 &a_constraint_k,
181 vector_alpha.get_elements(),
182 ) + &inner_product::compute_linear_combination(
183 &a_double_prime_k,
184 vector_beta.get_elements(),
185 ),
186 );
187 }
188 }
189 }
190
191 pub fn calculate_aggr_phi(
202 &mut self,
203 phi_constraint: &[Vec<RqVector>],
204 phi_double_prime: &[Vec<RqVector>],
205 vector_alpha: &RqVector,
206 vector_beta: &RqVector,
207 ) {
208 for i in 0..self.ep.multiplicity {
209 let phi_constraint_k: Vec<&RqVector> =
210 phi_constraint.iter().map(|element| &element[i]).collect();
211 let phi_double_prime_k: Vec<&RqVector> =
212 phi_double_prime.iter().map(|element| &element[i]).collect();
213 self.aggregated_phi[i] =
214 &inner_product::compute_linear_combination::<&RqVector, RqVector, Rq>(
215 &phi_constraint_k,
216 vector_alpha.get_elements(),
217 ) + &inner_product::compute_linear_combination(
218 &phi_double_prime_k,
219 vector_beta.get_elements(),
220 );
221 }
222 }
223
224 pub fn calculate_aggr_b(
235 &mut self,
236 b_constraint: &RqVector,
237 b_double_prime: &RqVector,
238 vector_alpha: &RqVector,
239 vector_beta: &RqVector,
240 ) {
241 self.aggregated_b = &inner_product::compute_linear_combination(
242 b_constraint.get_elements(),
243 vector_alpha.get_elements(),
244 ) + &inner_product::compute_linear_combination(
245 b_double_prime.get_elements(),
246 vector_beta.get_elements(),
247 )
248 }
249
250 pub fn get_agg_a(&self) -> &RqMatrix {
251 &self.aggregated_a
252 }
253
254 pub fn get_appr_phi(&self) -> &[RqVector] {
255 &self.aggregated_phi
256 }
257
258 pub fn get_aggr_b(&self) -> &Rq {
259 &self.aggregated_b
260 }
261}
262
263#[cfg(test)]
264#[allow(clippy::needless_range_loop)]
265mod constant_agg_tests {
266 use crate::relation::env_params;
267
268 use super::*;
269
270 mod variable_generator {
271 use super::*;
272 use rand::{
273 distr::{Distribution, Uniform},
274 rng,
275 };
276 fn sample_zq_vector(length: usize) -> Vec<Zq> {
277 let uniform = Uniform::new_inclusive(Zq::ZERO, Zq::NEG_ONE).unwrap();
278 let mut coeffs = vec![Zq::ZERO; length];
279 coeffs
280 .iter_mut()
281 .for_each(|c| *c = uniform.sample(&mut rng()));
282 coeffs
283 }
284
285 pub fn generate_vector_psi(vec_length: usize, inner_vec_size: usize) -> Vec<Vec<Zq>> {
286 let mut vector_psi = Vec::new();
287 for _ in 0..vec_length {
288 vector_psi.push(sample_zq_vector(inner_vec_size));
289 }
290 vector_psi
291 }
292
293 pub fn generate_a_prime(vec_length: usize, matrix_size: usize) -> Vec<RqMatrix> {
294 let mut a_prime = Vec::new();
295 for _ in 0..vec_length {
296 a_prime.push(RqMatrix::symmetric_random(&mut rng(), matrix_size));
297 }
298 a_prime
299 }
300
301 pub fn generate_phi_prime(
302 vec_length: usize,
303 inner_vec_length: usize,
304 inner_inner_vec_length: usize,
305 ) -> Vec<Vec<RqVector>> {
306 let mut phi_prime = Vec::new();
307 for _ in 0..vec_length {
308 let mut inner_vec = Vec::new();
309 for _ in 0..inner_vec_length {
310 inner_vec.push(RqVector::random(&mut rng(), inner_inner_vec_length));
311 }
312 phi_prime.push(inner_vec);
313 }
314 phi_prime
315 }
316
317 pub fn generate_conjugated_pi(
318 vec_length: usize,
319 matrix_row: usize,
320 matrix_col: usize,
321 ) -> Vec<RqMatrix> {
322 let mut conjugated_pi = Vec::new();
323 for _ in 0..vec_length {
324 conjugated_pi.push(RqMatrix::random(&mut rng(), matrix_row, matrix_col));
325 }
326 conjugated_pi
327 }
328
329 pub fn generate_omega(vec_length: usize, inner_vec_length: usize) -> Vec<Vec<Zq>> {
330 let mut vector_omega = Vec::new();
331 for _ in 0..vec_length {
332 vector_omega.push(variable_generator::sample_zq_vector(inner_vec_length));
333 }
334 vector_omega
335 }
336
337 pub fn generate_witness(vec_length: usize, inner_vec_length: usize) -> Vec<RqVector> {
338 let mut witness = Vec::new();
339 for _ in 0..vec_length {
340 witness.push(RqVector::random(&mut rng(), inner_vec_length));
341 }
342 witness
343 }
344 }
345
346 #[test]
347 fn test_calculate_agg_a_double_prime() {
348 let params = EnvironmentParameters::default();
349 let mut aggregator = ZeroConstantFunctionsAggregation::new(¶ms);
350
351 let vector_psi =
352 variable_generator::generate_vector_psi(params.const_agg_length, params.constraint_l);
353 let a_prime =
354 variable_generator::generate_a_prime(params.constraint_l, params.multiplicity);
355
356 aggregator.calculate_agg_a_double_prime(&vector_psi, &a_prime);
357
358 for k in 0..params.const_agg_length {
359 for i in 0..params.multiplicity {
360 for j in 0..params.multiplicity {
361 let mut rhs = Rq::zero();
362 for l in 0..params.constraint_l {
363 rhs = &rhs + &(a_prime[l].get_cell(i, j) * &vector_psi[k][l])
364 }
365 assert_eq!(*aggregator.a_double_prime[k].get_cell(i, j), rhs);
366 }
367 }
368 }
369 }
370
371 #[test]
372 fn test_calculate_agg_phi_double_prime() {
373 let params = EnvironmentParameters::default();
374 let mut aggregator = ZeroConstantFunctionsAggregation::new(¶ms);
375
376 let phi_prime = variable_generator::generate_phi_prime(
377 params.constraint_l,
378 params.multiplicity,
379 params.rank,
380 );
381 let conjugated_pi = variable_generator::generate_conjugated_pi(
382 params.multiplicity,
383 2 * env_params::SECURITY_PARAMETER,
384 params.rank,
385 );
386 let vector_psi =
387 variable_generator::generate_vector_psi(params.const_agg_length, params.constraint_l);
388 let vector_omega = variable_generator::generate_omega(
389 params.const_agg_length,
390 2 * env_params::SECURITY_PARAMETER,
391 );
392
393 aggregator.calculate_agg_phi_double_prime(
394 &phi_prime,
395 &conjugated_pi,
396 &vector_psi,
397 &vector_omega,
398 );
399
400 for k in 0..params.const_agg_length {
401 for i in 0..params.multiplicity {
402 let mut rhs = RqVector::zero(params.rank);
403 for l in 0..params.constraint_l {
404 rhs = &rhs + &(&phi_prime[l][i] * vector_psi[k][l]);
405 }
406 let mut lhs = RqVector::zero(params.rank);
407 for j in 0..2 * env_params::SECURITY_PARAMETER {
408 lhs = &lhs + &(&conjugated_pi[i].get_elements()[j] * vector_omega[k][j]);
409 }
410 assert_eq!(aggregator.phi_double_prime[k][i], &rhs + &lhs);
411 }
412 }
413 }
414
415 #[test]
416 fn test_calculate_agg_b_double_prime() {
417 let params = EnvironmentParameters::default();
418 let mut aggregator = ZeroConstantFunctionsAggregation::new(¶ms);
419
420 let phi_prime = variable_generator::generate_phi_prime(
421 params.constraint_l,
422 params.multiplicity,
423 params.rank,
424 );
425 let conjugated_pi = variable_generator::generate_conjugated_pi(
426 params.multiplicity,
427 2 * env_params::SECURITY_PARAMETER,
428 params.rank,
429 );
430 let vector_psi =
431 variable_generator::generate_vector_psi(params.const_agg_length, params.constraint_l);
432 let vector_omega = variable_generator::generate_omega(
433 params.const_agg_length,
434 2 * env_params::SECURITY_PARAMETER,
435 );
436 let a_prime =
437 variable_generator::generate_a_prime(params.constraint_l, params.multiplicity);
438 let witness_vector = variable_generator::generate_witness(params.multiplicity, params.rank);
439
440 aggregator.calculate_agg_a_double_prime(&vector_psi, &a_prime);
441 aggregator.calculate_agg_phi_double_prime(
442 &phi_prime,
443 &conjugated_pi,
444 &vector_psi,
445 &vector_omega,
446 );
447 let b_double_prime = aggregator.calculate_agg_b_double_prime(&witness_vector);
448
449 for k in 0..params.const_agg_length {
450 let mut rhs = Rq::zero();
451 for i in 0..params.multiplicity {
452 for j in 0..params.multiplicity {
453 rhs = &rhs
454 + &(aggregator.a_double_prime[k].get_cell(i, j)
455 * &inner_product::compute_linear_combination(
456 witness_vector[i].get_elements(),
457 witness_vector[j].get_elements(),
458 ));
459 }
460 }
461 let mut lhs = Rq::zero();
462 for i in 0..params.multiplicity {
463 lhs = &lhs
464 + (&inner_product::compute_linear_combination(
465 aggregator.phi_double_prime[k][i].get_elements(),
466 witness_vector[i].get_elements(),
467 ));
468 }
469 assert_eq!(b_double_prime.get_elements()[k], &rhs + &lhs);
470 }
471 }
472}
473
474#[cfg(test)]
475#[allow(clippy::needless_range_loop)]
476mod func_agg_tests {
477 use super::*;
478
479 mod variable_generator {
480 use super::*;
481 use rand::rng;
482
483 pub fn generate_rq_vector(vec_length: usize) -> RqVector {
484 let mut vector_alpha = Vec::new();
485 for _ in 0..vec_length {
486 vector_alpha.push(Rq::random(&mut rng()));
487 }
488 RqVector::new(vector_alpha)
489 }
490
491 pub fn generate_matrix_vector(vec_length: usize, matrix_size: usize) -> Vec<RqMatrix> {
492 let mut a_constraint = Vec::new();
493 for _ in 0..vec_length {
494 a_constraint.push(RqMatrix::symmetric_random(&mut rng(), matrix_size));
495 }
496 a_constraint
497 }
498
499 pub fn generate_rqvector_vector(
500 vec_length: usize,
501 inner_vec_length: usize,
502 inner_inner_vec_length: usize,
503 ) -> Vec<Vec<RqVector>> {
504 let mut phi_constraint = Vec::new();
505 for _ in 0..vec_length {
506 let mut inner_vec = Vec::new();
507 for _ in 0..inner_vec_length {
508 inner_vec.push(RqVector::random(&mut rng(), inner_inner_vec_length));
509 }
510 phi_constraint.push(inner_vec);
511 }
512 phi_constraint
513 }
514 }
515
516 #[test]
517 fn test_calculate_agg_a() {
518 let params = EnvironmentParameters::default();
519 let mut aggregator = FunctionsAggregation::new(¶ms);
520
521 let vector_alpha = variable_generator::generate_rq_vector(params.constraint_k);
522 let vector_beta = variable_generator::generate_rq_vector(params.const_agg_length);
523 let a_constraint =
524 variable_generator::generate_matrix_vector(params.constraint_k, params.multiplicity);
525 let a_double_prime = variable_generator::generate_matrix_vector(
526 params.const_agg_length,
527 params.multiplicity,
528 );
529
530 aggregator.calculate_agg_a(&a_constraint, &a_double_prime, &vector_alpha, &vector_beta);
531
532 for i in 0..params.multiplicity {
533 for j in 0..params.multiplicity {
534 let mut rhs = Rq::zero();
535 for k in 0..params.constraint_k {
536 rhs = &rhs + &(a_constraint[k].get_cell(i, j) * &vector_alpha.get_elements()[k])
537 }
538 let mut lhs = Rq::zero();
539 for k in 0..params.const_agg_length {
540 lhs =
541 &lhs + &(a_double_prime[k].get_cell(i, j) * &vector_beta.get_elements()[k])
542 }
543 assert_eq!(*aggregator.aggregated_a.get_cell(i, j), &rhs + &lhs);
544 }
545 }
546 }
547
548 #[test]
549 fn test_calculate_agg_phi() {
550 let params = EnvironmentParameters::default();
551 let mut aggregator = FunctionsAggregation::new(¶ms);
552
553 let vector_alpha = variable_generator::generate_rq_vector(params.constraint_k);
554 let vector_beta = variable_generator::generate_rq_vector(params.const_agg_length);
555 let phi_constraint = variable_generator::generate_rqvector_vector(
556 params.constraint_k,
557 params.multiplicity,
558 params.rank,
559 );
560 let phi_double_prime = variable_generator::generate_rqvector_vector(
561 params.const_agg_length,
562 params.multiplicity,
563 params.rank,
564 );
565
566 aggregator.calculate_aggr_phi(
567 &phi_constraint,
568 &phi_double_prime,
569 &vector_alpha,
570 &vector_beta,
571 );
572
573 for i in 0..params.multiplicity {
574 let mut rhs = RqVector::zero(params.rank);
575 for k in 0..params.constraint_k {
576 rhs = &rhs + &(&phi_constraint[k][i] * &vector_alpha.get_elements()[k])
577 }
578 let mut lhs = RqVector::zero(params.rank);
579 for k in 0..params.const_agg_length {
580 lhs = &lhs + &(&phi_double_prime[k][i] * &vector_beta.get_elements()[k])
581 }
582 assert_eq!(aggregator.aggregated_phi[i], &rhs + &lhs);
583 }
584 }
585
586 #[test]
587 fn test_calculate_agg_b() {
588 let params = EnvironmentParameters::default();
589 let mut aggregator = FunctionsAggregation::new(¶ms);
590
591 let vector_alpha = variable_generator::generate_rq_vector(params.constraint_k);
592 let vector_beta = variable_generator::generate_rq_vector(params.const_agg_length);
593 let b_constraint = variable_generator::generate_rq_vector(params.constraint_k);
594 let b_double_prime = variable_generator::generate_rq_vector(params.const_agg_length);
595
596 aggregator.calculate_aggr_b(&b_constraint, &b_double_prime, &vector_alpha, &vector_beta);
597
598 let mut rhs = Rq::zero();
599 for k in 0..params.constraint_k {
600 rhs = &rhs + &(&b_constraint.get_elements()[k] * &vector_alpha.get_elements()[k])
601 }
602 let mut lhs = Rq::zero();
603 for k in 0..params.const_agg_length {
604 lhs = &lhs + &(&b_double_prime.get_elements()[k] * &vector_beta.get_elements()[k])
605 }
606 assert_eq!(aggregator.aggregated_b, &rhs + &lhs);
607 }
608}