arnaucube
arnaucube/poulpyPublic Self-hosted repository
fixed rounding rescaling
Jean-Philippe Bossuat jeanphilippe.bossuat@gmail.com
Wed, 08 Jan 2025 11:06:56 +0100
commit

bdd57b91ed39fafeb7d977d0798082a6dacc2a23

parent

3db800f4ceed7dbb01058f84523fc99e46d0383b

M Cargo.lock → Cargo.lock

@@ -257,6 +257,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index"

@@ -270,9 +276,11 @@ "criterion",

"itertools 0.14.0", "num", "num-bigint", + "num-integer", "num-traits", "primality-test", "prime_factorization", + "rand_distr", "sampling", ]

@@ -353,6 +361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]]

@@ -467,6 +476,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"

checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", ] [[package]]
M math/Cargo.toml → math/Cargo.toml

@@ -8,9 +8,11 @@ num = "0.4.3"

primality-test = "0.3.0" num-bigint = "0.4.6" num-traits = "0.2.19" +num-integer ="0.1.46" prime_factorization = "1.0.5" itertools = "0.14.0" criterion = "0.5.1" +rand_distr = "0.4.3" sampling = { path = "../sampling" } [[bench]]
M math/benches/ring_rns.rs → math/benches/ring_rns.rs

@@ -8,7 +8,7 @@ let a: PolyRNS<u64> = r.new_polyrns();

let mut b: PolyRNS<u64> = r.new_polyrns(); let mut c: PolyRNS<u64> = r.new_polyrns(); - Box::new(move || r.div_floor_by_last_modulus::<true>(&a, &mut b, &mut c)) + Box::new(move || r.div_by_last_modulus::<false, true>(&a, &mut b, &mut c)) } let mut b: criterion::BenchmarkGroup<'_, criterion::measurement::WallTime> =
M math/src/lib.rs → math/src/lib.rs

@@ -6,6 +6,7 @@ pub mod modulus;

pub mod poly; pub mod ring; pub mod scalar; +pub mod num_bigint; pub const CHUNK: usize = 8;

@@ -393,6 +394,61 @@ }

_ => { izip!($c.iter_mut()).for_each(|c| { $f(&$self, $a, $b, c); + }); + } + } + }; + } + + #[macro_export] + macro_rules! apply_vvssv { + ($self:expr, $f:expr, $a:expr, $b:expr, $c:expr, $d:expr, $e: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!( + $e.len() == n, + "invalid argument e: e.len() = {} != a.len() = {}", + $e.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), + $e.chunks_exact_mut(8) + ) + .for_each(|(a, b, e)| { + $f(&$self, &a[0], &b[0], $c, $d, &mut e[0]); + $f(&$self, &a[1], &b[1], $c, $d, &mut e[1]); + $f(&$self, &a[2], &b[2], $c, $d, &mut e[2]); + $f(&$self, &a[3], &b[3], $c, $d, &mut e[3]); + $f(&$self, &a[4], &b[4], $c, $d, &mut e[4]); + $f(&$self, &a[5], &b[5], $c, $d, &mut e[5]); + $f(&$self, &a[6], &b[6], $c, $d, &mut e[6]); + $f(&$self, &a[7], &b[7], $c, $d, &mut e[7]); + }); + + let m = n - (n & 7); + izip!($a[m..].iter(), $b[m..].iter(), $e[m..].iter_mut()).for_each( + |(a, b, e)| { + $f(&$self, a, b, $c, $d, e); + }, + ); + } + _ => { + izip!($a.iter(), $b.iter(), $e.iter_mut()).for_each(|(a, b, e)| { + $f(&$self, a, b, $c, $d, e); }); } }
M math/src/modulus.rs → math/src/modulus.rs

@@ -79,6 +79,9 @@

// Assigns a - b to b. fn sa_sub_sb_into_sb<const SARANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &O, b: &mut O); + // Assigns a - b to a. + fn sa_sub_sb_into_sa<const SARANGE: u8, const REDUCE: REDUCEMOD>(&self, b: &O, a: &mut O); + // Assigns -a to a. fn sa_neg_into_sa<const SBRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &mut O);

@@ -155,6 +158,24 @@ b: &u64,

c: &barrett::Barrett<u64>, d: &mut u64 ); + + // Assigns (a - b + c) * d to e. + fn sb_sub_sa_add_sc_mul_sd_into_se<const SBRANGE: u8,const REDUCE: REDUCEMOD>( + &self, + a: &u64, + b: &u64, + c: &u64, + d: &barrett::Barrett<u64>, + e: &mut u64 + ); + + fn sb_sub_sa_add_sc_mul_sd_into_sa<const SBRANGE: u8,const REDUCE: REDUCEMOD>( + &self, + b: &u64, + c: &u64, + d: &barrett::Barrett<u64>, + a: &mut u64 + ); } pub trait VectorOperations<O> {

@@ -187,6 +208,9 @@

// vec(b) <- vec(a) - vec(b). fn va_sub_vb_into_vb<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &[O], b: &mut [O]); + // vec(a) <- vec(a) - vec(b). + fn va_sub_vb_into_va<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>(&self, b: &[O], a: &mut [O]); + // vec(c) <- vec(a) - vec(b). fn va_sub_vb_into_vc<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( &self,

@@ -269,6 +293,25 @@ fn va_add_sb_mul_sc_into_va<const CHUNK: usize, const REDUCE: REDUCEMOD>(

&self, sb: &u64, sc: &barrett::Barrett<u64>, + va: &mut [u64], + ); + + // vec(e) <- (vec(b) - vec(a) + scalar(c)) * scalar(e). + fn vb_sub_va_add_sc_mul_sd_into_ve<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + va: &[u64], + vb: &[u64], + sc: &u64, + sd: &barrett::Barrett<u64>, + ve: &mut [u64], + ); + + // vec(a) <- (vec(b) - vec(a) + scalar(c)) * scalar(e). + fn vb_sub_va_add_sc_mul_sd_into_va<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + vb: &[u64], + sc: &u64, + sd: &barrett::Barrett<u64>, va: &mut [u64], ); }
M math/src/modulus/impl_u64/operations.rs → math/src/modulus/impl_u64/operations.rs

@@ -3,7 +3,7 @@ use crate::modulus::montgomery::Montgomery;

use crate::modulus::prime::Prime; use crate::modulus::{REDUCEMOD, NONE}; use crate::modulus::{ScalarOperations, VectorOperations}; -use crate::{apply_sv, apply_svv, apply_v, apply_vsv, apply_vv, apply_vvsv, apply_vvv, apply_ssv, apply_vssv}; +use crate::{apply_sv, apply_svv, apply_v, apply_vsv, apply_vv, apply_vvsv, apply_vvv, apply_ssv, apply_vssv, apply_vvssv}; use itertools::izip; impl ScalarOperations<u64> for Prime<u64> {

@@ -40,6 +40,17 @@ 4 =>{*c = *a + self.four_q - *b}

_ => unreachable!("invalid SBRANGE argument"), } self.sa_reduce_into_sa::<REDUCE>(c) + } + + #[inline(always)] + fn sa_sub_sb_into_sa<const SBRANGE: u8, const REDUCE: REDUCEMOD>(&self, b: &u64, a: &mut u64) { + match SBRANGE{ + 1 =>{*a = *a + self.q - *b} + 2 =>{*a = *a + self.two_q - *b} + 4 =>{*a = *a + self.four_q - *b} + _ => unreachable!("invalid SBRANGE argument"), + } + self.sa_reduce_into_sa::<REDUCE>(a) } #[inline(always)]

