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