1use std::{
7 cmp, iter,
8 ops::{Add, Div, Mul, Neg, Sub},
9 pin::Pin,
10 task::{Context, Poll},
11};
12
13use ark_ec::CurveGroup;
14use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial};
15use futures::{ready, Future, FutureExt};
16use itertools::Itertools;
17
18use crate::{
19 algebra::{
20 macros::{impl_borrow_variants, impl_commutative},
21 AuthenticatedScalarOpenResult, AuthenticatedScalarResult, Scalar, ScalarResult,
22 },
23 error::MpcError,
24 MpcFabric,
25};
26
27use super::DensePolynomialResult;
28
29#[derive(Debug, Clone, Default)]
34pub struct AuthenticatedDensePoly<C: CurveGroup> {
35 pub coeffs: Vec<AuthenticatedScalarResult<C>>,
38}
39
40impl<C: CurveGroup> AuthenticatedDensePoly<C> {
41 pub fn from_coeffs(coeffs: Vec<AuthenticatedScalarResult<C>>) -> Self {
43 assert!(
44 !coeffs.is_empty(),
45 "AuthenticatedDensePoly must have at least one coefficient"
46 );
47 Self { coeffs }
48 }
49
50 pub fn zero(fabric: &MpcFabric<C>) -> Self {
52 let coeffs = vec![fabric.zero_authenticated()];
53 Self::from_coeffs(coeffs)
54 }
55
56 pub fn one(fabric: &MpcFabric<C>) -> Self {
59 let coeffs = vec![fabric.one_authenticated()];
60 Self::from_coeffs(coeffs)
61 }
62
63 pub fn degree(&self) -> usize {
65 self.coeffs.len() - 1
66 }
67
68 pub fn random(d: usize, fabric: &MpcFabric<C>) -> Self {
70 let coeffs = fabric.random_shared_scalars_authenticated(d + 1);
71 Self::from_coeffs(coeffs)
72 }
73
74 pub fn fabric(&self) -> &MpcFabric<C> {
76 self.coeffs[0].fabric()
77 }
78
79 pub fn eval(&self, x: &ScalarResult<C>) -> AuthenticatedScalarResult<C> {
84 let mut result = x.fabric().zero_authenticated();
86 for coeff in self.coeffs.iter().rev() {
87 result = result * x + coeff;
88 }
89
90 result
91 }
92
93 pub fn open(&self) -> DensePolynomialResult<C> {
95 let open_coeffs = AuthenticatedScalarResult::open_batch(&self.coeffs);
97 DensePolynomialResult::from_coeffs(open_coeffs)
98 }
99
100 pub fn open_authenticated(&self) -> AuthenticatedDensePolyOpenResult<C> {
102 let coeff_open_results = AuthenticatedScalarResult::open_authenticated_batch(&self.coeffs);
104 AuthenticatedDensePolyOpenResult { coeff_open_results }
105 }
106}
107
108impl<C: CurveGroup> AuthenticatedDensePoly<C> {
110 pub fn mod_xn(&self, n: usize) -> Self {
115 let mut coeffs = self.coeffs.clone();
116 coeffs.truncate(n);
117
118 Self::from_coeffs(coeffs)
119 }
120
121 pub fn rev(&self) -> Self {
131 let mut coeffs = self.coeffs.clone();
132 coeffs.reverse();
133
134 Self::from_coeffs(coeffs)
135 }
136
137 pub fn random_polynomial(n: usize, fabric: &MpcFabric<C>) -> Self {
139 let coeffs = fabric.random_shared_scalars_authenticated(n + 1);
140 Self::from_coeffs(coeffs)
141 }
142
143 pub fn mul_inverse_mod_t(&self, t: usize) -> Self {
149 let fabric = self.fabric();
150 let masking_poly = Self::random_polynomial(t , fabric);
151
152 let masked_poly = (&masking_poly * self).open_authenticated();
154
155 let masked_poly_res = DensePolynomialResult::from_coeffs(
157 masked_poly
158 .coeff_open_results
159 .into_iter()
160 .map(|c| c.value)
161 .collect_vec(),
162 );
163 let inverted_masked_poly = masked_poly_res.mul_inverse_mod_t(t);
164
165 let res = &inverted_masked_poly * &masking_poly;
168 res.mod_xn(t)
169 }
170}
171
172pub struct AuthenticatedDensePolyOpenResult<C: CurveGroup> {
176 pub coeff_open_results: Vec<AuthenticatedScalarOpenResult<C>>,
178}
179
180impl<C: CurveGroup> Future for AuthenticatedDensePolyOpenResult<C>
181where
182 C::ScalarField: Unpin,
183{
184 type Output = Result<DensePolynomial<C::ScalarField>, MpcError>;
185
186 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
187 let mut coeffs = Vec::new();
189 for coeff_open_result in self.coeff_open_results.iter_mut() {
190 match ready!(coeff_open_result.poll_unpin(cx)) {
191 Ok(coeff) => coeffs.push(coeff),
192 Err(e) => return Poll::Ready(Err(e)),
193 }
194 }
195
196 let inner_coeffs = coeffs
198 .into_iter()
199 .map(|coeff| coeff.inner())
200 .collect::<Vec<_>>();
201
202 Poll::Ready(Ok(DensePolynomial::from_coefficients_vec(inner_coeffs)))
203 }
204}
205
206impl<C: CurveGroup> Add<&DensePolynomial<C::ScalarField>> for &AuthenticatedDensePoly<C> {
212 type Output = AuthenticatedDensePoly<C>;
213 fn add(self, rhs: &DensePolynomial<C::ScalarField>) -> Self::Output {
214 assert!(!self.coeffs.is_empty(), "cannot add to an empty polynomial");
215 let fabric = self.coeffs[0].fabric();
216
217 let max_degree = cmp::max(self.degree(), rhs.degree());
218
219 let padded_coeffs0 = self
221 .coeffs
222 .iter()
223 .cloned()
224 .chain(iter::repeat(fabric.zero_authenticated()));
225 let padded_coeffs1 = rhs
226 .coeffs
227 .iter()
228 .copied()
229 .map(Scalar::<C>::new)
230 .chain(iter::repeat(Scalar::zero()));
231
232 let mut coeffs = Vec::new();
234 for (lhs_coeff, rhs_coeff) in padded_coeffs0.zip(padded_coeffs1).take(max_degree + 1) {
235 coeffs.push(lhs_coeff + rhs_coeff);
236 }
237
238 AuthenticatedDensePoly::from_coeffs(coeffs)
239 }
240}
241impl_borrow_variants!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomial<C::ScalarField>, C: CurveGroup);
242impl_commutative!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomial<C::ScalarField>, C: CurveGroup);
243
244impl<C: CurveGroup> Add<&DensePolynomialResult<C>> for &AuthenticatedDensePoly<C> {
245 type Output = AuthenticatedDensePoly<C>;
246 fn add(self, rhs: &DensePolynomialResult<C>) -> Self::Output {
247 assert!(!self.coeffs.is_empty(), "cannot add to an empty polynomial");
248
249 let n_coeffs = cmp::max(self.coeffs.len(), rhs.coeffs.len());
251 let zero = self.fabric().zero();
252 let zero_authenticated = self.fabric().zero_authenticated();
253
254 let padded_lhs = self
255 .coeffs
256 .iter()
257 .chain(iter::repeat(&zero_authenticated))
258 .take(n_coeffs);
259 let padded_rhs = rhs.coeffs.iter().chain(iter::repeat(&zero)).take(n_coeffs);
260
261 let mut coeffs = Vec::with_capacity(n_coeffs);
263 for (lhs_coeff, rhs_coeff) in padded_lhs.zip(padded_rhs) {
264 coeffs.push(lhs_coeff + rhs_coeff);
265 }
266
267 AuthenticatedDensePoly::from_coeffs(coeffs)
268 }
269}
270impl_borrow_variants!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomialResult<C>, C: CurveGroup);
271impl_commutative!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomialResult<C>, C: CurveGroup);
272
273impl<C: CurveGroup> Add<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
274 type Output = AuthenticatedDensePoly<C>;
275 fn add(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
276 let (shorter, longer) = if self.coeffs.len() < rhs.coeffs.len() {
278 (&self.coeffs, &rhs.coeffs)
279 } else {
280 (&rhs.coeffs, &self.coeffs)
281 };
282
283 let mut coeffs = Vec::new();
284 for (i, longer_coeff) in longer.iter().enumerate() {
285 let new_coeff = if i < shorter.len() {
286 &shorter[i] + longer_coeff
287 } else {
288 longer_coeff.clone()
289 };
290 coeffs.push(new_coeff);
291 }
292
293 AuthenticatedDensePoly::from_coeffs(coeffs)
294 }
295}
296impl_borrow_variants!(AuthenticatedDensePoly<C>, Add, add, +, AuthenticatedDensePoly<C>, C: CurveGroup);
297
298impl<C: CurveGroup> Neg for &AuthenticatedDensePoly<C> {
300 type Output = AuthenticatedDensePoly<C>;
301
302 fn neg(self) -> Self::Output {
303 let coeffs = self
304 .coeffs
305 .iter()
306 .map(|coeff| coeff.neg())
307 .collect::<Vec<_>>();
308
309 AuthenticatedDensePoly::from_coeffs(coeffs)
310 }
311}
312impl_borrow_variants!(AuthenticatedDensePoly<C>, Neg, neg, -, C: CurveGroup);
313
314#[allow(clippy::suspicious_arithmetic_impl)]
316impl<C: CurveGroup> Sub<&DensePolynomial<C::ScalarField>> for &AuthenticatedDensePoly<C> {
317 type Output = AuthenticatedDensePoly<C>;
318
319 fn sub(self, rhs: &DensePolynomial<C::ScalarField>) -> Self::Output {
320 let negated_rhs_coeffs = rhs.coeffs.iter().map(|coeff| coeff.neg()).collect_vec();
321 self + DensePolynomial::from_coefficients_vec(negated_rhs_coeffs)
322 }
323}
324impl_borrow_variants!(AuthenticatedDensePoly<C>, Sub, sub, -, DensePolynomial<C::ScalarField>, C: CurveGroup);
325
326#[allow(clippy::suspicious_arithmetic_impl)]
327impl<C: CurveGroup> Sub<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
328 type Output = AuthenticatedDensePoly<C>;
329
330 fn sub(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
331 self + (-rhs)
332 }
333}
334impl_borrow_variants!(AuthenticatedDensePoly<C>, Sub, sub, -, AuthenticatedDensePoly<C>, C: CurveGroup);
335
336impl<C: CurveGroup> Mul<&DensePolynomial<C::ScalarField>> for &AuthenticatedDensePoly<C> {
344 type Output = AuthenticatedDensePoly<C>;
345
346 fn mul(self, rhs: &DensePolynomial<C::ScalarField>) -> Self::Output {
347 assert!(
348 !self.coeffs.is_empty(),
349 "cannot multiply an empty polynomial"
350 );
351 let fabric = self.coeffs[0].fabric();
352
353 let result_degree = self.degree() + rhs.degree();
355 let mut coeffs = Vec::with_capacity(result_degree + 1);
356 for _ in 0..(result_degree + 1) {
357 coeffs.push(fabric.zero_authenticated());
358 }
359
360 for (i, lhs_coeff) in self.coeffs.iter().enumerate() {
362 for (j, rhs_coeff) in rhs.coeffs.iter().enumerate() {
363 coeffs[i + j] = &coeffs[i + j] + (lhs_coeff * Scalar::<C>::new(*rhs_coeff));
364 }
365 }
366
367 AuthenticatedDensePoly::from_coeffs(coeffs)
368 }
369}
370
371impl<C: CurveGroup> Mul<&DensePolynomialResult<C>> for &AuthenticatedDensePoly<C> {
372 type Output = AuthenticatedDensePoly<C>;
373
374 fn mul(self, rhs: &DensePolynomialResult<C>) -> Self::Output {
375 assert!(
376 !self.coeffs.is_empty(),
377 "cannot multiply an empty polynomial"
378 );
379 let fabric = self.coeffs[0].fabric();
380
381 let result_degree = self.degree() + rhs.degree();
383 let mut coeffs = Vec::with_capacity(result_degree + 1);
384 for _ in 0..(result_degree + 1) {
385 coeffs.push(fabric.zero_authenticated());
386 }
387
388 for (i, lhs_coeff) in self.coeffs.iter().enumerate() {
390 for (j, rhs_coeff) in rhs.coeffs.iter().enumerate() {
391 coeffs[i + j] = &coeffs[i + j] + (lhs_coeff * rhs_coeff);
392 }
393 }
394
395 AuthenticatedDensePoly::from_coeffs(coeffs)
396 }
397}
398impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, DensePolynomialResult<C>, C: CurveGroup);
399impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, DensePolynomialResult<C>, C: CurveGroup);
400
401impl<C: CurveGroup> Mul<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
402 type Output = AuthenticatedDensePoly<C>;
403
404 fn mul(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
405 assert!(
406 !self.coeffs.is_empty(),
407 "cannot multiply an empty polynomial"
408 );
409 let fabric = self.coeffs[0].fabric();
410
411 let result_degree = self.degree() + rhs.degree();
413 let mut coeffs = Vec::with_capacity(result_degree + 1);
414 for _ in 0..(result_degree + 1) {
415 coeffs.push(fabric.zero_authenticated());
416 }
417
418 for (i, lhs_coeff) in self.coeffs.iter().enumerate() {
420 for (j, rhs_coeff) in rhs.coeffs.iter().enumerate() {
421 coeffs[i + j] = &coeffs[i + j] + (lhs_coeff * rhs_coeff);
422 }
423 }
424
425 AuthenticatedDensePoly::from_coeffs(coeffs)
426 }
427}
428
429impl<C: CurveGroup> Mul<&Scalar<C>> for &AuthenticatedDensePoly<C> {
432 type Output = AuthenticatedDensePoly<C>;
433
434 fn mul(self, rhs: &Scalar<C>) -> Self::Output {
435 let new_coeffs = self.coeffs.iter().map(|coeff| coeff * rhs).collect_vec();
436 AuthenticatedDensePoly::from_coeffs(new_coeffs)
437 }
438}
439impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
440impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
441
442impl<C: CurveGroup> Mul<&ScalarResult<C>> for &AuthenticatedDensePoly<C> {
443 type Output = AuthenticatedDensePoly<C>;
444
445 fn mul(self, rhs: &ScalarResult<C>) -> Self::Output {
446 let new_coeffs = self.coeffs.iter().map(|coeff| coeff * rhs).collect_vec();
447 AuthenticatedDensePoly::from_coeffs(new_coeffs)
448 }
449}
450impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, ScalarResult<C>, C: CurveGroup);
451impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, ScalarResult<C>, C: CurveGroup);
452
453impl<C: CurveGroup> Mul<&AuthenticatedScalarResult<C>> for &AuthenticatedDensePoly<C> {
454 type Output = AuthenticatedDensePoly<C>;
455
456 fn mul(self, rhs: &AuthenticatedScalarResult<C>) -> Self::Output {
457 let new_coeffs = self.coeffs.iter().map(|coeff| coeff * rhs).collect_vec();
458 AuthenticatedDensePoly::from_coeffs(new_coeffs)
459 }
460}
461impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, AuthenticatedScalarResult<C>, C: CurveGroup);
462impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, AuthenticatedScalarResult<C>, C: CurveGroup);
463
464impl<C: CurveGroup> Div<&DensePolynomialResult<C>> for &AuthenticatedDensePoly<C> {
481 type Output = AuthenticatedDensePoly<C>;
482
483 fn div(self, rhs: &DensePolynomialResult<C>) -> Self::Output {
484 assert!(!rhs.coeffs.is_empty(), "cannot divide by zero polynomial");
488 let fabric = self.coeffs[0].fabric();
489
490 let quotient_degree = self.degree().saturating_sub(rhs.degree());
491 if quotient_degree == 0 {
492 return AuthenticatedDensePoly::zero(fabric);
493 }
494
495 let mut remainder = self.clone();
496 let mut quotient_coeffs = fabric.zeros_authenticated(quotient_degree + 1);
497
498 let divisor_leading_inverse = rhs.coeffs.last().unwrap().inverse();
499 for deg in (0..=quotient_degree).rev() {
500 let remainder_leading_coeff = remainder.coeffs.last().unwrap();
502 let next_quotient_coeff = remainder_leading_coeff * &divisor_leading_inverse;
503
504 for (i, divisor_coeff) in rhs.coeffs.iter().enumerate() {
506 let remainder_ind = deg + i;
507 remainder.coeffs[remainder_ind] =
508 &remainder.coeffs[remainder_ind] - divisor_coeff * &next_quotient_coeff;
509 }
510
511 quotient_coeffs[deg] = next_quotient_coeff;
512
513 remainder.coeffs.pop();
515 }
516
517 AuthenticatedDensePoly::from_coeffs(quotient_coeffs)
518 }
519}
520impl_borrow_variants!(AuthenticatedDensePoly<C>, Div, div, /, DensePolynomialResult<C>, C: CurveGroup);
521
522impl<C: CurveGroup> Div<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
556 type Output = AuthenticatedDensePoly<C>;
557
558 fn div(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
560 let n = self.degree();
561 let m = rhs.degree();
562 if n < m {
563 return AuthenticatedDensePoly::zero(self.fabric());
564 }
565
566 let modulus = n - m + 1;
567
568 let rev_f = self.rev();
570 let rev_g = rhs.rev();
571
572 let rev_g_inv = rev_g.mul_inverse_mod_t(modulus);
574
575 let rev_q = (&rev_f * &rev_g_inv).mod_xn(modulus);
577
578 rev_q.rev()
580 }
581}
582impl_borrow_variants!(AuthenticatedDensePoly<C>, Div, div, /, AuthenticatedDensePoly<C>, C: CurveGroup);
583
584#[cfg(test)]
585mod test {
586 use ark_poly::Polynomial;
587 use rand::thread_rng;
588
589 use crate::{
590 algebra::{
591 poly_test_helpers::{allocate_poly, random_poly, share_poly},
592 Scalar,
593 },
594 test_helpers::execute_mock_mpc,
595 PARTY0, PARTY1,
596 };
597
598 const DEGREE_BOUND: usize = 100;
600
601 #[tokio::test]
603 async fn test_eval() {
604 let mut rng = thread_rng();
605 let poly = random_poly(DEGREE_BOUND);
606 let point = Scalar::random(&mut rng);
607
608 let expected_res = poly.evaluate(&point.inner());
609
610 let (res, _) = execute_mock_mpc(|fabric| {
611 let poly = poly.clone();
612 async move {
613 let shared_poly = share_poly(poly, PARTY0, &fabric);
614 let point = fabric.allocate_scalar(point);
615
616 shared_poly.eval(&point).open_authenticated().await
617 }
618 })
619 .await;
620
621 assert!(res.is_ok());
622 assert_eq!(res.unwrap(), Scalar::new(expected_res));
623 }
624
625 #[tokio::test]
627 async fn test_add_constant_poly() {
628 let poly1 = random_poly(DEGREE_BOUND);
629 let poly2 = random_poly(DEGREE_BOUND);
630
631 let expected_res = &poly1 + &poly2;
632
633 let (res, _) = execute_mock_mpc(|fabric| {
634 let poly1 = poly1.clone();
635 let poly2 = poly2.clone();
636
637 async move {
638 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
639
640 let res = &shared_poly1 + &poly2;
641 res.open_authenticated().await
642 }
643 })
644 .await;
645
646 assert!(res.is_ok());
647 assert_eq!(res.unwrap(), expected_res);
648 }
649
650 #[tokio::test]
652 async fn test_add_public_poly() {
653 let poly1 = random_poly(DEGREE_BOUND);
654 let poly2 = random_poly(DEGREE_BOUND);
655
656 let expected_res = &poly1 + &poly2;
657
658 let (res, _) = execute_mock_mpc(|fabric| {
659 let poly1 = poly1.clone();
660 let poly2 = poly2.clone();
661
662 async move {
663 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
664 let poly2 = allocate_poly(&poly2, &fabric);
665
666 let res = &shared_poly1 + &poly2;
667 res.open_authenticated().await
668 }
669 })
670 .await;
671
672 assert!(res.is_ok());
673 assert_eq!(res.unwrap(), expected_res);
674 }
675
676 #[tokio::test]
678 async fn test_add_poly() {
679 let poly1 = random_poly(DEGREE_BOUND);
680 let poly2 = random_poly(DEGREE_BOUND);
681
682 let expected_res = &poly1 + &poly2;
683
684 let (res, _) = execute_mock_mpc(|fabric| {
685 let poly1 = poly1.clone();
686 let poly2 = poly2.clone();
687
688 async move {
689 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
690 let shared_poly2 = share_poly(poly2, PARTY0, &fabric);
691
692 let res = &shared_poly1 + &shared_poly2;
693 res.open_authenticated().await
694 }
695 })
696 .await;
697
698 assert!(res.is_ok());
699 assert_eq!(res.unwrap(), expected_res);
700 }
701
702 #[tokio::test]
704 async fn test_subtract_constant_poly() {
705 let poly1 = random_poly(DEGREE_BOUND);
706 let poly2 = random_poly(DEGREE_BOUND);
707
708 let expected_res = &poly1 - &poly2;
709
710 let (res, _) = execute_mock_mpc(|fabric| {
711 let poly1 = poly1.clone();
712 let poly2 = poly2.clone();
713
714 async move {
715 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
716
717 let res = &shared_poly1 - &poly2;
718 res.open_authenticated().await
719 }
720 })
721 .await;
722
723 assert!(res.is_ok());
724 assert_eq!(res.unwrap(), expected_res);
725 }
726
727 #[tokio::test]
729 async fn test_subtract_poly() {
730 let poly1 = random_poly(DEGREE_BOUND);
731 let poly2 = random_poly(DEGREE_BOUND);
732
733 let expected_res = &poly1 - &poly2;
734
735 let (res, _) = execute_mock_mpc(|fabric| {
736 let poly1 = poly1.clone();
737 let poly2 = poly2.clone();
738
739 async move {
740 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
741 let shared_poly2 = share_poly(poly2, PARTY0, &fabric);
742
743 let res = &shared_poly1 - &shared_poly2;
744 res.open_authenticated().await
745 }
746 })
747 .await;
748
749 assert!(res.is_ok());
750 assert_eq!(res.unwrap(), expected_res);
751 }
752
753 #[tokio::test]
755 async fn test_mul_constant_polynomial() {
756 let poly1 = random_poly(DEGREE_BOUND);
757 let poly2 = random_poly(DEGREE_BOUND);
758
759 let expected_res = &poly1 * &poly2;
760
761 let (res, _) = execute_mock_mpc(|fabric| {
762 let poly1 = poly1.clone();
763 let poly2 = poly2.clone();
764
765 async move {
766 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
767
768 let res = &shared_poly1 * &poly2;
769 res.open_authenticated().await
770 }
771 })
772 .await;
773
774 assert!(res.is_ok());
775 assert_eq!(res.unwrap(), expected_res);
776 }
777
778 #[tokio::test]
780 async fn test_mul_public_polynomial() {
781 let poly1 = random_poly(DEGREE_BOUND);
782 let poly2 = random_poly(DEGREE_BOUND);
783
784 let expected_res = &poly1 * &poly2;
785
786 let (res, _) = execute_mock_mpc(|fabric| {
787 let poly1 = poly1.clone();
788 let poly2 = poly2.clone();
789
790 async move {
791 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
792 let poly2 = allocate_poly(&poly2, &fabric);
793
794 let res = &shared_poly1 * &poly2;
795 res.open_authenticated().await
796 }
797 })
798 .await;
799
800 assert!(res.is_ok());
801 assert_eq!(res.unwrap(), expected_res);
802 }
803
804 #[tokio::test]
806 async fn test_mul_polynomial() {
807 let poly1 = random_poly(DEGREE_BOUND);
808 let poly2 = random_poly(DEGREE_BOUND);
809
810 let expected_res = &poly1 * &poly2;
811
812 let (res, _) = execute_mock_mpc(|fabric| {
813 let poly1 = poly1.clone();
814 let poly2 = poly2.clone();
815
816 async move {
817 let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
818 let shared_poly2 = share_poly(poly2, PARTY0, &fabric);
819
820 let res = &shared_poly1 * &shared_poly2;
821 res.open_authenticated().await
822 }
823 })
824 .await;
825
826 assert!(res.is_ok());
827 assert_eq!(res.unwrap(), expected_res);
828 }
829
830 #[tokio::test]
832 async fn test_scalar_mul_constant() {
833 let mut rng = thread_rng();
834 let poly = random_poly(DEGREE_BOUND);
835 let scaling_factor = Scalar::random(&mut rng);
836
837 let expected_res = &poly * scaling_factor.inner();
838
839 let (res, _) = execute_mock_mpc(|fabric| {
840 let poly = poly.clone();
841 async move {
842 let shared_poly = share_poly(poly, PARTY0, &fabric);
843 (shared_poly * scaling_factor).open_authenticated().await
844 }
845 })
846 .await;
847
848 assert!(res.is_ok());
849 assert_eq!(res.unwrap(), expected_res);
850 }
851
852 #[tokio::test]
854 async fn test_scalar_mul_public() {
855 let mut rng = thread_rng();
856 let poly = random_poly(DEGREE_BOUND);
857 let scaling_factor = Scalar::random(&mut rng);
858
859 let expected_res = &poly * scaling_factor.inner();
860
861 let (res, _) = execute_mock_mpc(|fabric| {
862 let poly = poly.clone();
863 async move {
864 let shared_poly = share_poly(poly, PARTY0, &fabric);
865 let scaling_factor = fabric.allocate_scalar(scaling_factor);
866
867 (shared_poly * scaling_factor).open_authenticated().await
868 }
869 })
870 .await;
871
872 assert!(res.is_ok());
873 assert_eq!(res.unwrap(), expected_res);
874 }
875
876 #[tokio::test]
878 async fn test_scalar_mul() {
879 let mut rng = thread_rng();
880 let poly = random_poly(DEGREE_BOUND);
881 let scaling_factor = Scalar::random(&mut rng);
882
883 let expected_res = &poly * scaling_factor.inner();
884
885 let (res, _) = execute_mock_mpc(|fabric| {
886 let poly = poly.clone();
887 async move {
888 let shared_poly = share_poly(poly, PARTY0, &fabric);
889 let scaling_factor = fabric.share_scalar(scaling_factor, PARTY0);
890
891 (shared_poly * scaling_factor).open_authenticated().await
892 }
893 })
894 .await;
895
896 assert!(res.is_ok());
897 assert_eq!(res.unwrap(), expected_res);
898 }
899
900 #[tokio::test]
902 async fn test_div_polynomial_public() {
903 let poly1 = random_poly(DEGREE_BOUND);
904 let poly2 = random_poly(DEGREE_BOUND);
905
906 let expected_res = &poly1 / &poly2;
907
908 let (res, _) = execute_mock_mpc(|fabric| {
909 let poly1 = poly1.clone();
910 let poly2 = poly2.clone();
911 async move {
912 let dividend = share_poly(poly1, PARTY0, &fabric);
913 let divisor = allocate_poly(&poly2, &fabric);
914
915 let quotient = dividend / divisor;
916 quotient.open_authenticated().await
917 }
918 })
919 .await;
920
921 assert!(res.is_ok());
922 assert_eq!(res.unwrap(), expected_res);
923 }
924
925 #[tokio::test]
927 async fn test_div_polynomial() {
928 let poly1 = random_poly(DEGREE_BOUND);
929 let poly2 = random_poly(DEGREE_BOUND);
930
931 let expected_res = &poly1 / &poly2;
932
933 let (res, _) = execute_mock_mpc(|fabric| {
934 let poly1 = poly1.clone();
935 let poly2 = poly2.clone();
936 async move {
937 let dividend = share_poly(poly1, PARTY0, &fabric);
938 let divisor = share_poly(poly2, PARTY1, &fabric);
939
940 let quotient = dividend / divisor;
941 quotient.open_authenticated().await
942 }
943 })
944 .await;
945
946 assert!(res.is_ok());
947 assert_eq!(res.unwrap(), expected_res);
948 }
949}