use std::{
cmp, iter,
ops::{Add, Div, Mul, Neg, Sub},
pin::Pin,
task::{Context, Poll},
};
use ark_ec::CurveGroup;
use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial};
use futures::{ready, Future, FutureExt};
use itertools::Itertools;
use crate::{
algebra::{
macros::{impl_borrow_variants, impl_commutative},
AuthenticatedScalarOpenResult, AuthenticatedScalarResult, Scalar, ScalarResult,
},
error::MpcError,
MpcFabric,
};
use super::DensePolynomialResult;
#[derive(Debug, Clone, Default)]
pub struct AuthenticatedDensePoly<C: CurveGroup> {
pub coeffs: Vec<AuthenticatedScalarResult<C>>,
}
impl<C: CurveGroup> AuthenticatedDensePoly<C> {
pub fn from_coeffs(coeffs: Vec<AuthenticatedScalarResult<C>>) -> Self {
assert!(
!coeffs.is_empty(),
"AuthenticatedDensePoly must have at least one coefficient"
);
Self { coeffs }
}
pub fn zero(fabric: &MpcFabric<C>) -> Self {
let coeffs = vec![fabric.zero_authenticated()];
Self::from_coeffs(coeffs)
}
pub fn one(fabric: &MpcFabric<C>) -> Self {
let coeffs = vec![fabric.one_authenticated()];
Self::from_coeffs(coeffs)
}
pub fn degree(&self) -> usize {
self.coeffs.len() - 1
}
pub fn random(d: usize, fabric: &MpcFabric<C>) -> Self {
let coeffs = fabric.random_shared_scalars_authenticated(d + 1);
Self::from_coeffs(coeffs)
}
pub fn fabric(&self) -> &MpcFabric<C> {
self.coeffs[0].fabric()
}
pub fn eval(&self, x: &ScalarResult<C>) -> AuthenticatedScalarResult<C> {
let mut result = x.fabric().zero_authenticated();
for coeff in self.coeffs.iter().rev() {
result = result * x + coeff;
}
result
}
pub fn open(&self) -> DensePolynomialResult<C> {
let open_coeffs = AuthenticatedScalarResult::open_batch(&self.coeffs);
DensePolynomialResult::from_coeffs(open_coeffs)
}
pub fn open_authenticated(&self) -> AuthenticatedDensePolyOpenResult<C> {
let coeff_open_results = AuthenticatedScalarResult::open_authenticated_batch(&self.coeffs);
AuthenticatedDensePolyOpenResult { coeff_open_results }
}
}
impl<C: CurveGroup> AuthenticatedDensePoly<C> {
pub fn mod_xn(&self, n: usize) -> Self {
let mut coeffs = self.coeffs.clone();
coeffs.truncate(n);
Self::from_coeffs(coeffs)
}
pub fn rev(&self) -> Self {
let mut coeffs = self.coeffs.clone();
coeffs.reverse();
Self::from_coeffs(coeffs)
}
pub fn random_polynomial(n: usize, fabric: &MpcFabric<C>) -> Self {
let coeffs = fabric.random_shared_scalars_authenticated(n + 1);
Self::from_coeffs(coeffs)
}
pub fn mul_inverse_mod_t(&self, t: usize) -> Self {
let fabric = self.fabric();
let masking_poly = Self::random_polynomial(t , fabric);
let masked_poly = (&masking_poly * self).open_authenticated();
let masked_poly_res = DensePolynomialResult::from_coeffs(
masked_poly
.coeff_open_results
.into_iter()
.map(|c| c.value)
.collect_vec(),
);
let inverted_masked_poly = masked_poly_res.mul_inverse_mod_t(t);
let res = &inverted_masked_poly * &masking_poly;
res.mod_xn(t)
}
}
pub struct AuthenticatedDensePolyOpenResult<C: CurveGroup> {
pub coeff_open_results: Vec<AuthenticatedScalarOpenResult<C>>,
}
impl<C: CurveGroup> Future for AuthenticatedDensePolyOpenResult<C>
where
C::ScalarField: Unpin,
{
type Output = Result<DensePolynomial<C::ScalarField>, MpcError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut coeffs = Vec::new();
for coeff_open_result in self.coeff_open_results.iter_mut() {
match ready!(coeff_open_result.poll_unpin(cx)) {
Ok(coeff) => coeffs.push(coeff),
Err(e) => return Poll::Ready(Err(e)),
}
}
let inner_coeffs = coeffs
.into_iter()
.map(|coeff| coeff.inner())
.collect::<Vec<_>>();
Poll::Ready(Ok(DensePolynomial::from_coefficients_vec(inner_coeffs)))
}
}
impl<C: CurveGroup> Add<&DensePolynomial<C::ScalarField>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn add(self, rhs: &DensePolynomial<C::ScalarField>) -> Self::Output {
assert!(!self.coeffs.is_empty(), "cannot add to an empty polynomial");
let fabric = self.coeffs[0].fabric();
let max_degree = cmp::max(self.degree(), rhs.degree());
let padded_coeffs0 = self
.coeffs
.iter()
.cloned()
.chain(iter::repeat(fabric.zero_authenticated()));
let padded_coeffs1 = rhs
.coeffs
.iter()
.copied()
.map(Scalar::<C>::new)
.chain(iter::repeat(Scalar::zero()));
let mut coeffs = Vec::new();
for (lhs_coeff, rhs_coeff) in padded_coeffs0.zip(padded_coeffs1).take(max_degree + 1) {
coeffs.push(lhs_coeff + rhs_coeff);
}
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomial<C::ScalarField>, C: CurveGroup);
impl_commutative!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomial<C::ScalarField>, C: CurveGroup);
impl<C: CurveGroup> Add<&DensePolynomialResult<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn add(self, rhs: &DensePolynomialResult<C>) -> Self::Output {
assert!(!self.coeffs.is_empty(), "cannot add to an empty polynomial");
let n_coeffs = cmp::max(self.coeffs.len(), rhs.coeffs.len());
let zero = self.fabric().zero();
let zero_authenticated = self.fabric().zero_authenticated();
let padded_lhs = self
.coeffs
.iter()
.chain(iter::repeat(&zero_authenticated))
.take(n_coeffs);
let padded_rhs = rhs.coeffs.iter().chain(iter::repeat(&zero)).take(n_coeffs);
let mut coeffs = Vec::with_capacity(n_coeffs);
for (lhs_coeff, rhs_coeff) in padded_lhs.zip(padded_rhs) {
coeffs.push(lhs_coeff + rhs_coeff);
}
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomialResult<C>, C: CurveGroup);
impl_commutative!(AuthenticatedDensePoly<C>, Add, add, +, DensePolynomialResult<C>, C: CurveGroup);
impl<C: CurveGroup> Add<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn add(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
let (shorter, longer) = if self.coeffs.len() < rhs.coeffs.len() {
(&self.coeffs, &rhs.coeffs)
} else {
(&rhs.coeffs, &self.coeffs)
};
let mut coeffs = Vec::new();
for (i, longer_coeff) in longer.iter().enumerate() {
let new_coeff = if i < shorter.len() {
&shorter[i] + longer_coeff
} else {
longer_coeff.clone()
};
coeffs.push(new_coeff);
}
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Add, add, +, AuthenticatedDensePoly<C>, C: CurveGroup);
impl<C: CurveGroup> Neg for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn neg(self) -> Self::Output {
let coeffs = self
.coeffs
.iter()
.map(|coeff| coeff.neg())
.collect::<Vec<_>>();
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Neg, neg, -, C: CurveGroup);
#[allow(clippy::suspicious_arithmetic_impl)]
impl<C: CurveGroup> Sub<&DensePolynomial<C::ScalarField>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn sub(self, rhs: &DensePolynomial<C::ScalarField>) -> Self::Output {
let negated_rhs_coeffs = rhs.coeffs.iter().map(|coeff| coeff.neg()).collect_vec();
self + DensePolynomial::from_coefficients_vec(negated_rhs_coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Sub, sub, -, DensePolynomial<C::ScalarField>, C: CurveGroup);
#[allow(clippy::suspicious_arithmetic_impl)]
impl<C: CurveGroup> Sub<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn sub(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
self + (-rhs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Sub, sub, -, AuthenticatedDensePoly<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&DensePolynomial<C::ScalarField>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn mul(self, rhs: &DensePolynomial<C::ScalarField>) -> Self::Output {
assert!(
!self.coeffs.is_empty(),
"cannot multiply an empty polynomial"
);
let fabric = self.coeffs[0].fabric();
let result_degree = self.degree() + rhs.degree();
let mut coeffs = Vec::with_capacity(result_degree + 1);
for _ in 0..(result_degree + 1) {
coeffs.push(fabric.zero_authenticated());
}
for (i, lhs_coeff) in self.coeffs.iter().enumerate() {
for (j, rhs_coeff) in rhs.coeffs.iter().enumerate() {
coeffs[i + j] = &coeffs[i + j] + (lhs_coeff * Scalar::<C>::new(*rhs_coeff));
}
}
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl<C: CurveGroup> Mul<&DensePolynomialResult<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn mul(self, rhs: &DensePolynomialResult<C>) -> Self::Output {
assert!(
!self.coeffs.is_empty(),
"cannot multiply an empty polynomial"
);
let fabric = self.coeffs[0].fabric();
let result_degree = self.degree() + rhs.degree();
let mut coeffs = Vec::with_capacity(result_degree + 1);
for _ in 0..(result_degree + 1) {
coeffs.push(fabric.zero_authenticated());
}
for (i, lhs_coeff) in self.coeffs.iter().enumerate() {
for (j, rhs_coeff) in rhs.coeffs.iter().enumerate() {
coeffs[i + j] = &coeffs[i + j] + (lhs_coeff * rhs_coeff);
}
}
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, DensePolynomialResult<C>, C: CurveGroup);
impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, DensePolynomialResult<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn mul(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
assert!(
!self.coeffs.is_empty(),
"cannot multiply an empty polynomial"
);
let fabric = self.coeffs[0].fabric();
let result_degree = self.degree() + rhs.degree();
let mut coeffs = Vec::with_capacity(result_degree + 1);
for _ in 0..(result_degree + 1) {
coeffs.push(fabric.zero_authenticated());
}
for (i, lhs_coeff) in self.coeffs.iter().enumerate() {
for (j, rhs_coeff) in rhs.coeffs.iter().enumerate() {
coeffs[i + j] = &coeffs[i + j] + (lhs_coeff * rhs_coeff);
}
}
AuthenticatedDensePoly::from_coeffs(coeffs)
}
}
impl<C: CurveGroup> Mul<&Scalar<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn mul(self, rhs: &Scalar<C>) -> Self::Output {
let new_coeffs = self.coeffs.iter().map(|coeff| coeff * rhs).collect_vec();
AuthenticatedDensePoly::from_coeffs(new_coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, Scalar<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&ScalarResult<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn mul(self, rhs: &ScalarResult<C>) -> Self::Output {
let new_coeffs = self.coeffs.iter().map(|coeff| coeff * rhs).collect_vec();
AuthenticatedDensePoly::from_coeffs(new_coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, ScalarResult<C>, C: CurveGroup);
impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, ScalarResult<C>, C: CurveGroup);
impl<C: CurveGroup> Mul<&AuthenticatedScalarResult<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn mul(self, rhs: &AuthenticatedScalarResult<C>) -> Self::Output {
let new_coeffs = self.coeffs.iter().map(|coeff| coeff * rhs).collect_vec();
AuthenticatedDensePoly::from_coeffs(new_coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Mul, mul, *, AuthenticatedScalarResult<C>, C: CurveGroup);
impl_commutative!(AuthenticatedDensePoly<C>, Mul, mul, *, AuthenticatedScalarResult<C>, C: CurveGroup);
impl<C: CurveGroup> Div<&DensePolynomialResult<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn div(self, rhs: &DensePolynomialResult<C>) -> Self::Output {
assert!(!rhs.coeffs.is_empty(), "cannot divide by zero polynomial");
let fabric = self.coeffs[0].fabric();
let quotient_degree = self.degree().saturating_sub(rhs.degree());
if quotient_degree == 0 {
return AuthenticatedDensePoly::zero(fabric);
}
let mut remainder = self.clone();
let mut quotient_coeffs = fabric.zeros_authenticated(quotient_degree + 1);
let divisor_leading_inverse = rhs.coeffs.last().unwrap().inverse();
for deg in (0..=quotient_degree).rev() {
let remainder_leading_coeff = remainder.coeffs.last().unwrap();
let next_quotient_coeff = remainder_leading_coeff * &divisor_leading_inverse;
for (i, divisor_coeff) in rhs.coeffs.iter().enumerate() {
let remainder_ind = deg + i;
remainder.coeffs[remainder_ind] =
&remainder.coeffs[remainder_ind] - divisor_coeff * &next_quotient_coeff;
}
quotient_coeffs[deg] = next_quotient_coeff;
remainder.coeffs.pop();
}
AuthenticatedDensePoly::from_coeffs(quotient_coeffs)
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Div, div, /, DensePolynomialResult<C>, C: CurveGroup);
impl<C: CurveGroup> Div<&AuthenticatedDensePoly<C>> for &AuthenticatedDensePoly<C> {
type Output = AuthenticatedDensePoly<C>;
fn div(self, rhs: &AuthenticatedDensePoly<C>) -> Self::Output {
let n = self.degree();
let m = rhs.degree();
if n < m {
return AuthenticatedDensePoly::zero(self.fabric());
}
let modulus = n - m + 1;
let rev_f = self.rev();
let rev_g = rhs.rev();
let rev_g_inv = rev_g.mul_inverse_mod_t(modulus);
let rev_q = (&rev_f * &rev_g_inv).mod_xn(modulus);
rev_q.rev()
}
}
impl_borrow_variants!(AuthenticatedDensePoly<C>, Div, div, /, AuthenticatedDensePoly<C>, C: CurveGroup);
#[cfg(test)]
mod test {
use ark_poly::Polynomial;
use rand::thread_rng;
use crate::{
algebra::{
poly_test_helpers::{allocate_poly, random_poly, share_poly},
Scalar,
},
test_helpers::execute_mock_mpc,
PARTY0, PARTY1,
};
const DEGREE_BOUND: usize = 100;
#[tokio::test]
async fn test_eval() {
let mut rng = thread_rng();
let poly = random_poly(DEGREE_BOUND);
let point = Scalar::random(&mut rng);
let expected_res = poly.evaluate(&point.inner());
let (res, _) = execute_mock_mpc(|fabric| {
let poly = poly.clone();
async move {
let shared_poly = share_poly(poly, PARTY0, &fabric);
let point = fabric.allocate_scalar(point);
shared_poly.eval(&point).open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), Scalar::new(expected_res));
}
#[tokio::test]
async fn test_add_constant_poly() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 + &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let res = &shared_poly1 + &poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_add_public_poly() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 + &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let poly2 = allocate_poly(&poly2, &fabric);
let res = &shared_poly1 + &poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_add_poly() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 + &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let shared_poly2 = share_poly(poly2, PARTY0, &fabric);
let res = &shared_poly1 + &shared_poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_subtract_constant_poly() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 - &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let res = &shared_poly1 - &poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_subtract_poly() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 - &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let shared_poly2 = share_poly(poly2, PARTY0, &fabric);
let res = &shared_poly1 - &shared_poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_mul_constant_polynomial() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 * &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let res = &shared_poly1 * &poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_mul_public_polynomial() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 * &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let poly2 = allocate_poly(&poly2, &fabric);
let res = &shared_poly1 * &poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_mul_polynomial() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 * &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let shared_poly1 = share_poly(poly1, PARTY0, &fabric);
let shared_poly2 = share_poly(poly2, PARTY0, &fabric);
let res = &shared_poly1 * &shared_poly2;
res.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_scalar_mul_constant() {
let mut rng = thread_rng();
let poly = random_poly(DEGREE_BOUND);
let scaling_factor = Scalar::random(&mut rng);
let expected_res = &poly * scaling_factor.inner();
let (res, _) = execute_mock_mpc(|fabric| {
let poly = poly.clone();
async move {
let shared_poly = share_poly(poly, PARTY0, &fabric);
(shared_poly * scaling_factor).open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_scalar_mul_public() {
let mut rng = thread_rng();
let poly = random_poly(DEGREE_BOUND);
let scaling_factor = Scalar::random(&mut rng);
let expected_res = &poly * scaling_factor.inner();
let (res, _) = execute_mock_mpc(|fabric| {
let poly = poly.clone();
async move {
let shared_poly = share_poly(poly, PARTY0, &fabric);
let scaling_factor = fabric.allocate_scalar(scaling_factor);
(shared_poly * scaling_factor).open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_scalar_mul() {
let mut rng = thread_rng();
let poly = random_poly(DEGREE_BOUND);
let scaling_factor = Scalar::random(&mut rng);
let expected_res = &poly * scaling_factor.inner();
let (res, _) = execute_mock_mpc(|fabric| {
let poly = poly.clone();
async move {
let shared_poly = share_poly(poly, PARTY0, &fabric);
let scaling_factor = fabric.share_scalar(scaling_factor, PARTY0);
(shared_poly * scaling_factor).open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_div_polynomial_public() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 / &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let dividend = share_poly(poly1, PARTY0, &fabric);
let divisor = allocate_poly(&poly2, &fabric);
let quotient = dividend / divisor;
quotient.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
#[tokio::test]
async fn test_div_polynomial() {
let poly1 = random_poly(DEGREE_BOUND);
let poly2 = random_poly(DEGREE_BOUND);
let expected_res = &poly1 / &poly2;
let (res, _) = execute_mock_mpc(|fabric| {
let poly1 = poly1.clone();
let poly2 = poly2.clone();
async move {
let dividend = share_poly(poly1, PARTY0, &fabric);
let divisor = share_poly(poly2, PARTY1, &fabric);
let quotient = dividend / divisor;
quotient.open_authenticated().await
}
})
.await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), expected_res);
}
}