@@ -159,6 +170,31 @@ ) {

*a = self.barrett.mul_external::<REDUCE>(*c, *a + *b); } + #[inline(always)] + fn sb_sub_sa_add_sc_mul_sd_into_se<const SBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + a: &u64, + b: &u64, + c: &u64, + d: &Barrett<u64>, + e: &mut u64 + ) { + self.sa_sub_sb_into_sc::<SBRANGE, NONE>(&(b + c), a, e); + self.barrett.mul_external_assign::<REDUCE>(*d, e); + } + + #[inline(always)] + fn sb_sub_sa_add_sc_mul_sd_into_sa<const SBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + b: &u64, + c: &u64, + d: &Barrett<u64>, + a: &mut u64 + ) { + self.sa_sub_sb_into_sb::<SBRANGE, NONE>(&(b + c), a); + self.barrett.mul_external_assign::<REDUCE>(*d, a); + } + } impl VectorOperations<u64> for Prime<u64> {

@@ -223,6 +259,15 @@ apply_vvv!(self, Self::sa_sub_sb_into_sc::<VBRANGE, REDUCE>, a, b, c, CHUNK);

} #[inline(always)] + fn va_sub_vb_into_va<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + b: &[u64], + a: &mut [u64], + ) { + apply_vv!(self, Self::sa_sub_sb_into_sa::<VBRANGE, REDUCE>, b, a, CHUNK); + } + + #[inline(always)] fn va_sub_vb_into_vb<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( &self, a: &[u64],

@@ -365,6 +410,47 @@ a,

b, c, d, + CHUNK + ); + } + + // vec(e) <- (vec(a) - vec(b) + scalar(c)) * scalar(e). + fn vb_sub_va_add_sc_mul_sd_into_ve<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + va: &[u64], + vb: &[u64], + sc: &u64, + sd: &Barrett<u64>, + ve: &mut [u64], + ){ + apply_vvssv!( + self, + Self::sb_sub_sa_add_sc_mul_sd_into_se::<VBRANGE, REDUCE>, + va, + vb, + sc, + sd, + ve, + CHUNK + ); + } + + // vec(a) <- (vec(b) - vec(a) + scalar(c)) * scalar(e). + fn vb_sub_va_add_sc_mul_sd_into_va<const CHUNK: usize, const VBRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + vb: &[u64], + sc: &u64, + sd: &Barrett<u64>, + va: &mut [u64], + ){ + + apply_vssv!( + self, + Self::sb_sub_sa_add_sc_mul_sd_into_sa::<VBRANGE, REDUCE>, + vb, + sc, + sd, + va, CHUNK ); }
A math/src/num_bigint.rs

@@ -0,0 +1,34 @@

+use num_bigint::BigInt; +use num_bigint::Sign; +use num_integer::Integer; +use num_traits::{Zero, One, Signed}; + +pub trait Div{ + fn div_floor(&self, other: &Self) -> Self; + fn div_round(&self, other: &Self) -> Self; +} + +impl Div for BigInt{ + + fn div_floor(&self, other:&Self) -> Self{ + let quo: BigInt = self / other; + if self.sign() == Sign::Minus { + return quo - BigInt::one() + } + return quo + } + + fn div_round(&self, other:&Self) -> Self{ + let (quo, mut rem) = self.div_rem(other); + rem <<= 1; + if rem != BigInt::zero() && &rem.abs() > other{ + if self.sign() == other.sign(){ + return quo + BigInt::one() + }else{ + return quo - BigInt::one() + } + } + return quo + } +} +
M math/src/ring/impl_u64/rescaling_rns.rs → math/src/ring/impl_u64/rescaling_rns.rs

@@ -8,7 +8,7 @@ extern crate test;

impl RingRNS<u64> { /// Updates b to floor(a / q[b.level()]). - pub fn div_floor_by_last_modulus<const NTT: bool>( + pub fn div_by_last_modulus<const ROUND: bool, const NTT: bool>( &self, a: &PolyRNS<u64>, buf: &mut PolyRNS<u64>,

@@ -30,34 +30,76 @@ );

let level = self.level(); let rescaling_constants: ScalarRNS<Barrett<u64>> = self.rescaling_constant(); + let r_last: &Ring<u64> = &self.0[level]; + + if ROUND{ - if NTT { - let (buf_ntt_q_scaling, buf_ntt_qi_scaling) = buf.0.split_at_mut(1); - self.0[level].intt::<false>(a.at(level), &mut buf_ntt_q_scaling[0]); - for (i, r) in self.0[0..level].iter().enumerate() { - r.ntt::<true>(&buf_ntt_q_scaling[0], &mut buf_ntt_qi_scaling[0]); - r.a_sub_b_mul_c_scalar_barrett::<2, ONCE>( - &buf_ntt_qi_scaling[0], - a.at(i), - &rescaling_constants.0[i], - b.at_mut(i), - ); + let q_level_half: u64 = r_last.modulus.q >> 1; + + let (buf_q_scaling, buf_qi_scaling) = buf.0.split_at_mut(1); + + if NTT { + r_last.intt::<false>(a.at(level), &mut buf_q_scaling[0]); + r_last.a_add_b_scalar_into_a::<ONCE>(&q_level_half, &mut buf_q_scaling[0]); + for (i, r) in self.0[0..level].iter().enumerate() { + r_last.a_add_b_scalar_into_c::<NONE>( + &buf_q_scaling[0], + &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), + &mut buf_qi_scaling[0], + ); + r.ntt_inplace::<true>(&mut buf_qi_scaling[0]); + r.a_sub_b_mul_c_scalar_barrett_into_d::<2, ONCE>( + &buf_qi_scaling[0], + a.at(i), + &rescaling_constants.0[i], + b.at_mut(i), + ); + } + } else { + r_last.a_add_b_scalar_into_c::<ONCE>(a.at(self.level()), &q_level_half, &mut buf_q_scaling[0]); + for (i, r) in self.0[0..level].iter().enumerate() { + r_last.a_add_b_scalar_into_c::<NONE>( + &buf_q_scaling[0], + &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), + &mut buf_qi_scaling[0], + ); + r.a_sub_b_mul_c_scalar_barrett_into_d::<2, ONCE>( + &buf_qi_scaling[0], + a.at(i), + &rescaling_constants.0[i], + b.at_mut(i), + ); + } } - } else { - for (i, r) in self.0[0..level].iter().enumerate() { - r.a_sub_b_mul_c_scalar_barrett::<2, ONCE>( - a.at(level), - a.at(i), - &rescaling_constants.0[i], - b.at_mut(i), - ); + }else{ + if NTT { + let (buf_ntt_q_scaling, buf_ntt_qi_scaling) = buf.0.split_at_mut(1); + self.0[level].intt::<false>(a.at(level), &mut buf_ntt_q_scaling[0]); + for (i, r) in self.0[0..level].iter().enumerate() { + r.ntt::<true>(&buf_ntt_q_scaling[0], &mut buf_ntt_qi_scaling[0]); + r.a_sub_b_mul_c_scalar_barrett_into_d::<2, ONCE>( + &buf_ntt_qi_scaling[0], + a.at(i), + &rescaling_constants.0[i], + b.at_mut(i), + ); + } + } else { + for (i, r) in self.0[0..level].iter().enumerate() { + r.a_sub_b_mul_c_scalar_barrett_into_d::<2, ONCE>( + a.at(level), + a.at(i), + &rescaling_constants.0[i], + b.at_mut(i), + ); + } } } } /// Updates a to floor(a / q[b.level()]). /// Expects a to be in the NTT domain. - pub fn div_floor_by_last_modulus_inplace<const NTT: bool>( + pub fn div_by_last_modulus_inplace<const ROUND: bool, const NTT: bool>( &self, buf: &mut PolyRNS<u64>, a: &mut PolyRNS<u64>,

