use crate::modulus::barrett::Barrett; use crate::modulus::montgomery::Montgomery; use crate::modulus::prime::Prime; use crate::modulus::ReduceOnce; use crate::modulus::REDUCEMOD; use crate::modulus::{ScalarOperations, VectorOperations}; use crate::{apply_sv, apply_svv, apply_v, apply_vsv, apply_vv, apply_vvsv, apply_vvv}; use itertools::izip; impl ScalarOperations for Prime { /// Applies a modular reduction on x based on REDUCE: /// - LAZY: no modular reduction. /// - ONCE: subtracts q if x >= q. /// - TWO: subtracts 2q if x >= 2q. /// - FOUR: subtracts 4q if x >= 4q. /// - BARRETT: maps x to x mod q using Barrett reduction. /// - BARRETTLAZY: maps x to x mod q using Barrett reduction with values in [0, 2q-1]. #[inline(always)] fn sa_reduce_into_sa(&self, a: &mut u64) { self.montgomery.reduce_assign::(a); } #[inline(always)] fn sa_add_sb_into_sc(&self, a: &u64, b: &u64, c: &mut u64) { *c = a.wrapping_add(*b); self.sa_reduce_into_sa::(c); } #[inline(always)] fn sa_add_sb_into_sb(&self, a: &u64, b: &mut u64) { *b = a.wrapping_add(*b); self.sa_reduce_into_sa::(b); } #[inline(always)] fn sa_sub_sb_into_sc(&self, a: &u64, b: &u64, c: &mut u64) { *c = a.wrapping_add(self.q.wrapping_sub(*b)).reduce_once(self.q); } #[inline(always)] fn sa_sub_sb_into_sb(&self, a: &u64, b: &mut u64) { *b = a.wrapping_add(self.q.wrapping_sub(*b)).reduce_once(self.q); } #[inline(always)] fn sa_neg_into_sa(&self, a: &mut u64) { *a = self.q.wrapping_sub(*a); self.sa_reduce_into_sa::(a) } #[inline(always)] fn sa_neg_into_sb(&self, a: &u64, b: &mut u64) { *b = self.q.wrapping_sub(*a); self.sa_reduce_into_sa::(b) } #[inline(always)] fn sa_prep_mont_into_sb(&self, a: &u64, b: &mut Montgomery) { self.montgomery.prepare_assign::(*a, b); } #[inline(always)] fn sa_mont_mul_sb_into_sc( &self, a: &Montgomery, b: &u64, c: &mut u64, ) { *c = self.montgomery.mul_external::(*a, *b); } #[inline(always)] fn sa_mont_mul_sb_into_sb(&self, a: &Montgomery, b: &mut u64) { self.montgomery.mul_external_assign::(*a, b); } #[inline(always)] fn sa_barrett_mul_sb_into_sc( &self, a: &Barrett, b: &u64, c: &mut u64, ) { *c = self.barrett.mul_external::(*a, *b); } #[inline(always)] fn sa_barrett_mul_sb_into_sb(&self, a: &Barrett, b: &mut u64) { self.barrett.mul_external_assign::(*a, b); } #[inline(always)] fn sa_sub_sb_mul_sc_into_sd( &self, a: &u64, b: &u64, c: &Barrett, d: &mut u64, ) { *d = self.two_q.wrapping_sub(*b).wrapping_add(*a); self.barrett.mul_external_assign::(*c, d); } #[inline(always)] fn sa_sub_sb_mul_sc_into_sb( &self, a: &u64, c: &Barrett, b: &mut u64, ) { *b = self.two_q.wrapping_sub(*b).wrapping_add(*a); self.barrett.mul_external_assign::(*c, b); } } impl VectorOperations for Prime { /// Applies a modular reduction on x based on REDUCE: /// - LAZY: no modular reduction. /// - ONCE: subtracts q if x >= q. /// - TWO: subtracts 2q if x >= 2q. /// - FOUR: subtracts 4q if x >= 4q. /// - BARRETT: maps x to x mod q using Barrett reduction. /// - BARRETTLAZY: maps x to x mod q using Barrett reduction with values in [0, 2q-1]. #[inline(always)] fn va_reduce_into_va(&self, a: &mut [u64]) { apply_v!(self, Self::sa_reduce_into_sa::, a, CHUNK); } #[inline(always)] fn va_add_vb_into_vc( &self, a: &[u64], b: &[u64], c: &mut [u64], ) { apply_vvv!(self, Self::sa_add_sb_into_sc::, a, b, c, CHUNK); } #[inline(always)] fn va_add_vb_into_vb( &self, a: &[u64], b: &mut [u64], ) { apply_vv!(self, Self::sa_add_sb_into_sb::, a, b, CHUNK); } #[inline(always)] fn va_add_sb_into_vc( &self, a: &[u64], b: &u64, c: &mut [u64], ) { apply_vsv!(self, Self::sa_add_sb_into_sc::, a, b, c, CHUNK); } #[inline(always)] fn sa_add_vb_into_vb( &self, a: &u64, b: &mut [u64], ) { apply_sv!(self, Self::sa_add_sb_into_sb::, a, b, CHUNK); } #[inline(always)] fn va_sub_vb_into_vc( &self, a: &[u64], b: &[u64], c: &mut [u64], ) { apply_vvv!(self, Self::sa_sub_sb_into_sc::, a, b, c, CHUNK); } #[inline(always)] fn va_sub_vb_into_vb( &self, a: &[u64], b: &mut [u64], ) { apply_vv!(self, Self::sa_sub_sb_into_sb::, a, b, CHUNK); } #[inline(always)] fn va_neg_into_va(&self, a: &mut [u64]) { apply_v!(self, Self::sa_neg_into_sa::, a, CHUNK); } #[inline(always)] fn va_neg_into_vb( &self, a: &[u64], b: &mut [u64], ) { apply_vv!(self, Self::sa_neg_into_sb::, a, b, CHUNK); } #[inline(always)] fn va_prep_mont_into_vb( &self, a: &[u64], b: &mut [Montgomery], ) { apply_vv!(self, Self::sa_prep_mont_into_sb::, a, b, CHUNK); } #[inline(always)] fn va_mont_mul_vb_into_vc( &self, a: &[Montgomery], b: &[u64], c: &mut [u64], ) { apply_vvv!(self, Self::sa_mont_mul_sb_into_sc::, a, b, c, CHUNK); } #[inline(always)] fn va_mont_mul_vb_into_vb( &self, a: &[Montgomery], b: &mut [u64], ) { apply_vv!(self, Self::sa_mont_mul_sb_into_sb::, a, b, CHUNK); } #[inline(always)] fn sa_barrett_mul_vb_into_vc( &self, a: &Barrett, b: &[u64], c: &mut [u64], ) { apply_svv!( self, Self::sa_barrett_mul_sb_into_sc::, a, b, c, CHUNK ); } #[inline(always)] fn sa_barrett_mul_vb_into_vb( &self, a: &Barrett, b: &mut [u64], ) { apply_sv!(self, Self::sa_barrett_mul_sb_into_sb::, a, b, CHUNK); } fn va_sub_vb_mul_sc_into_vd( &self, a: &[u64], b: &[u64], c: &Barrett, d: &mut [u64], ) { apply_vvsv!( self, Self::sa_sub_sb_mul_sc_into_sd::, a, b, c, d, CHUNK ); } fn va_sub_vb_mul_sc_into_vb( &self, a: &[u64], b: &Barrett, c: &mut [u64], ) { apply_vsv!( self, Self::sa_sub_sb_mul_sc_into_sb::, a, b, c, CHUNK ); } }