use crate::Exceptions;
use crate::common::Result;
use super::ModulusGF;
#[derive(Clone, Debug)]
pub struct ModulusPoly {
field: &'static ModulusGF,
coefficients: Vec<u32>,
}
impl ModulusPoly {
pub fn new(field: &'static ModulusGF, coefficients: Vec<u32>) -> Result<ModulusPoly> {
if coefficients.is_empty() {
return Err(Exceptions::ILLEGAL_ARGUMENT);
}
let orig_coefs = coefficients.clone();
let mut coefficients = coefficients;
let coefficientsLength = coefficients.len();
if coefficientsLength > 1 && coefficients[0] == 0 {
let mut firstNonZero = 1;
while firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0 {
firstNonZero += 1;
}
if firstNonZero == coefficientsLength {
coefficients = vec![0];
} else {
coefficients = vec![0u32; coefficientsLength - firstNonZero];
coefficients[..].copy_from_slice(&orig_coefs[firstNonZero..]);
}
}
Ok(ModulusPoly {
field,
coefficients,
})
}
pub fn getCoefficients(&self) -> &[u32] {
&self.coefficients
}
pub fn getDegree(&self) -> u32 {
self.coefficients.len() as u32 - 1
}
pub fn isZero(&self) -> bool {
self.coefficients[0] == 0
}
pub fn getCoefficient(&self, degree: usize) -> u32 {
self.coefficients[self.coefficients.len() - 1 - degree]
}
pub fn evaluateAt(&self, a: u32) -> u32 {
if a == 0 {
return self.getCoefficient(0);
}
if a == 1 {
let mut result = 0;
for coefficient in self.coefficients.iter() {
result = self.field.add(result, *coefficient);
}
return result;
}
let mut result = self.coefficients[0];
let size = self.coefficients.len();
for i in 1..size {
result = self
.field
.add(self.field.multiply(a, result), self.coefficients[i]);
}
result
}
pub fn add(&self, other: ModulusPoly) -> Result<ModulusPoly> {
if self.field != other.field {
return Err(Exceptions::illegal_argument_with(
"ModulusPolys do not have same ModulusGF field",
));
}
if self.isZero() {
return Ok(other);
}
if other.isZero() {
return Ok(self.clone());
}
let mut smallerCoefficients = &self.coefficients;
let mut largerCoefficients = &other.coefficients;
if smallerCoefficients.len() > largerCoefficients.len() {
std::mem::swap(&mut smallerCoefficients, &mut largerCoefficients);
}
let mut sumDiff = vec![0_u32; largerCoefficients.len()];
let lengthDiff = largerCoefficients.len() - smallerCoefficients.len();
sumDiff[..lengthDiff].copy_from_slice(&largerCoefficients[..lengthDiff]);
for i in lengthDiff..largerCoefficients.len() {
sumDiff[i] = self
.field
.add(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
ModulusPoly::new(self.field, sumDiff)
}
pub fn subtract(&self, other: ModulusPoly) -> Result<ModulusPoly> {
if self.field != other.field {
return Err(Exceptions::illegal_argument_with(
"ModulusPolys do not have same ModulusGF field",
));
}
if other.isZero() {
return Ok(self.clone());
};
self.add(other.negative())
}
pub fn multiply(&self, other: ModulusPoly) -> Result<ModulusPoly> {
if !(self.field == other.field) {
return Err(Exceptions::illegal_argument_with(
"ModulusPolys do not have same ModulusGF field",
));
}
if self.isZero() || other.isZero() {
return Ok(Self::getZero(self.field));
}
let aCoefficients = &self.coefficients;
let aLength = aCoefficients.len();
let bCoefficients = &other.coefficients;
let bLength = bCoefficients.len();
let mut product = vec![0u32; aLength + bLength - 1];
for i in 0..aLength {
let aCoeff = aCoefficients[i];
for j in 0..bLength {
product[i + j] = self.field.add(
product[i + j],
self.field.multiply(aCoeff, bCoefficients[j]),
);
}
}
ModulusPoly::new(self.field, product)
}
pub fn negative(&self) -> ModulusPoly {
let size = self.coefficients.len();
let mut negativeCoefficients = vec![0u32; size];
for (i, neg_coef) in negativeCoefficients.iter_mut().enumerate().take(size) {
*neg_coef = self.field.subtract(0, self.coefficients[i]);
}
ModulusPoly::new(self.field, negativeCoefficients)
.expect("should always generate with known goods")
}
pub fn multiplyByScaler(&self, scalar: u32) -> ModulusPoly {
if scalar == 0 {
return Self::getZero(self.field);
}
if scalar == 1 {
return self.clone();
}
let size = self.coefficients.len();
let mut product = vec![0u32; size];
for (i, prod) in product.iter_mut().enumerate().take(size) {
*prod = self.field.multiply(self.coefficients[i], scalar);
}
ModulusPoly::new(self.field, product).expect("should always generate with known goods")
}
pub fn multiplyByMonomial(&self, degree: usize, coefficient: u32) -> ModulusPoly {
if coefficient == 0 {
return Self::getZero(self.field);
}
let size = self.coefficients.len();
let mut product = vec![0u32; size + degree];
for (i, prod) in product.iter_mut().enumerate().take(size) {
*prod = self.field.multiply(self.coefficients[i], coefficient);
}
ModulusPoly::new(self.field, product).expect("should always generate with known goods")
}
pub fn getZero(field: &'static ModulusGF) -> ModulusPoly {
ModulusPoly::new(field, vec![0]).expect("should always generate with known goods")
}
pub fn getOne(field: &'static ModulusGF) -> ModulusPoly {
ModulusPoly::new(field, vec![1]).expect("should always generate with known goods")
}
pub fn buildMonomial(
field: &'static ModulusGF,
degree: usize,
coefficient: u32,
) -> ModulusPoly {
if coefficient == 0 {
return Self::getZero(field);
}
let mut coefficients = vec![0_u32; degree + 1];
coefficients[0] = coefficient;
ModulusPoly::new(field, coefficients).expect("should always generate with known goods")
}
}