@@ -71,32 +113,70 @@ );

let level = self.level(); let rescaling_constants: ScalarRNS<Barrett<u64>> = self.rescaling_constant(); + let r_last: &Ring<u64> = &self.0[level]; - if NTT { - let (buf_ntt_q_scaling, buf_ntt_qi_scaling) = buf.0.split_at_mut(1); - self.0[level].intt::<false>(a.at(level), &mut buf_ntt_q_scaling[0]); - for (i, r) in self.0[0..level].iter().enumerate() { - r.ntt::<true>(&buf_ntt_q_scaling[0], &mut buf_ntt_qi_scaling[0]); - r.a_sub_b_mul_c_scalar_barrett_inplace::<2, ONCE>( - &buf_ntt_qi_scaling[0], - &rescaling_constants.0[i], - a.at_mut(i), - ); + if ROUND{ + + let q_level_half: u64 = r_last.modulus.q >> 1; + let (buf_q_scaling, buf_qi_scaling) = buf.0.split_at_mut(1); + + if NTT { + r_last.intt::<false>(a.at(level), &mut buf_q_scaling[0]); + r_last.a_add_b_scalar_into_a::<ONCE>(&q_level_half, &mut buf_q_scaling[0]); + for (i, r) in self.0[0..level].iter().enumerate() { + r_last.a_add_b_scalar_into_c::<NONE>( + &buf_q_scaling[0], + &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), + &mut buf_qi_scaling[0], + ); + r.ntt_inplace::<false>(&mut buf_qi_scaling[0]); + r.b_sub_a_mul_c_scalar_barrett_into_a::<2, ONCE>( + &buf_qi_scaling[0], + &rescaling_constants.0[i], + a.at_mut(i), + ); + } + } else { + let (a_qi, a_q_last) = a.0.split_at_mut(self.level()); + r_last.a_add_b_scalar_into_a::<ONCE>(&q_level_half, &mut a_q_last[0]); + for (i, r) in self.0[0..level].iter().enumerate() { + r.b_sub_a_add_c_scalar_mul_d_scalar_barrett_into_a::<1, ONCE>( + &a_q_last[0], + &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), + &rescaling_constants.0[i], + &mut a_qi[i], + ); + } } - } else { - let (a_i, a_level) = a.0.split_at_mut(level); - for (i, r) in self.0[0..level].iter().enumerate() { - r.a_sub_b_mul_c_scalar_barrett_inplace::<2, ONCE>( - &a_level[0], - &rescaling_constants.0[i], - &mut a_i[i], - ); + }else{ + + if NTT { + let (buf_ntt_q_scaling, buf_ntt_qi_scaling) = buf.0.split_at_mut(1); + r_last.intt::<false>(a.at(level), &mut buf_ntt_q_scaling[0]); + for (i, r) in self.0[0..level].iter().enumerate() { + r.ntt::<true>(&buf_ntt_q_scaling[0], &mut buf_ntt_qi_scaling[0]); + r.b_sub_a_mul_c_scalar_barrett_into_a::<2, ONCE>( + &buf_ntt_qi_scaling[0], + &rescaling_constants.0[i], + a.at_mut(i), + ); + } + }else{ + let (a_i, a_level) = a.0.split_at_mut(level); + for (i, r) in self.0[0..level].iter().enumerate() { + r.b_sub_a_mul_c_scalar_barrett_into_a::<2, ONCE>( + &a_level[0], + &rescaling_constants.0[i], + &mut a_i[i], + ); + } } } + } /// Updates b to floor(a / prod_{level - nb_moduli}^{level} q[i]) - pub fn div_floor_by_last_moduli<const NTT: bool>( + pub fn div_by_last_moduli<const ROUND: bool, const NTT: bool>( &self, nb_moduli: usize, a: &PolyRNS<u64>,

@@ -133,38 +213,35 @@ if a != c {

c.copy(a); } } else { - if NTT { + + if NTT{ self.intt::<false>(a, buf); (0..nb_moduli).for_each(|i| { self.at_level(self.level() - i) - .div_floor_by_last_modulus_inplace::<false>( + .div_by_last_modulus_inplace::<ROUND, false>( &mut PolyRNS::<u64>::default(), buf, ) }); self.at_level(self.level() - nb_moduli).ntt::<false>(buf, c); - } else { - - let empty_buf: &mut PolyRNS<u64> = &mut PolyRNS::<u64>::default(); + }else{ + + println!("{} {:?}", self.level(), buf.level()); + self.div_by_last_modulus::<ROUND, false>(a, buf, c); - if nb_moduli == 1{ - self.div_floor_by_last_modulus::<false>(a, empty_buf, c); - }else{ - self.div_floor_by_last_modulus::<false>(a, empty_buf, buf); - } - (1..nb_moduli-1).for_each(|i| { + println!("{} {:?}", self.level() - i, buf.level()); self.at_level(self.level() - i) - .div_floor_by_last_modulus_inplace::<false>(empty_buf, buf); + .div_by_last_modulus_inplace::<ROUND, false>(buf, c); }); - - self.at_level(self.level()-nb_moduli+1).div_floor_by_last_modulus::<false>(buf, empty_buf, c); + + self.at_level(self.level()-nb_moduli+1).div_by_last_modulus_inplace::<ROUND, false>(buf, c); } } } /// Updates a to floor(a / prod_{level - nb_moduli}^{level} q[i]) - pub fn div_floor_by_last_moduli_inplace<const NTT: bool>( + pub fn div_by_last_moduli_inplace<const ROUND:bool, const NTT: bool>( &self, nb_moduli: usize, buf: &mut PolyRNS<u64>,

@@ -185,218 +262,18 @@ );

