From 66a75139870754bbe192d99e663ec73ca00e6261 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bossuat Date: Fri, 3 Jan 2025 22:06:06 +0100 Subject: [PATCH] wip --- math/Cargo.toml | 4 + math/benches/ring_rns.rs | 39 +++++++ math/src/dft/ntt.rs | 20 ++-- math/src/lib.rs | 120 ++++++++++++++++++- math/src/modulus.rs | 18 +++ math/src/modulus/barrett.rs | 2 + math/src/modulus/impl_u64/barrett.rs | 76 +++++------- math/src/modulus/impl_u64/montgomery.rs | 20 +--- math/src/modulus/impl_u64/operations.rs | 53 +++++++-- math/src/poly.rs | 27 ++++- math/src/ring.rs | 43 ++++++- math/src/ring/impl_u64/mod.rs | 3 +- math/src/ring/impl_u64/rescaling_rns.rs | 56 +++++++++ math/src/ring/impl_u64/ring.rs | 52 ++++++++- math/src/ring/impl_u64/ring_rns.rs | 148 ++++++++++++------------ 15 files changed, 505 insertions(+), 176 deletions(-) create mode 100644 math/benches/ring_rns.rs create mode 100644 math/src/ring/impl_u64/rescaling_rns.rs diff --git a/math/Cargo.toml b/math/Cargo.toml index fdc7dd2..3cb66bc 100644 --- a/math/Cargo.toml +++ b/math/Cargo.toml @@ -17,4 +17,8 @@ harness = false [[bench]] name = "operations" +harness = false + +[[bench]] +name = "ring_rns" harness = false \ No newline at end of file diff --git a/math/benches/ring_rns.rs b/math/benches/ring_rns.rs new file mode 100644 index 0000000..271ab20 --- /dev/null +++ b/math/benches/ring_rns.rs @@ -0,0 +1,39 @@ +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use math::ring::{Ring, RingRNS}; +use math::ring::impl_u64::ring_rns::new_rings; +use math::poly::PolyRNS; + +fn div_floor_by_last_modulus_ntt(c: &mut Criterion) { + fn runner(r: RingRNS) -> Box { + + let a: PolyRNS = r.new_polyrns(); + let mut b: PolyRNS = r.new_polyrns(); + let mut c: PolyRNS = r.new_polyrns(); + + Box::new(move || { + r.div_floor_by_last_modulus_ntt(&a, &mut b, &mut c) + }) + } + + let mut b: criterion::BenchmarkGroup<'_, criterion::measurement::WallTime> = c.benchmark_group("div_floor_by_last_modulus_ntt"); + for log_n in 11..18 { + + let n = 1< = vec![0x1fffffffffe00001u64, 0x1fffffffffc80001u64, 0x1fffffffffb40001, 0x1fffffffff500001]; + let rings: Vec> = new_rings(n, moduli); + let ring_rns: RingRNS<'_, u64> = RingRNS::new(&rings); + + let runners = [ + (format!("prime/n={}/level={}", n, ring_rns.level()), { + runner(ring_rns) + }), + ]; + + for (name, mut runner) in runners { + b.bench_with_input(name, &(), |b, _| b.iter(&mut runner)); + } + } +} + +criterion_group!(benches, div_floor_by_last_modulus_ntt); +criterion_main!(benches); diff --git a/math/src/dft/ntt.rs b/math/src/dft/ntt.rs index f987fde..8a2a49f 100644 --- a/math/src/dft/ntt.rs +++ b/math/src/dft/ntt.rs @@ -3,7 +3,7 @@ use crate::modulus::barrett::Barrett; use crate::modulus::prime::Prime; use crate::modulus::ReduceOnce; use crate::modulus::WordOps; -use crate::modulus::ONCE; +use crate::modulus::{NONE, ONCE, BARRETT}; use crate::dft::DFT; use itertools::izip; @@ -114,8 +114,8 @@ impl Table{ izip!(a.chunks_exact_mut(t), &self.psi_forward_rev[m..]).for_each(|(a, psi)| { let (a, b) = a.split_at_mut(size); self.dit_inplace::(&mut a[0], &mut b[0], *psi); - self.prime.barrett.reduce_assign(&mut a[0]); - self.prime.barrett.reduce_assign(&mut b[0]); + self.prime.barrett.reduce_assign::(&mut a[0]); + self.prime.barrett.reduce_assign::(&mut b[0]); debug_assert!(a[0] < self.q, "forward_inplace_core:: output {} > {} (q-1)", a[0], self.q-1); debug_assert!(b[0] < self.q, "forward_inplace_core:: output {} > {} (q-1)", b[0], self.q-1); }); @@ -149,7 +149,7 @@ impl Table{ debug_assert!(*a < self.four_q, "a:{} q:{}", a, self.four_q); debug_assert!(*b < self.four_q, "b:{} q:{}", b, self.four_q); a.reduce_once_assign(self.two_q); - let bt: u64 = self.prime.barrett.mul_external_lazy(t, *b); + let bt: u64 = self.prime.barrett.mul_external::(t, *b); *b = a.wrapping_add(self.two_q-bt); *a = a.wrapping_add(bt); if !LAZY { @@ -176,7 +176,7 @@ impl Table{ if layer == 0 { let n_inv: Barrett = self.prime.barrett.prepare(self.prime.inv(n as u64)); - let psi: Barrett = self.prime.barrett.prepare(self.prime.barrett.mul_external(n_inv, self.psi_backward_rev[1].0)); + let psi: Barrett = self.prime.barrett.prepare(self.prime.barrett.mul_external::(n_inv, self.psi_backward_rev[1].0)); izip!(a.chunks_exact_mut(2 * size)).for_each( |a| { @@ -225,7 +225,7 @@ impl Table{ fn dif_inplace(&self, a: &mut u64, b: &mut u64, t: Barrett) { debug_assert!(*a < self.two_q, "a:{} q:{}", a, self.four_q); debug_assert!(*b < self.two_q, "b:{} q:{}", b, self.four_q); - let d: u64 = self.prime.barrett.mul_external_lazy(t, *a + self.two_q - *b); + let d: u64 = self.prime.barrett.mul_external::(t, *a + self.two_q - *b); *a = a.wrapping_add(*b); a.reduce_once_assign(self.two_q); *b = d; @@ -239,12 +239,12 @@ impl Table{ debug_assert!(*a < self.two_q); debug_assert!(*b < self.two_q); if LAZY{ - let d: u64 = self.prime.barrett.mul_external_lazy(psi, *a + self.two_q - *b); - *a = self.prime.barrett.mul_external_lazy(n_inv, *a + *b); + let d: u64 = self.prime.barrett.mul_external::(psi, *a + self.two_q - *b); + *a = self.prime.barrett.mul_external::(n_inv, *a + *b); *b = d; }else{ - let d: u64 = self.prime.barrett.mul_external(psi, *a + self.two_q - *b); - *a = self.prime.barrett.mul_external(n_inv, *a + *b); + let d: u64 = self.prime.barrett.mul_external::(psi, *a + self.two_q - *b); + *a = self.prime.barrett.mul_external::(n_inv, *a + *b); *b = d; } } diff --git a/math/src/lib.rs b/math/src/lib.rs index 3dba2fe..8ee8bd7 100644 --- a/math/src/lib.rs +++ b/math/src/lib.rs @@ -11,13 +11,12 @@ pub const CHUNK: usize= 8; pub mod macros{ #[macro_export] - macro_rules! apply_unary { + macro_rules! apply_v { ($self:expr, $f:expr, $a:expr, $CHUNK:expr) => { match CHUNK{ 8 => { - $a.chunks_exact_mut(8).for_each(|a| { $f(&$self, &mut a[0]); $f(&$self, &mut a[1]); @@ -45,7 +44,7 @@ pub mod macros{ } #[macro_export] - macro_rules! apply_binary { + macro_rules! apply_vv { ($self:expr, $f:expr, $a:expr, $b:expr, $CHUNK:expr) => { @@ -82,12 +81,13 @@ pub mod macros{ } #[macro_export] - macro_rules! apply_ternary { + macro_rules! apply_vvv { ($self:expr, $f:expr, $a:expr, $b:expr, $c:expr, $CHUNK:expr) => { let n: usize = $a.len(); debug_assert!($b.len() == n, "invalid argument b: b.len() = {} != a.len() = {}", $b.len(), n); + debug_assert!($c.len() == n, "invalid argument c: b.len() = {} != a.len() = {}", $c.len(), n); debug_assert!(CHUNK&(CHUNK-1) == 0, "invalid CHUNK const: not a power of two"); match CHUNK{ @@ -117,4 +117,116 @@ pub mod macros{ } }; } + + #[macro_export] + macro_rules! apply_sv { + + ($self:expr, $f:expr, $a:expr, $b:expr, $CHUNK:expr) => { + + let n: usize = $b.len(); + + debug_assert!(CHUNK&(CHUNK-1) == 0, "invalid CHUNK const: not a power of two"); + + match CHUNK{ + 8 => { + + izip!($b.chunks_exact_mut(8)).for_each(|b| { + $f(&$self, $a, &mut b[0]); + $f(&$self, $a, &mut b[1]); + $f(&$self, $a, &mut b[2]); + $f(&$self, $a, &mut b[3]); + $f(&$self, $a, &mut b[4]); + $f(&$self, $a, &mut b[5]); + $f(&$self, $a, &mut b[6]); + $f(&$self, $a, &mut b[7]); + }); + + let m = n - (n&7); + izip!($b[m..].iter_mut()).for_each(|b| { + $f(&$self, $a, b); + }); + }, + _=>{ + izip!($b.iter_mut()).for_each(|b| { + $f(&$self, $a, b); + }); + } + } + }; + } + + #[macro_export] + macro_rules! apply_svv { + + ($self:expr, $f:expr, $a:expr, $b:expr, $c:expr, $CHUNK:expr) => { + + let n: usize = $b.len(); + debug_assert!($c.len() == n, "invalid argument c: c.len() = {} != b.len() = {}", $c.len(), n); + debug_assert!(CHUNK&(CHUNK-1) == 0, "invalid CHUNK const: not a power of two"); + + match CHUNK{ + 8 => { + + izip!($b.chunks_exact(8), $c.chunks_exact_mut(8)).for_each(|(b, c)| { + $f(&$self, $a, &b[0], &mut c[0]); + $f(&$self, $a, &b[1], &mut c[1]); + $f(&$self, $a, &b[2], &mut c[2]); + $f(&$self, $a, &b[3], &mut c[3]); + $f(&$self, $a, &b[4], &mut c[4]); + $f(&$self, $a, &b[5], &mut c[5]); + $f(&$self, $a, &b[6], &mut c[6]); + $f(&$self, $a, &b[7], &mut c[7]); + }); + + let m = n - (n&7); + izip!($b[m..].iter(), $c[m..].iter_mut()).for_each(|(b, c)| { + $f(&$self, $a, b, c); + }); + }, + _=>{ + izip!($b.iter(), $c.iter_mut()).for_each(|(b, c)| { + $f(&$self, $a, b, c); + }); + } + } + }; + } + + #[macro_export] + macro_rules! apply_vvsv { + + ($self:expr, $f:expr, $a:expr, $b:expr, $c:expr, $d:expr, $CHUNK:expr) => { + + let n: usize = $a.len(); + debug_assert!($b.len() == n, "invalid argument b: b.len() = {} != a.len() = {}", $b.len(), n); + debug_assert!($d.len() == n, "invalid argument d: d.len() = {} != a.len() = {}", $d.len(), n); + debug_assert!(CHUNK&(CHUNK-1) == 0, "invalid CHUNK const: not a power of two"); + + match CHUNK{ + 8 => { + + izip!($a.chunks_exact(8), $b.chunks_exact(8), $d.chunks_exact_mut(8)).for_each(|(a, b, d)| { + $f(&$self, &a[0], &b[0], $c, &mut d[0]); + $f(&$self, &a[1], &b[1], $c, &mut d[1]); + $f(&$self, &a[2], &b[2], $c, &mut d[2]); + $f(&$self, &a[3], &b[3], $c, &mut d[3]); + $f(&$self, &a[4], &b[4], $c, &mut d[4]); + $f(&$self, &a[5], &b[5], $c, &mut d[5]); + $f(&$self, &a[6], &b[6], $c, &mut d[6]); + $f(&$self, &a[7], &b[7], $c, &mut d[7]); + }); + + let m = n - (n&7); + izip!($a[m..].iter(), $b[m..].iter(), $d[m..].iter_mut()).for_each(|(a, b, d)| { + $f(&$self, a, b, $c, d); + }); + }, + _=>{ + izip!($a.iter(), $b.iter(), $d.iter_mut()).for_each(|(a, b, d)| { + $f(&$self, a, b, $c, d); + }); + } + } + }; + } } \ No newline at end of file diff --git a/math/src/modulus.rs b/math/src/modulus.rs index 7f1adb4..8b14a0d 100644 --- a/math/src/modulus.rs +++ b/math/src/modulus.rs @@ -85,6 +85,15 @@ pub trait WordOperations{ // Assigns a * b to b. fn word_mul_montgomery_external_unary_assign(&self, a:&montgomery::Montgomery, b:&mut O); + + // Assigns a * b to c. + fn word_mul_barrett_binary_assign(&self, a: &barrett::Barrett, b:&O, c: &mut O); + + // Assigns a * b to b. + fn word_mul_barrett_unary_assign(&self, a:&barrett::Barrett, b:&mut O); + + // Assigns (a + 2q - b) * c to d. + fn word_sum_aqqmb_prod_c_barrett_assign_d(&self, a: &O, b: &O, c: &barrett::Barrett, d: &mut O); } pub trait VecOperations{ @@ -118,6 +127,15 @@ pub trait VecOperations{ // Assigns a[i] * b[i] to b[i]. fn vec_mul_montgomery_external_unary_assign(&self, a:&[montgomery::Montgomery], b:&mut [O]); + + // Assigns a * b[i] to b[i]. + fn vec_mul_scalar_barrett_external_unary_assign(&self, a:& barrett::Barrett, b:&mut [u64]); + + // Assigns a * b[i] to c[i]. + fn vec_mul_scalar_barrett_external_binary_assign(&self, a:& barrett::Barrett, b:&[u64], c: &mut [u64]); + + // Assigns (a[i] + 2q - b[i]) * c to d[i]. + fn vec_sum_aqqmb_prod_c_scalar_barrett_assign_d(&self, a: &[u64], b: &[u64], c: &barrett::Barrett, d: &mut [u64]); } diff --git a/math/src/modulus/barrett.rs b/math/src/modulus/barrett.rs index 0499fbb..efaee2e 100644 --- a/math/src/modulus/barrett.rs +++ b/math/src/modulus/barrett.rs @@ -17,6 +17,8 @@ impl Barrett { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct BarrettPrecomp{ pub q: O, + pub two_q:O, + pub four_q:O, pub lo:O, pub hi:O, pub one: Barrett, diff --git a/math/src/modulus/impl_u64/barrett.rs b/math/src/modulus/impl_u64/barrett.rs index 0641009..7a0141f 100644 --- a/math/src/modulus/impl_u64/barrett.rs +++ b/math/src/modulus/impl_u64/barrett.rs @@ -1,5 +1,6 @@ use crate::modulus::barrett::{Barrett, BarrettPrecomp}; use crate::modulus::ReduceOnce; +use crate::modulus::{REDUCEMOD, NONE, ONCE, TWICE, FOURTIMES, BARRETT, BARRETTLAZY}; use num_bigint::BigUint; use num_traits::cast::ToPrimitive; @@ -10,7 +11,7 @@ impl BarrettPrecomp{ let big_r: BigUint = (BigUint::from(1 as usize)<<((u64::BITS<<1) as usize)) / BigUint::from(q); let lo: u64 = (&big_r & BigUint::from(u64::MAX)).to_u64().unwrap(); let hi: u64 = (big_r >> u64::BITS).to_u64().unwrap(); - let mut precomp: BarrettPrecomp = Self{q, lo, hi, one:Barrett(0,0)}; + let mut precomp: BarrettPrecomp = Self{q:q, two_q:q<<1, four_q:q<<2, lo:lo, hi:hi, one:Barrett(0,0)}; precomp.one = precomp.prepare(1); precomp } @@ -20,6 +21,30 @@ impl BarrettPrecomp{ self.one } + /// Applies a modular reduction on x based on REDUCE: + /// - LAZY: no modular reduction. + /// - ONCE: subtracts q if x >= q. + /// - FULL: maps x to x mod q using Barrett reduction. + #[inline(always)] + pub fn reduce_assign(&self, x: &mut u64){ + match REDUCE { + NONE =>{}, + ONCE =>{x.reduce_once_assign(self.q)}, + TWICE=>{x.reduce_once_assign(self.two_q)}, + FOURTIMES =>{x.reduce_once_assign(self.four_q)}, + BARRETT =>{ + let (_, mhi) = x.widening_mul(self.hi); + *x = *x - mhi.wrapping_mul(self.q); + x.reduce_once_assign(self.q); + }, + BARRETTLAZY =>{ + let (_, mhi) = x.widening_mul(self.hi); + *x = *x - mhi.wrapping_mul(self.q) + }, + _ => unreachable!("invalid REDUCE argument") + } + } + #[inline(always)] pub fn prepare(&self, v: u64) -> Barrett { debug_assert!(v < self.q); @@ -27,58 +52,17 @@ impl BarrettPrecomp{ Barrett(v, quotient) } - /// Returns lhs mod q. #[inline(always)] - pub fn reduce(&self, lhs: u64) -> u64{ - let mut r: u64 = self.reduce_lazy(lhs); - r.reduce_once_assign(self.q); - r - } - - /// Returns lhs mod q in range [0, 2q-1]. - #[inline(always)] - pub fn reduce_lazy(&self, lhs: u64) -> u64{ - let (_, mhi) = lhs.widening_mul(self.hi); - lhs - mhi.wrapping_mul(self.q) - } - - /// Assigns lhs mod q to lhs. - #[inline(always)] - pub fn reduce_assign(&self, lhs: &mut u64){ - self.reduce_lazy_assign(lhs); - lhs.reduce_once_assign(self.q); - } - - /// Assigns lhs mod q in range [0, 2q-1] to lhs. - #[inline(always)] - pub fn reduce_lazy_assign(&self, lhs: &mut u64){ - let (_, mhi) = lhs.widening_mul(self.hi); - *lhs = *lhs - mhi.wrapping_mul(self.q) - } - - #[inline(always)] - pub fn mul_external(&self, lhs: Barrett, rhs: u64) -> u64 { - let mut r: u64 = self.mul_external_lazy(lhs, rhs); - r.reduce_once_assign(self.q); - r - } - - #[inline(always)] - pub fn mul_external_assign(&self, lhs: Barrett, rhs: &mut u64){ - self.mul_external_lazy_assign(lhs, rhs); - rhs.reduce_once_assign(self.q); - } - - #[inline(always)] - pub fn mul_external_lazy(&self, lhs: Barrett, rhs: u64) -> u64 { + pub fn mul_external(&self, lhs: Barrett, rhs: u64) -> u64 { let mut r: u64 = rhs; - self.mul_external_lazy_assign(lhs, &mut r); + self.mul_external_assign::(lhs, &mut r); r } #[inline(always)] - pub fn mul_external_lazy_assign(&self, lhs: Barrett, rhs: &mut u64){ + pub fn mul_external_assign(&self, lhs: Barrett, rhs: &mut u64){ let t: u64 = ((*lhs.quotient() as u128 * *rhs as u128) >> 64) as _; *rhs = (rhs.wrapping_mul(*lhs.value())).wrapping_sub(self.q.wrapping_mul(t)); + self.reduce_assign::(rhs); } } \ No newline at end of file diff --git a/math/src/modulus/impl_u64/montgomery.rs b/math/src/modulus/impl_u64/montgomery.rs index cd03a0a..99395d0 100644 --- a/math/src/modulus/impl_u64/montgomery.rs +++ b/math/src/modulus/impl_u64/montgomery.rs @@ -2,7 +2,7 @@ use crate::modulus::ReduceOnce; use crate::modulus::montgomery::{MontgomeryPrecomp, Montgomery}; use crate::modulus::barrett::BarrettPrecomp; -use crate::modulus::{REDUCEMOD, NONE, ONCE, TWICE, FOURTIMES, BARRETT, BARRETTLAZY}; +use crate::modulus::{REDUCEMOD, ONCE}; extern crate test; /// MontgomeryPrecomp is a set of methods implemented for MontgomeryPrecomp @@ -65,15 +65,7 @@ impl MontgomeryPrecomp{ /// - FULL: maps x to x mod q using Barrett reduction. #[inline(always)] pub fn reduce_assign(&self, x: &mut u64){ - match REDUCE { - NONE =>{}, - ONCE =>{x.reduce_once_assign(self.q)}, - TWICE=>{x.reduce_once_assign(self.two_q)}, - FOURTIMES =>{x.reduce_once_assign(self.four_q)}, - BARRETT =>{self.barrett.reduce_assign(x)}, - BARRETTLAZY =>{self.barrett.reduce_lazy_assign(x)}, - _ => unreachable!("invalid REDUCE argument") - } + self.barrett.reduce_assign::(x); } /// Returns lhs * 2^64 mod q as a Montgomery. @@ -137,7 +129,7 @@ impl MontgomeryPrecomp{ #[inline(always)] pub fn add_internal(&self, lhs: Montgomery, rhs: Montgomery) -> Montgomery{ - self.barrett.reduce(rhs + lhs) + rhs + lhs } /// Assigns lhs + rhs to rhs. @@ -153,12 +145,6 @@ impl MontgomeryPrecomp{ rhs.reduce_once_assign(self.q); } - /// Returns lhs mod q in range [0, 2q-1]. - #[inline(always)] - pub fn reduce_lazy_assign(&self, lhs: &mut u64){ - self.barrett.reduce_lazy_assign(lhs) - } - /// Returns (x^exponent) * 2^64 mod q. #[inline(always)] pub fn pow(&self, x: Montgomery, exponent:u64) -> Montgomery{ diff --git a/math/src/modulus/impl_u64/operations.rs b/math/src/modulus/impl_u64/operations.rs index 7f41c92..3acf34c 100644 --- a/math/src/modulus/impl_u64/operations.rs +++ b/math/src/modulus/impl_u64/operations.rs @@ -3,8 +3,9 @@ use crate::modulus::{WordOperations, VecOperations}; use crate::modulus::prime::Prime; use crate::modulus::ReduceOnce; use crate::modulus::montgomery::Montgomery; +use crate::modulus::barrett::Barrett; use crate::modulus::REDUCEMOD; -use crate::{apply_unary, apply_binary, apply_ternary}; +use crate::{apply_v, apply_vv, apply_vvv, apply_sv, apply_svv, apply_vvsv}; use itertools::izip; impl WordOperations for Prime{ @@ -69,6 +70,22 @@ impl WordOperations for Prime{ fn word_mul_montgomery_external_unary_assign(&self, lhs:&Montgomery, rhs:&mut u64){ self.montgomery.mul_external_assign::(*lhs, rhs); } + + #[inline(always)] + fn word_mul_barrett_binary_assign(&self, a: &Barrett, b:&u64, c: &mut u64){ + *c = self.barrett.mul_external::(*a, *b); + } + + #[inline(always)] + fn word_mul_barrett_unary_assign(&self, a:&Barrett, b:&mut u64){ + self.barrett.mul_external_assign::(*a, b); + } + + #[inline(always)] + fn word_sum_aqqmb_prod_c_barrett_assign_d(&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); + } } impl VecOperations for Prime{ @@ -82,51 +99,65 @@ impl VecOperations for Prime{ /// - BARRETTLAZY: maps x to x mod q using Barrett reduction with values in [0, 2q-1]. #[inline(always)] fn vec_reduce_assign(&self, x: &mut [u64]){ - apply_unary!(self, Self::word_reduce_assign::, x, CHUNK); + apply_v!(self, Self::word_reduce_assign::, x, CHUNK); } #[inline(always)] fn vec_add_binary_assign(&self, a: &[u64], b:&[u64], c:&mut [u64]){ - apply_ternary!(self, Self::word_add_binary_assign::, a, b, c, CHUNK); + apply_vvv!(self, Self::word_add_binary_assign::, a, b, c, CHUNK); } #[inline(always)] fn vec_add_unary_assign(&self, a: &[u64], b:&mut [u64]){ - apply_binary!(self, Self::word_add_unary_assign::, a, b, CHUNK); + apply_vv!(self, Self::word_add_unary_assign::, a, b, CHUNK); } #[inline(always)] fn vec_sub_binary_assign(&self, a: &[u64], b:&[u64], c:&mut [u64]){ - apply_ternary!(self, Self::word_sub_binary_assign::, a, b, c, CHUNK); + apply_vvv!(self, Self::word_sub_binary_assign::, a, b, c, CHUNK); } #[inline(always)] fn vec_sub_unary_assign(&self, a: &[u64], b:&mut [u64]){ - apply_binary!(self, Self::word_sub_unary_assign::, a, b, CHUNK); + apply_vv!(self, Self::word_sub_unary_assign::, a, b, CHUNK); } #[inline(always)] fn vec_neg_unary_assign(&self, a: &mut [u64]){ - apply_unary!(self, Self::word_neg_unary_assign::, a, CHUNK); + apply_v!(self, Self::word_neg_unary_assign::, a, CHUNK); } #[inline(always)] fn vec_neg_binary_assign(&self, a: &[u64], b: &mut [u64]){ - apply_binary!(self, Self::word_neg_binary_assign::, a, b, CHUNK); + apply_vv!(self, Self::word_neg_binary_assign::, a, b, CHUNK); } #[inline(always)] fn vec_prepare_montgomery_assign(&self, a: &[u64], b: &mut [Montgomery]){ - apply_binary!(self, Self::word_prepare_montgomery_assign::, a, b, CHUNK); + apply_vv!(self, Self::word_prepare_montgomery_assign::, a, b, CHUNK); } #[inline(always)] fn vec_mul_montgomery_external_binary_assign(&self, a:& [Montgomery], b:&[u64], c: &mut [u64]){ - apply_ternary!(self, Self::word_mul_montgomery_external_binary_assign::, a, b, c, CHUNK); + apply_vvv!(self, Self::word_mul_montgomery_external_binary_assign::, a, b, c, CHUNK); } #[inline(always)] fn vec_mul_montgomery_external_unary_assign(&self, a:& [Montgomery], b:&mut [u64]){ - apply_binary!(self, Self::word_mul_montgomery_external_unary_assign::, a, b, CHUNK); + apply_vv!(self, Self::word_mul_montgomery_external_unary_assign::, a, b, CHUNK); + } + + #[inline(always)] + fn vec_mul_scalar_barrett_external_binary_assign(&self, a:& Barrett, b:&[u64], c: &mut [u64]){ + apply_svv!(self, Self::word_mul_barrett_binary_assign::, a, b, c, CHUNK); + } + + #[inline(always)] + fn vec_mul_scalar_barrett_external_unary_assign(&self, a:& Barrett, b:&mut [u64]){ + apply_sv!(self, Self::word_mul_barrett_unary_assign::, a, b, CHUNK); + } + + fn vec_sum_aqqmb_prod_c_scalar_barrett_assign_d(&self, a: &[u64], b: &[u64], c: &Barrett, d: &mut [u64]){ + apply_vvsv!(self, Self::word_sum_aqqmb_prod_c_barrett_assign_d::, a, b, c, d, CHUNK); } } diff --git a/math/src/poly.rs b/math/src/poly.rs index 83f4f02..d153249 100644 --- a/math/src/poly.rs +++ b/math/src/poly.rs @@ -30,8 +30,12 @@ pub struct PolyRNS(pub Vec>); impl PolyRNSwhere O: Default + Clone, { - pub fn new(n: usize) -> Self{ - Self(vec![Poly::::new(n);n]) + + pub fn new(n: usize, level: usize) -> Self{ + let mut polyrns: PolyRNS = PolyRNS::::default(); + let mut buf: Vec = vec![O::default();polyrns.buffer_size(n, level)]; + polyrns.from_buffer(n, level, &mut buf[..]); + polyrns } pub fn n(&self) -> usize{ @@ -42,8 +46,8 @@ impl PolyRNSwhere self.0.len()-1 } - pub fn buffer_size(&self) -> usize{ - self.n() * (self.level()+1) + pub fn buffer_size(&self, n: usize, level:usize) -> usize{ + n * (level+1) } pub fn from_buffer(&mut self, n: usize, level: usize, buf: &mut [O]){ @@ -55,4 +59,19 @@ impl PolyRNSwhere self.0.push(poly); } } + + pub fn at(&self, level:usize) -> &Poly{ + &self.0[level] + } + + pub fn at_mut(&mut self, level:usize) -> &mut Poly{ + &mut self.0[level] + } +} + +impl Default for PolyRNS{ + fn default() -> Self{ + let polys:Vec> = Vec::new(); + Self{0:polys} + } } \ No newline at end of file diff --git a/math/src/ring.rs b/math/src/ring.rs index 8bb9a1d..4a3de26 100644 --- a/math/src/ring.rs +++ b/math/src/ring.rs @@ -1,6 +1,7 @@ pub mod impl_u64; use crate::modulus::prime::Prime; +use crate::poly::{Poly, PolyRNS}; use crate::dft::DFT; @@ -10,5 +11,45 @@ pub struct Ring{ pub dft:Box>, } +impl Ring{ + pub fn n(&self) -> usize{ + return self.n + } -pub struct RingRNS(pub Vec>); \ No newline at end of file + pub fn new_poly(&self) -> Poly{ + Poly::::new(self.n()) + } +} + + +//pub struct RingRNS<'a, O: Copy>(pub Vec>>); + +pub struct RingRNS<'a, O>(& 'a [Ring]); + +impl RingRNS<'_, O>{ + + pub fn n(&self) -> usize{ + self.0[0].n() + } + + pub fn new_polyrns(&self) -> PolyRNS{ + PolyRNS::::new(self.n(), self.level()) + } + + pub fn max_level(&self) -> usize{ + self.0.len()-1 + } + + pub fn modulus(&self) -> O{ + self.0[LEVEL].modulus.q + } + + pub fn level(&self) -> usize{ + self.0.len()-1 + } + + pub fn at_level(&self, level:usize) -> RingRNS{ + assert!(level <= self.0.len()); + RingRNS(&self.0[..level+1]) + } +} diff --git a/math/src/ring/impl_u64/mod.rs b/math/src/ring/impl_u64/mod.rs index 8e359a7..81c756d 100644 --- a/math/src/ring/impl_u64/mod.rs +++ b/math/src/ring/impl_u64/mod.rs @@ -1,3 +1,4 @@ pub mod automorphism; pub mod ring; -pub mod ring_rns; \ No newline at end of file +pub mod ring_rns; +pub mod rescaling_rns; \ No newline at end of file diff --git a/math/src/ring/impl_u64/rescaling_rns.rs b/math/src/ring/impl_u64/rescaling_rns.rs new file mode 100644 index 0000000..505d225 --- /dev/null +++ b/math/src/ring/impl_u64/rescaling_rns.rs @@ -0,0 +1,56 @@ +use crate::ring::RingRNS; +use crate::poly::PolyRNS; +use crate::modulus::barrett::Barrett; +use crate::modulus::ONCE; +extern crate test; + +impl RingRNS<'_, u64>{ + + /// Updates b to floor(b / q[b.level()]). + /// Expects a and b to be in the NTT domain. + pub fn div_floor_by_last_modulus_ntt(&self, a: &PolyRNS, buf: &mut PolyRNS, b: &mut PolyRNS){ + assert!(b.level() >= a.level()-1, "invalid input b: b.level()={} < a.level()-1={}", b.level(), a.level()-1); + let level = self.level(); + self.0[level].intt::(a.at(level), buf.at_mut(0)); + let rescaling_constants: Vec> = self.rescaling_constant(); + let (buf_ntt_q_scaling, buf_ntt_qi_scaling) = buf.0.split_at_mut(1); + for (i, r) in self.0[0..level].iter().enumerate(){ + r.ntt::(&buf_ntt_q_scaling[0], &mut buf_ntt_qi_scaling[0]); + r.sum_aqqmb_prod_c_scalar_barrett::(&buf_ntt_qi_scaling[0], a.at(i), &rescaling_constants[i], b.at_mut(i)); + } + } + + /// Updates b to floor(b / q[b.level()]). + pub fn div_floor_by_last_modulus(&self, a: &PolyRNS, b: &mut PolyRNS){ + assert!(b.level() >= a.level()-1, "invalid input b: b.level()={} < a.level()-1={}", b.level(), a.level()-1); + let level = self.level(); + let rescaling_constants: Vec> = self.rescaling_constant(); + for (i, r) in self.0[0..level].iter().enumerate(){ + r.sum_aqqmb_prod_c_scalar_barrett::(a.at(level), a.at(i), &rescaling_constants[i], b.at_mut(i)); + } + } +} + + +#[cfg(test)] +mod tests { + use crate::ring::Ring; + use crate::ring::impl_u64::ring_rns::new_rings; + use super::*; + + #[test] + fn test_div_floor_by_last_modulus_ntt() { + let n = 1<<10; + let moduli: Vec = vec![0x1fffffffffe00001u64, 0x1fffffffffc80001u64]; + let rings: Vec> = new_rings(n, moduli); + let ring_rns = RingRNS::new(&rings); + + let a: PolyRNS = ring_rns.new_polyrns(); + let mut b: PolyRNS = ring_rns.new_polyrns(); + let mut c: PolyRNS = ring_rns.new_polyrns(); + + ring_rns.div_floor_by_last_modulus_ntt(&a, &mut b, &mut c); + + //assert!(m_precomp.mul_external::(y_mont, x) == (x as u128 * y as u128 % q as u128) as u64); + } +} \ No newline at end of file diff --git a/math/src/ring/impl_u64/ring.rs b/math/src/ring/impl_u64/ring.rs index 728475f..ed6934d 100644 --- a/math/src/ring/impl_u64/ring.rs +++ b/math/src/ring/impl_u64/ring.rs @@ -2,9 +2,12 @@ use crate::ring::Ring; use crate::dft::ntt::Table; use crate::modulus::prime::Prime; use crate::modulus::montgomery::Montgomery; +use crate::modulus::barrett::Barrett; use crate::poly::Poly; use crate::modulus::REDUCEMOD; use crate::modulus::VecOperations; +use num_bigint::BigInt; +use num_traits::ToPrimitive; use crate::CHUNK; impl Ring{ @@ -17,12 +20,11 @@ impl Ring{ } } - pub fn n(&self) -> usize{ - return self.n - } - - pub fn new_poly(&self) -> Poly{ - Poly::::new(self.n()) + pub fn from_bigint(&self, coeffs: &[BigInt], step:usize, a: &mut Poly){ + assert!(step <= a.n(), "invalid step: step={} > a.n()={}", step, a.n()); + assert!(coeffs.len() <= a.n() / step, "invalid coeffs: coeffs.len()={} > a.n()/step={}", coeffs.len(), a.n()/step); + let q_big: BigInt = BigInt::from(self.modulus.q); + a.0.iter_mut().step_by(step).enumerate().for_each(|(i, v)| *v = (&coeffs[i] % &q_big).to_u64().unwrap()); } } @@ -62,41 +64,79 @@ impl Ring{ #[inline(always)] pub fn add_inplace(&self, a: &Poly, b: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); self.modulus.vec_add_unary_assign::(&a.0, &mut b.0); } #[inline(always)] pub fn add(&self, a: &Poly, b: &Poly, c: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + debug_assert!(c.n() == self.n(), "c.n()={} != n={}", c.n(), self.n()); self.modulus.vec_add_binary_assign::(&a.0, &b.0, &mut c.0); } #[inline(always)] pub fn sub_inplace(&self, a: &Poly, b: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); self.modulus.vec_sub_unary_assign::(&a.0, &mut b.0); } #[inline(always)] pub fn sub(&self, a: &Poly, b: &Poly, c: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + debug_assert!(c.n() == self.n(), "c.n()={} != n={}", c.n(), self.n()); self.modulus.vec_sub_binary_assign::(&a.0, &b.0, &mut c.0); } #[inline(always)] pub fn neg(&self, a: &Poly, b: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); self.modulus.vec_neg_binary_assign::(&a.0, &mut b.0); } #[inline(always)] pub fn neg_inplace(&self, a: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); self.modulus.vec_neg_unary_assign::(&mut a.0); } #[inline(always)] pub fn mul_montgomery_external(&self, a:&Poly>, b:&Poly, c: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + debug_assert!(c.n() == self.n(), "c.n()={} != n={}", c.n(), self.n()); self.modulus.vec_mul_montgomery_external_binary_assign::(&a.0, &b.0, &mut c.0); } #[inline(always)] pub fn mul_montgomery_external_inplace(&self, a:&Poly>, b:&mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); self.modulus.vec_mul_montgomery_external_unary_assign::(&a.0, &mut b.0); } + + #[inline(always)] + pub fn mul_scalar_barrett_inplace(&self, a:&Barrett, b:&mut Poly){ + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + self.modulus.vec_mul_scalar_barrett_external_unary_assign::(a, &mut b.0); + } + + #[inline(always)] + pub fn mul_scalar_barrett(&self, a:&Barrett, b: &Poly, c:&mut Poly){ + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + self.modulus.vec_mul_scalar_barrett_external_binary_assign::(a, &b.0, &mut c.0); + } + + #[inline(always)] + pub fn sum_aqqmb_prod_c_scalar_barrett(&self, a: &Poly, b: &Poly, c: &Barrett, d: &mut Poly){ + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); + debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + debug_assert!(d.n() == self.n(), "d.n()={} != n={}", d.n(), self.n()); + self.modulus.vec_sum_aqqmb_prod_c_scalar_barrett_assign_d::(&a.0, &b.0, c, &mut d.0); + } } \ No newline at end of file diff --git a/math/src/ring/impl_u64/ring_rns.rs b/math/src/ring/impl_u64/ring_rns.rs index 069038a..b4b6339 100644 --- a/math/src/ring/impl_u64/ring_rns.rs +++ b/math/src/ring/impl_u64/ring_rns.rs @@ -1,114 +1,110 @@ use crate::ring::{Ring, RingRNS}; use crate::poly::PolyRNS; use crate::modulus::montgomery::Montgomery; +use crate::modulus::barrett::Barrett; use crate::modulus::REDUCEMOD; +use num_bigint::BigInt; -impl RingRNS{ - pub fn new(n:usize, moduli: Vec) -> Self{ - assert!(!moduli.is_empty(), "moduli cannot be empty"); - let rings: Vec> = moduli - .into_iter() - .map(|prime: u64| Ring::new(n, prime, 1)) - .collect(); +pub fn new_rings(n: usize, moduli: Vec) -> Vec>{ + assert!(!moduli.is_empty(), "moduli cannot be empty"); + let rings: Vec> = moduli + .into_iter() + .map(|prime| Ring::new(n, prime, 1)) + .collect(); + return rings +} + +impl<'a> RingRNS<'a, u64>{ + pub fn new(rings:&'a [Ring]) -> Self{ RingRNS(rings) } - pub fn n(&self) -> usize{ - self.0[0].n() + pub fn rescaling_constant(&self) -> Vec> { + let level = self.level(); + let q_scale: u64 = self.0[level].modulus.q; + (0..level).map(|i| {self.0[i].modulus.barrett.prepare(self.0[i].modulus.q - self.0[i].modulus.inv(q_scale))}).collect() } - pub fn max_level(&self) -> usize{ - self.0.len()-1 + pub fn set_poly_from_bigint(&self, coeffs: &[BigInt], step:usize, a: &mut PolyRNS){ + let level = self.level(); + assert!(level <= a.level(), "invalid level: level={} > a.level()={}", level, a.level()); + (0..level).for_each(|i|{self.0[i].from_bigint(coeffs, step, a.at_mut(i))}); } } -impl RingRNS{ - -} - -impl RingRNS{ +impl RingRNS<'_, u64>{ #[inline(always)] - pub fn add(&self, a: &PolyRNS, b: &PolyRNS, c: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(c.n() >= self.n(), "c.n()={} < n={}", c.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - debug_assert!(c.level() >= LEVEL, "c.level()={} < LEVEL={}", c.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.add::(&a.0[i], &b.0[i], &mut c.0[i])); + pub fn add(&self, a: &PolyRNS, b: &PolyRNS, c: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + debug_assert!(c.level() >= level, "c.level()={} < level={}", c.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.add::(&a.0[i], &b.0[i], &mut c.0[i])); } #[inline(always)] - pub fn add_inplace(&self, a: &PolyRNS, b: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.add_inplace::(&a.0[i], &mut b.0[i])); + pub fn add_inplace(&self, a: &PolyRNS, b: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.add_inplace::(&a.0[i], &mut b.0[i])); } #[inline(always)] - pub fn sub(&self, a: &PolyRNS, b: &PolyRNS, c: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(c.n() >= self.n(), "c.n()={} < n={}", c.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - debug_assert!(c.level() >= LEVEL, "c.level()={} < LEVEL={}", c.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.sub::(&a.0[i], &b.0[i], &mut c.0[i])); + pub fn sub(&self, a: &PolyRNS, b: &PolyRNS, c: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + debug_assert!(c.level() >= level, "c.level()={} < level={}", c.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.sub::(&a.0[i], &b.0[i], &mut c.0[i])); } #[inline(always)] - pub fn sub_inplace(&self, a: &PolyRNS, b: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.sub_inplace::(&a.0[i], &mut b.0[i])); + pub fn sub_inplace(&self, a: &PolyRNS, b: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.sub_inplace::(&a.0[i], &mut b.0[i])); } #[inline(always)] - pub fn neg(&self, a: &PolyRNS, b: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.neg::(&a.0[i], &mut b.0[i])); + pub fn neg(&self, a: &PolyRNS, b: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.neg::(&a.0[i], &mut b.0[i])); } #[inline(always)] - pub fn neg_inplace(&self, a: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.neg_inplace::(&mut a.0[i])); + pub fn neg_inplace(&self, a: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.neg_inplace::(&mut a.0[i])); } #[inline(always)] - pub fn mul_montgomery_external(&self, a:&PolyRNS>, b:&PolyRNS, c: &mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(c.n() >= self.n(), "c.n()={} < n={}", c.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - debug_assert!(c.level() >= LEVEL, "c.level()={} < LEVEL={}", c.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.mul_montgomery_external::(&a.0[i], &b.0[i], &mut c.0[i])); + pub fn mul_montgomery_external(&self, a:&PolyRNS>, b:&PolyRNS, c: &mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + debug_assert!(c.level() >= level, "c.level()={} < level={}", c.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.mul_montgomery_external::(&a.0[i], &b.0[i], &mut c.0[i])); } #[inline(always)] - pub fn mul_montgomery_external_inplace(&self, a:&PolyRNS>, b:&mut PolyRNS){ - debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL); - debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n()); - debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n()); - debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL); - debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL); - self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.mul_montgomery_external_inplace::(&a.0[i], &mut b.0[i])); + pub fn mul_montgomery_external_inplace(&self, a:&PolyRNS>, b:&mut PolyRNS){ + let level: usize = self.level(); + debug_assert!(self.max_level() <= level, "max_level={} < level={}", self.max_level(), level); + debug_assert!(a.level() >= level, "a.level()={} < level={}", a.level(), level); + debug_assert!(b.level() >= level, "b.level()={} < level={}", b.level(), level); + self.0.iter().take(level + 1).enumerate().for_each(|(i, ring)| ring.mul_montgomery_external_inplace::(&a.0[i], &mut b.0[i])); } } \ No newline at end of file