if nb_moduli == 0{ return } - if NTT { - self.intt::<false>(a, buf); - (0..nb_moduli).for_each(|i| { - self.at_level(self.level() - i) - .div_floor_by_last_modulus_inplace::<false>(&mut PolyRNS::<u64>::default(), buf) - }); - self.at_level(self.level() - nb_moduli+1).ntt::<false>(buf, a); - } else { - (0..nb_moduli).for_each(|i| { - self.at_level(self.level() - i) - .div_floor_by_last_modulus_inplace::<false>(buf, a); - }); - } - } - - /// Updates b to round(a / q[b.level()]). - /// Expects b to be in the NTT domain. - pub fn div_round_by_last_modulus<const NTT: bool>( - &self, - a: &PolyRNS<u64>, - buf: &mut PolyRNS<u64>, - b: &mut PolyRNS<u64>, - ) { - debug_assert!( - self.level() <= a.level(), - "invalid input a: self.level()={} > a.level()={}", - self.level(), - a.level() - ); - debug_assert!( - b.level() >= a.level() - 1, - "invalid input b: b.level()={} < a.level()-1={}", - b.level(), - a.level() - 1 - ); - - let level: usize = self.level(); - let r_last: &Ring<u64> = &self.0[level]; - let q_level_half: u64 = r_last.modulus.q >> 1; - let rescaling_constants: ScalarRNS<Barrett<u64>> = self.rescaling_constant(); - let (buf_q_scaling, buf_qi_scaling) = buf.0.split_at_mut(1); if NTT { - r_last.intt::<false>(a.at(level), &mut buf_q_scaling[0]); - r_last.add_scalar_inplace::<ONCE>(&q_level_half, &mut buf_q_scaling[0]); - for (i, r) in self.0[0..level].iter().enumerate() { - r_last.add_scalar::<NONE>( - &buf_q_scaling[0], - &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), - &mut buf_qi_scaling[0], - ); - r.ntt_inplace::<true>(&mut buf_qi_scaling[0]); - r.a_sub_b_mul_c_scalar_barrett::<2, ONCE>( - &buf_qi_scaling[0], - a.at(i), - &rescaling_constants.0[i], - b.at_mut(i), - ); - } - } else { - r_last.add_scalar_inplace::<ONCE>(&q_level_half, &mut buf_q_scaling[0]); - for (i, r) in self.0[0..level].iter().enumerate() { - r_last.add_scalar::<NONE>( - &buf_q_scaling[0], - &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), - &mut buf_qi_scaling[0], - ); - r.a_sub_b_mul_c_scalar_barrett::<2, ONCE>( - &buf_qi_scaling[0], - a.at(i), - &rescaling_constants.0[i], - b.at_mut(i), - ); - } - } - } - - /// Updates a to round(a / q[b.level()]). - /// Expects a to be in the NTT domain. - pub fn div_round_by_last_modulus_inplace<const NTT: bool>( - &self, - buf: &mut PolyRNS<u64>, - a: &mut PolyRNS<u64>, - ) { - debug_assert!( - self.level() <= a.level(), - "invalid input a: self.level()={} > a.level()={}", - self.level(), - a.level() - ); - - let level = self.level(); - let r_last: &Ring<u64> = &self.0[level]; - let q_level_half: u64 = r_last.modulus.q >> 1; - let rescaling_constants: ScalarRNS<Barrett<u64>> = self.rescaling_constant(); - let (buf_q_scaling, buf_qi_scaling) = buf.0.split_at_mut(1); - - if NTT { - r_last.intt::<false>(a.at(level), &mut buf_q_scaling[0]); - r_last.add_scalar_inplace::<ONCE>(&q_level_half, &mut buf_q_scaling[0]); - for (i, r) in self.0[0..level].iter().enumerate() { - r_last.add_scalar::<NONE>( - &buf_q_scaling[0], - &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), - &mut buf_qi_scaling[0], - ); - r.ntt_inplace::<false>(&mut buf_qi_scaling[0]); - r.a_sub_b_mul_c_scalar_barrett_inplace::<2, ONCE>( - &buf_qi_scaling[0], - &rescaling_constants.0[i], - a.at_mut(i), - ); - } - } else { - r_last.add_scalar_inplace::<ONCE>(&q_level_half, &mut buf_q_scaling[0]); - for (i, r) in self.0[0..level].iter().enumerate() { - r_last.add_scalar::<NONE>( - &buf_q_scaling[0], - &(r.modulus.q - r_last.modulus.barrett.reduce::<BARRETT>(&q_level_half)), - &mut buf_qi_scaling[0], - ); - r.a_sub_b_mul_c_scalar_barrett_inplace::<2, ONCE>( - &buf_qi_scaling[0], - &rescaling_constants.0[i], - a.at_mut(i), - ); - } - } - } - - /// Updates b to round(a / prod_{level - nb_moduli}^{level} q[i]) - pub fn div_round_by_last_moduli<const NTT: bool>( - &self, - nb_moduli: usize, - a: &PolyRNS<u64>, - buf: &mut PolyRNS<u64>, - c: &mut PolyRNS<u64>, - ) { - debug_assert!( - self.level() <= a.level(), - "invalid input a: self.level()={} > a.level()={}", - self.level(), - a.level() - ); - debug_assert!( - c.level() >= a.level() - 1, - "invalid input b: b.level()={} < a.level()-1={}", - c.level(), - a.level() - 1 - ); - debug_assert!( - nb_moduli <= a.level(), - "invalid input nb_moduli: nb_moduli={} > a.level()={}", - nb_moduli, - a.level() - ); - - if nb_moduli == 0 { - if a != c { - c.copy(a); - } - } else { - if NTT { - self.intt::<false>(a, buf); - (0..nb_moduli).for_each(|i| { - self.at_level(self.level() - i) - .div_round_by_last_modulus_inplace::<false>( - &mut PolyRNS::<u64>::default(), - buf, - ) - }); - self.at_level(self.level() - nb_moduli).ntt::<false>(buf, c); - } else { - self.div_round_by_last_modulus::<false>(a, buf, c); - (1..nb_moduli).for_each(|i| { - self.at_level(self.level() - i) - .div_round_by_last_modulus_inplace::<false>(buf, c) - }); - } - } - } - - /// Updates a to round(a / prod_{level - nb_moduli}^{level} q[i]) - pub fn div_round_by_last_moduli_inplace<const NTT: bool>( - &self, - nb_moduli: usize, - buf: &mut PolyRNS<u64>, - a: &mut PolyRNS<u64>, - ) { - debug_assert!( - self.level() <= a.level(), - "invalid input a: self.level()={} > a.level()={}", - self.level(), - a.level() - ); - debug_assert!( - nb_moduli <= a.level(), - "invalid input nb_moduli: nb_moduli={} > a.level()={}", - nb_moduli, - a.level() - ); - if NTT { self.intt::<false>(a, buf); (0..nb_moduli).for_each(|i| { self.at_level(self.level() - i) - .div_round_by_last_modulus_inplace::<false>(&mut PolyRNS::<u64>::default(), buf) + .div_by_last_modulus_inplace::<ROUND, false>(&mut PolyRNS::<u64>::default(), buf) }); self.at_level(self.level() - nb_moduli).ntt::<false>(buf, a); } else { (0..nb_moduli).for_each(|i| { self.at_level(self.level() - i) - .div_round_by_last_modulus_inplace::<false>(buf, a) + .div_by_last_modulus_inplace::<ROUND, false>(buf, a) }); } }
M math/src/ring/impl_u64/ring.rs → math/src/ring/impl_u64/ring.rs

@@ -75,7 +75,7 @@ }

impl Ring<u64> { #[inline(always)] - pub fn add_inplace<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>) { + pub fn a_add_b_into_b<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>) { 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

@@ -83,7 +83,7 @@ .va_add_vb_into_vb::<CHUNK, REDUCE>(&a.0, &mut b.0);

} #[inline(always)] - pub fn add<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &Poly<u64>, c: &mut Poly<u64>) { + pub fn a_add_b_into_c<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &Poly<u64>, c: &mut Poly<u64>) { 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());

@@ -92,13 +92,13 @@ .va_add_vb_into_vc::<CHUNK, REDUCE>(&a.0, &b.0, &mut c.0);

} #[inline(always)] - pub fn add_scalar_inplace<const REDUCE: REDUCEMOD>(&self, b: &u64, a: &mut Poly<u64>) { + pub fn a_add_b_scalar_into_a<const REDUCE: REDUCEMOD>(&self, b: &u64, a: &mut Poly<u64>) { debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); self.modulus.va_add_sb_into_va::<CHUNK, REDUCE>(b, &mut a.0); } #[inline(always)] - pub fn add_scalar<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &u64, c: &mut Poly<u64>) { + pub fn a_add_b_scalar_into_c<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &u64, c: &mut Poly<u64>) { debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); debug_assert!(c.n() == self.n(), "c.n()={} != n={}", c.n(), self.n()); self.modulus

@@ -106,7 +106,7 @@ .va_add_sb_into_vc::<CHUNK, REDUCE>(&a.0, b, &mut c.0);

} #[inline(always)] - pub fn add_scalar_then_mul_scalar_barrett_inplace<const REDUCE: REDUCEMOD>(&self, b: &u64, c: &Barrett<u64>, a: &mut Poly<u64>) { + pub fn a_add_scalar_b_mul_c_scalar_barrett_into_a<const REDUCE: REDUCEMOD>(&self, b: &u64, c: &Barrett<u64>, a: &mut Poly<u64>) { debug_assert!(a.n() == self.n(), "b.n()={} != n={}", a.n(), self.n()); self.modulus.va_add_sb_mul_sc_into_va::<CHUNK, REDUCE>(b, c, &mut a.0); }

@@ -120,7 +120,7 @@ .va_add_sb_mul_sc_into_vd::<CHUNK, REDUCE>(&a.0, b, c, &mut d.0);

} #[inline(always)] - pub fn sub_inplace<const BRANGE:u8, const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>) { + pub fn a_sub_b_into_b<const BRANGE:u8, const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>) { 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

@@ -128,7 +128,15 @@ .va_sub_vb_into_vb::<CHUNK, BRANGE, REDUCE>(&a.0, &mut b.0);

} #[inline(always)] - pub fn sub<const BRANGE:u8, const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &Poly<u64>, c: &mut Poly<u64>) { + pub fn a_sub_b_into_a<const BRANGE:u8, const REDUCE: REDUCEMOD>(&self, b: &Poly<u64>, a: &mut Poly<u64>) { + 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 + .va_sub_vb_into_va::<CHUNK, BRANGE, REDUCE>(&b.0, &mut a.0); + } + + #[inline(always)] + pub fn a_sub_b_into_c<const BRANGE:u8, const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &Poly<u64>, c: &mut Poly<u64>) { 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());

@@ -137,20 +145,20 @@ .va_sub_vb_into_vc::<CHUNK, BRANGE, REDUCE>(&a.0, &b.0, &mut c.0);

} #[inline(always)] - pub fn neg<const ARANGE:u8, const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>) { + pub fn a_neg_into_b<const ARANGE:u8, const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>) { 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.va_neg_into_vb::<CHUNK, ARANGE, REDUCE>(&a.0, &mut b.0); } #[inline(always)] - pub fn neg_inplace<const ARANGE:u8,const REDUCE: REDUCEMOD>(&self, a: &mut Poly<u64>) { + pub fn a_neg_into_a<const ARANGE:u8,const REDUCE: REDUCEMOD>(&self, a: &mut Poly<u64>) { debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); self.modulus.va_neg_into_va::<CHUNK, ARANGE, REDUCE>(&mut a.0); } #[inline(always)] - pub fn mul_montgomery_external<const REDUCE: REDUCEMOD>( + pub fn a_mul_b_montgomery_into_c<const REDUCE: REDUCEMOD>( &self, a: &Poly<Montgomery<u64>>, b: &Poly<u64>,

@@ -164,20 +172,20 @@ .va_mont_mul_vb_into_vc::<CHUNK, REDUCE>(&a.0, &b.0, &mut c.0);

} #[inline(always)] - pub fn mul_montgomery_external_inplace<const REDUCE: REDUCEMOD>( + pub fn a_mul_b_montgomery_into_a<const REDUCE: REDUCEMOD>( &self, - a: &Poly<Montgomery<u64>>, - b: &mut Poly<u64>, + b: &Poly<Montgomery<u64>>, + a: &mut Poly<u64>, ) { 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 - .va_mont_mul_vb_into_vb::<CHUNK, REDUCE>(&a.0, &mut b.0); + .va_mont_mul_vb_into_vb::<CHUNK, REDUCE>(&b.0, &mut a.0); } #[inline(always)] - pub fn mul_scalar<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &u64, c: &mut Poly<u64>) { - debug_assert!(a.n() == self.n(), "b.n()={} != n={}", a.n(), self.n()); + pub fn a_mul_b_scalar_into_c<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &u64, c: &mut Poly<u64>) { + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); debug_assert!(c.n() == self.n(), "c.n()={} != n={}", c.n(), self.n()); self.modulus.sa_barrett_mul_vb_into_vc::<CHUNK, REDUCE>( &self.modulus.barrett.prepare(*b),

@@ -187,30 +195,30 @@ );

} #[inline(always)] - pub fn mul_scalar_inplace<const REDUCE: REDUCEMOD>(&self, a: &u64, b: &mut Poly<u64>) { - debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + pub fn a_mul_b_scalar_into_a<const REDUCE: REDUCEMOD>(&self, b: &u64, a: &mut Poly<u64>) { + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); self.modulus.sa_barrett_mul_vb_into_vb::<CHUNK, REDUCE>( &self .modulus .barrett - .prepare(self.modulus.barrett.reduce::<BARRETT>(a)), - &mut b.0, + .prepare(self.modulus.barrett.reduce::<BARRETT>(b)), + &mut a.0, ); } #[inline(always)] - pub fn mul_scalar_barrett_inplace<const REDUCE: REDUCEMOD>( + pub fn a_mul_b_scalar_barrett_into_a<const REDUCE: REDUCEMOD>( &self, - a: &Barrett<u64>, - b: &mut Poly<u64>, + b: &Barrett<u64>, + a: &mut Poly<u64>, ) { - debug_assert!(b.n() == self.n(), "b.n()={} != n={}", b.n(), self.n()); + debug_assert!(a.n() == self.n(), "a.n()={} != n={}", a.n(), self.n()); self.modulus - .sa_barrett_mul_vb_into_vb::<CHUNK, REDUCE>(a, &mut b.0); + .sa_barrett_mul_vb_into_vb::<CHUNK, REDUCE>(b, &mut a.0); } #[inline(always)] - pub fn mul_scalar_barrett<const REDUCE: REDUCEMOD>( + pub fn a_mul_b_scalar_barrett_into_c<const REDUCE: REDUCEMOD>( &self, a: &Barrett<u64>, b: &Poly<u64>,

@@ -222,7 +230,7 @@ .sa_barrett_mul_vb_into_vc::<CHUNK, REDUCE>(a, &b.0, &mut c.0);

} #[inline(always)] - pub fn a_sub_b_mul_c_scalar_barrett<const VBRANGE: u8, const REDUCE: REDUCEMOD>( + pub fn a_sub_b_mul_c_scalar_barrett_into_d<const VBRANGE: u8, const REDUCE: REDUCEMOD>( &self, a: &Poly<u64>, b: &Poly<u64>,

@@ -237,15 +245,46 @@ .va_sub_vb_mul_sc_into_vd::<CHUNK, VBRANGE, REDUCE>(&a.0, &b.0, c, &mut d.0);

} #[inline(always)] - pub fn a_sub_b_mul_c_scalar_barrett_inplace<const BRANGE: u8, const REDUCE: REDUCEMOD>( + pub fn b_sub_a_mul_c_scalar_barrett_into_a<const BRANGE: u8, const REDUCE: REDUCEMOD>( &self, - a: &Poly<u64>, + b: &Poly<u64>, c: &Barrett<u64>, - b: &mut Poly<u64>, + a: &mut Poly<u64>, ) { 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 - .va_sub_vb_mul_sc_into_vb::<CHUNK, BRANGE, REDUCE>(&a.0, c, &mut b.0); + .va_sub_vb_mul_sc_into_vb::<CHUNK, BRANGE, REDUCE>(&b.0, c, &mut a.0); } + + #[inline(always)] + pub fn a_sub_b_add_c_scalar_mul_d_scalar_barrett_into_e<const BRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + a: &Poly<u64>, + b: &Poly<u64>, + c: &u64, + d: &Barrett<u64>, + e: &mut Poly<u64>, + ){ + 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!(e.n() == self.n(), "e.n()={} != n={}", e.n(), self.n()); + self.modulus + .vb_sub_va_add_sc_mul_sd_into_ve::<CHUNK, BRANGE, REDUCE>(&a.0, &b.0, c, d, &mut e.0); + } + + #[inline(always)] + pub fn b_sub_a_add_c_scalar_mul_d_scalar_barrett_into_a<const BRANGE: u8, const REDUCE: REDUCEMOD>( + &self, + b: &Poly<u64>, + c: &u64, + d: &Barrett<u64>, + a: &mut Poly<u64>, + ){ + 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 + .vb_sub_va_add_sc_mul_sd_into_va::<CHUNK, BRANGE, REDUCE>(&b.0, c, d, &mut a.0); + } + }
M math/src/ring/impl_u64/ring_rns.rs → math/src/ring/impl_u64/ring_rns.rs

@@ -7,6 +7,8 @@ use crate::scalar::ScalarRNS;

use num_bigint::BigInt; use std::sync::Arc; + + impl RingRNS<u64> { pub fn new(n: usize, moduli: Vec<u64>) -> Self { assert!(!moduli.is_empty(), "moduli cannot be empty");

@@ -121,7 +123,7 @@ }

impl RingRNS<u64> { #[inline(always)] - pub fn add<const REDUCE: REDUCEMOD>( + pub fn a_add_b_into_c<const REDUCE: REDUCEMOD>( &self, a: &PolyRNS<u64>, b: &PolyRNS<u64>,

@@ -148,11 +150,11 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.add::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i])); + .for_each(|(i, ring)| ring.a_add_b_into_c::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i])); } #[inline(always)] - pub fn add_inplace<const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>) { + pub fn a_add_b_into_b<const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>) { debug_assert!( a.level() >= self.level(), "a.level()={} < self.level()={}",

@@ -168,11 +170,11 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.add_inplace::<REDUCE>(&a.0[i], &mut b.0[i])); + .for_each(|(i, ring)| ring.a_add_b_into_b::<REDUCE>(&a.0[i], &mut b.0[i])); } #[inline(always)] - pub fn sub<const BRANGE: u8, const REDUCE: REDUCEMOD>( + pub fn a_sub_b_into_c<const BRANGE: u8, const REDUCE: REDUCEMOD>( &self, a: &PolyRNS<u64>, b: &PolyRNS<u64>,

@@ -199,11 +201,31 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.sub::<BRANGE, REDUCE>(&a.0[i], &b.0[i], &mut c.0[i])); + .for_each(|(i, ring)| ring.a_sub_b_into_c::<BRANGE, REDUCE>(&a.0[i], &b.0[i], &mut c.0[i])); + } + + #[inline(always)] + pub fn a_sub_b_into_b<const BRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>) { + debug_assert!( + a.level() >= self.level(), + "a.level()={} < self.level()={}", + a.level(), + self.level() + ); + debug_assert!( + b.level() >= self.level(), + "b.level()={} < self.level()={}", + b.level(), + self.level() + ); + self.0 + .iter() + .enumerate() + .for_each(|(i, ring)| ring.a_sub_b_into_b::<BRANGE, REDUCE>(&a.0[i], &mut b.0[i])); } #[inline(always)] - pub fn sub_inplace<const BRANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>) { + pub fn a_sub_b_into_a<const BRANGE: u8, const REDUCE: REDUCEMOD>(&self, b: &PolyRNS<u64>, a: &mut PolyRNS<u64>) { debug_assert!( a.level() >= self.level(), "a.level()={} < self.level()={}",

@@ -219,11 +241,11 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.sub_inplace::<BRANGE, REDUCE>(&a.0[i], &mut b.0[i])); + .for_each(|(i, ring)| ring.a_sub_b_into_a::<BRANGE, REDUCE>(&b.0[i], &mut a.0[i])); } #[inline(always)] - pub fn neg<const ARANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>) { + pub fn a_neg_into_b<const ARANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>) { debug_assert!( a.level() >= self.level(), "a.level()={} < self.level()={}",

@@ -239,11 +261,11 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.neg::<ARANGE, REDUCE>(&a.0[i], &mut b.0[i])); + .for_each(|(i, ring)| ring.a_neg_into_b::<ARANGE, REDUCE>(&a.0[i], &mut b.0[i])); } #[inline(always)] - pub fn neg_inplace<const ARANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &mut PolyRNS<u64>) { + pub fn a_neg_into_a<const ARANGE: u8, const REDUCE: REDUCEMOD>(&self, a: &mut PolyRNS<u64>) { debug_assert!( a.level() >= self.level(), "a.level()={} < self.level()={}",

@@ -253,7 +275,7 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.neg_inplace::<ARANGE, REDUCE>(&mut a.0[i])); + .for_each(|(i, ring)| ring.a_neg_into_a::<ARANGE, REDUCE>(&mut a.0[i])); } #[inline(always)]

@@ -282,7 +304,7 @@ c.level(),

self.level() ); self.0.iter().enumerate().for_each(|(i, ring)| { - ring.mul_montgomery_external::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i]) + ring.a_mul_b_montgomery_into_c::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i]) }); }

@@ -305,7 +327,7 @@ b.level(),

self.level() ); self.0.iter().enumerate().for_each(|(i, ring)| { - ring.mul_montgomery_external_inplace::<REDUCE>(&a.0[i], &mut b.0[i]) + ring.a_mul_b_montgomery_into_a::<REDUCE>(&a.0[i], &mut b.0[i]) }); }

@@ -331,11 +353,57 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.mul_scalar::<REDUCE>(&a.0[i], b, &mut c.0[i])); + .for_each(|(i, ring)| ring.a_mul_b_scalar_into_c::<REDUCE>(&a.0[i], b, &mut c.0[i])); } #[inline(always)] - pub fn mul_scalar_inplace<const REDUCE: REDUCEMOD>(&self, a: &u64, b: &mut PolyRNS<u64>) { + pub fn mul_scalar_inplace<const REDUCE: REDUCEMOD>(&self, b: &u64, a: &mut PolyRNS<u64>) { + debug_assert!( + a.level() >= self.level(), + "b.level()={} < self.level()={}", + a.level(), + self.level() + ); + self.0 + .iter() + .enumerate() + .for_each(|(i, ring)| ring.a_mul_b_scalar_into_a::<REDUCE>(b, &mut a.0[i])); + } + + #[inline(always)] + pub fn a_sub_b_add_scalar_mul_scalar_barrett_into_e<const BRANGE:u8, const REDUCE:REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &PolyRNS<u64>, c: &u64, d: &Barrett<u64>, e: &mut PolyRNS<u64>){ + debug_assert!( + a.level() >= self.level(), + "a.level()={} < self.level()={}", + a.level(), + self.level() + ); + debug_assert!( + b.level() >= self.level(), + "b.level()={} < self.level()={}", + b.level(), + self.level() + ); + debug_assert!( + e.level() >= self.level(), + "e.level()={} < self.level()={}", + e.level(), + self.level() + ); + self.0 + .iter() + .enumerate() + .for_each(|(i, ring)| ring.a_sub_b_add_c_scalar_mul_d_scalar_barrett_into_e::<BRANGE, REDUCE>(&a.0[i], &b.0[i], c, d, &mut e.0[i])); + } + + #[inline(always)] + pub fn b_sub_a_add_c_scalar_mul_d_scalar_barrett_into_a<const BRANGE:u8, const REDUCE:REDUCEMOD>(&self, b: &PolyRNS<u64>, c: &u64, d: &Barrett<u64>, a: &mut PolyRNS<u64>){ + debug_assert!( + a.level() >= self.level(), + "a.level()={} < self.level()={}", + a.level(), + self.level() + ); debug_assert!( b.level() >= self.level(), "b.level()={} < self.level()={}",

@@ -345,6 +413,6 @@ );

self.0 .iter() .enumerate() - .for_each(|(i, ring)| ring.mul_scalar_inplace::<REDUCE>(a, &mut b.0[i])); + .for_each(|(i, ring)| ring.b_sub_a_add_c_scalar_mul_d_scalar_barrett_into_a::<BRANGE, REDUCE>(&b.0[i], c, d, &mut a.0[i])); } }
M math/src/ring/impl_u64/sampling.rs → math/src/ring/impl_u64/sampling.rs

@@ -1,6 +1,8 @@

use crate::modulus::WordOps; use crate::poly::{Poly, PolyRNS}; use crate::ring::{Ring, RingRNS}; +use num::ToPrimitive; +use rand_distr::{Normal, Distribution}; use sampling::source::Source; impl Ring<u64> {

@@ -10,6 +12,24 @@ let mask: u64 = max.mask();

a.0.iter_mut() .for_each(|a| *a = source.next_u64n(max, mask)); } + + pub fn fill_dist_f64<T: Distribution<f64>>(&self, source: &mut Source, dist: T, bound: f64, a: &mut Poly<u64>) { + let max: u64 = self.modulus.q; + a.0.iter_mut() + .for_each(|a| { + + let mut dist_f64: f64 = dist.sample(source); + + while dist_f64.abs() > bound{ + dist_f64 = dist.sample(source) + } + + let dist_u64: u64 = (dist_f64+0.5).abs().to_u64().unwrap(); + let sign: u64 = dist_f64.to_bits()>>63; + + *a = (dist_u64 * sign) | (max-dist_u64)*(sign^1) + }); + } } impl RingRNS<u64> {

@@ -18,5 +38,22 @@ self.0

.iter() .enumerate() .for_each(|(i, r)| r.fill_uniform(source, a.at_mut(i))); + } + + pub fn fill_dist_f64<T: Distribution<f64>>(&self, source: &mut Source, dist: T, bound: f64, a: &mut PolyRNS<u64>) { + (0..a.n()).for_each(|j|{ + let mut dist_f64: f64 = dist.sample(source); + + while dist_f64.abs() > bound{ + dist_f64 = dist.sample(source) + } + + let dist_u64: u64 = (dist_f64+0.5).abs().to_u64().unwrap(); + let sign: u64 = dist_f64.to_bits()>>63; + + self.0.iter().enumerate().for_each(|(i, r)|{ + a.at_mut(i).0[j] = (dist_u64 * sign) | (r.modulus.q-dist_u64)*(sign^1); + }) + }) } }
M math/tests/rescaling_rns.rs → math/tests/rescaling_rns.rs

@@ -1,8 +1,9 @@

use math::poly::PolyRNS; use math::ring::RingRNS; use num_bigint::BigInt; -use num_bigint::Sign; +use math::num_bigint::Div; use sampling::source::Source; +use itertools::izip; #[test] fn rescaling_rns_u64() {

@@ -10,17 +11,31 @@ let n = 1 << 10;

let moduli: Vec<u64> = vec![0x1fffffffffc80001u64, 0x1fffffffffe00001u64, 0x1fffffffffb40001, 0x1fffffffff500001]; let ring_rns: RingRNS<u64> = RingRNS::new(n, moduli); - test_div_floor_by_last_modulus::<false>(&ring_rns); - test_div_floor_by_last_modulus::<true>(&ring_rns); - test_div_floor_by_last_modulus_inplace::<false>(&ring_rns); - test_div_floor_by_last_modulus_inplace::<true>(&ring_rns); - test_div_floor_by_last_moduli::<false>(&ring_rns); - test_div_floor_by_last_moduli::<true>(&ring_rns); - test_div_floor_by_last_moduli_inplace::<false>(&ring_rns); - test_div_floor_by_last_moduli_inplace::<true>(&ring_rns); + + sub_test("test_div_by_last_modulus::<ROUND:false, NTT:false>", ||{test_div_by_last_modulus::<false, false>(&ring_rns)}); + sub_test("test_div_by_last_modulus::<ROUND:false, NTT:true>", ||{test_div_by_last_modulus::<false, true>(&ring_rns)}); + sub_test("test_div_by_last_modulus::<ROUND:true, NTT:false>", ||{test_div_by_last_modulus::<true, false>(&ring_rns)}); + sub_test("test_div_by_last_modulus::<ROUND:true, NTT:true>", ||{test_div_by_last_modulus::<true, true>(&ring_rns)}); + sub_test("test_div_by_last_modulus_inplace::<ROUND:false, NTT:false>", ||{test_div_by_last_modulus_inplace::<false, false>(&ring_rns)}); + sub_test("test_div_by_last_modulus_inplace::<ROUND:false, NTT:true>", ||{test_div_by_last_modulus_inplace::<false, true>(&ring_rns)}); + sub_test("test_div_by_last_modulus_inplace::<ROUND:true, NTT:true>", ||{test_div_by_last_modulus_inplace::<true, true>(&ring_rns)}); + sub_test("test_div_by_last_modulus_inplace::<ROUND:true, NTT:false>", ||{test_div_by_last_modulus_inplace::<true, false>(&ring_rns)}); + + + + + + + //sub_test("test_div_by_last_moduli::<ROUND:false, NTT:false>", ||{test_div_by_last_moduli::<false, false>(&ring_rns)}); } -fn test_div_floor_by_last_modulus<const NTT: bool>(ring_rns: &RingRNS<u64>) { +fn sub_test<F: FnOnce()>(name: &str, f: F) { + println!("Running {}", name); + f(); +} + +fn test_div_by_last_modulus<const ROUND:bool, const NTT:bool>(ring_rns: &RingRNS<u64>){ + let seed: [u8; 32] = [0; 32]; let mut source: Source = Source::new(seed);

@@ -42,7 +57,8 @@ if NTT {

ring_rns.ntt_inplace::<false>(&mut a); } - ring_rns.div_floor_by_last_modulus::<NTT>(&a, &mut b, &mut c); + ring_rns.div_by_last_modulus::<ROUND,NTT>(&a, &mut b, &mut c); + if NTT { ring_rns.at_level(c.level()).intt_inplace::<false>(&mut c);

@@ -57,22 +73,23 @@

// Performs floor division on a let scalar_big = BigInt::from(ring_rns.0[ring_rns.level()].modulus.q); coeffs_a.iter_mut().for_each(|a| { - // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1] - *a /= &scalar_big; - if a.sign() == Sign::Minus { - *a -= 1; - } + if ROUND{ + *a = a.div_round(&scalar_big); + }else{ + *a = a.div_floor(&scalar_big); + } }); - assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_modulus"); + izip!(coeffs_a, coeffs_c).for_each(|(a, b)| assert_eq!(a, b)); } -fn test_div_floor_by_last_modulus_inplace<const NTT: bool>(ring_rns: &RingRNS<u64>) { +fn test_div_by_last_modulus_inplace<const ROUND:bool, const NTT:bool>(ring_rns: &RingRNS<u64>) { + let seed: [u8; 32] = [0; 32]; let mut source: Source = Source::new(seed); let mut a: PolyRNS<u64> = ring_rns.new_polyrns(); - let mut b: PolyRNS<u64> = ring_rns.new_polyrns(); + let mut buf: PolyRNS<u64> = ring_rns.new_polyrns(); // Allocates a random PolyRNS ring_rns.fill_uniform(&mut source, &mut a);

@@ -88,7 +105,7 @@ if NTT {

ring_rns.ntt_inplace::<false>(&mut a); } - ring_rns.div_floor_by_last_modulus_inplace::<NTT>(&mut b, &mut a); + ring_rns.div_by_last_modulus_inplace::<ROUND,NTT>(&mut buf, &mut a); if NTT { ring_rns.at_level(a.level()-1).intt_inplace::<false>(&mut a);

@@ -103,24 +120,26 @@

// Performs floor division on a let scalar_big = BigInt::from(ring_rns.0[ring_rns.level()].modulus.q); coeffs_a.iter_mut().for_each(|a| { - // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1] - *a /= &scalar_big; - if a.sign() == Sign::Minus { - *a -= 1; - } + if ROUND{ + *a = a.div_round(&scalar_big); + }else{ + *a = a.div_floor(&scalar_big); + } }); - assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_modulus_inplace"); + izip!(coeffs_a, coeffs_c).for_each(|(a, b)| assert_eq!(a, b)); } -fn test_div_floor_by_last_moduli<const NTT: bool>(ring_rns: &RingRNS<u64>) { + +fn test_div_by_last_moduli<const ROUND:bool, const NTT:bool>(ring_rns: &RingRNS<u64>){ + let seed: [u8; 32] = [0; 32]; let mut source: Source = Source::new(seed); let nb_moduli: usize = ring_rns.level(); let mut a: PolyRNS<u64> = ring_rns.new_polyrns(); - let mut b: PolyRNS<u64> = ring_rns.new_polyrns(); + let mut buf: PolyRNS<u64> = ring_rns.new_polyrns(); let mut c: PolyRNS<u64> = ring_rns.at_level(ring_rns.level() - nb_moduli).new_polyrns(); // Allocates a random PolyRNS

@@ -137,14 +156,14 @@ if NTT {

ring_rns.ntt_inplace::<false>(&mut a); } - ring_rns.div_floor_by_last_moduli::<NTT>(nb_moduli, &a, &mut b, &mut c); + ring_rns.div_by_last_moduli::<ROUND,NTT>(nb_moduli, &a, &mut buf, &mut c); if NTT { ring_rns.at_level(c.level()).intt_inplace::<false>(&mut c); } // Exports c to coeffs_c - let mut coeffs_c = vec![BigInt::from(0); c.n()]; + let mut coeffs_c = vec![BigInt::from(0); a.n()]; ring_rns .at_level(c.level()) .to_bigint_inplace(&c, 1, &mut coeffs_c);

@@ -152,18 +171,18 @@

// Performs floor division on a let mut scalar_big = BigInt::from(1); (0..nb_moduli).for_each(|i|{scalar_big *= BigInt::from(ring_rns.0[ring_rns.level()-i].modulus.q)}); - coeffs_a.iter_mut().for_each(|a| { - // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1] - *a /= &scalar_big; - if a.sign() == Sign::Minus { - *a -= 1; - } + if ROUND{ + *a = a.div_round(&scalar_big); + }else{ + *a = a.div_floor(&scalar_big); + } }); - assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_moduli"); + izip!(coeffs_a, coeffs_c).for_each(|(a, b)| assert_eq!(a, b)); } +/* fn test_div_floor_by_last_moduli_inplace<const NTT: bool>(ring_rns: &RingRNS<u64>) { let seed: [u8; 32] = [0; 32]; let mut source: Source = Source::new(seed);

@@ -202,13 +221,8 @@

// Performs floor division on a let mut scalar_big = BigInt::from(1); (0..nb_moduli).for_each(|i|{scalar_big *= BigInt::from(ring_rns.0[ring_rns.level()-i].modulus.q)}); - coeffs_a.iter_mut().for_each(|a| { - // Emulates floor division in [0, q-1] and maps to [-(q-1)/2, (q-1)/2-1] - *a /= &scalar_big; - if a.sign() == Sign::Minus { - *a -= 1; - } - }); + coeffs_a.iter_mut().for_each(|a| {a.div_floor(&scalar_big)}); assert!(coeffs_a == coeffs_c, "test_div_floor_by_last_moduli_inplace"); -}+} +*/
M sampling/src/source.rs → sampling/src/source.rs

@@ -22,11 +22,6 @@ seed

} #[inline(always)] - pub fn next_u64(&mut self) -> u64 { - self.source.next_u64() - } - - #[inline(always)] pub fn next_u64n(&mut self, max: u64, mask: u64) -> u64 { let mut x: u64 = self.next_u64() & mask; while x >= max {

@@ -39,9 +34,26 @@ #[inline(always)]

pub fn next_f64(&mut self, min: f64, max: f64) -> f64 { min + ((self.next_u64() << 11 >> 11) as f64) / MAXF64 * (max - min) } +} +impl RngCore for Source{ #[inline(always)] - pub fn fill_bytes(&mut self, bytes: &mut [u8]) { + fn next_u32(&mut self) -> u32 { + self.source.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.source.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, bytes: &mut [u8]) { self.source.fill_bytes(bytes) } -} + + #[inline(always)] + fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), rand_core::Error>{ + self.source.try_fill_bytes(bytes) + } +}