use std::collections::HashMap; use crate::poly::Poly; use crate::ring::Ring; use crate::modulus::{ONCE, WordOps}; use crate::modulus::barrett::Barrett; use std::cmp::min; use std::mem::transmute; impl Ring{ // Generates a vector storing {X^{2^0}, X^{2^1}, .., X^{2^log_n}}. pub fn gen_x_pow_2(&self, log_n: usize) -> Vec>{ let mut x_pow: Vec> = Vec::>::with_capacity(log_n); (0..log_n).for_each(|i|{ let mut idx: usize = 1<(&mut x_pow[i]); }else{ let (left, right) = x_pow.split_at_mut(i); self.a_mul_b_montgomery_into_c::(&left[i-1], &left[i-1], &mut right[0]); } }); if INV{ self.a_neg_into_a::<1, ONCE>(&mut x_pow[0]); } if !NTT{ x_pow.iter_mut().for_each(|x| self.intt_inplace::(x)); } x_pow } pub fn pack<'a, const ZEROGARBAGE: bool, const NTT: bool>(&self, polys: &'a mut HashMap>, log_gap: usize) -> &'a Poly{ let log_n: usize = self.log_n(); let log_nth_root: usize = log_n+1; let nth_root: usize = 1< = polys.keys().copied().collect(); keys.sort(); let mut gap = 0usize; if keys.len() > 1{ gap = max_pow2_gap(&keys); }else{ gap = 1< 0 { log_end -= log_gap; } } let n_inv: Barrett = self.modulus.barrett.prepare(self.modulus.inv(1<<(log_end - log_start))); for (_, poly) in polys.iter_mut() { if !NTT{ self.ntt_inplace::(poly); } self.a_mul_b_scalar_barrett_into_a::(&n_inv, poly); } let x_pow2: Vec> = self.gen_x_pow_2::(log_n); let mut tmpa: Poly = self.new_poly(); let mut tmpb: Poly = self.new_poly(); for i in log_start..log_end{ let t: usize = 1<<(log_n-1-i); for j in 0..t{ let option_lo: Option<&&mut Poly> = polys.get(&i); let option_hi: Option<&&mut Poly> = polys.get(&(i+t)); let mut hi_exists: bool = false; match option_hi{ Some(hi) =>{ // Unsafe code is necessary because two mutables references are // accessed from the map. unsafe{ self.a_mul_b_montgomery_into_a::(&x_pow2[log_n-i-1], transmute(*hi as *const Poly as *mut Poly)); } hi_exists = true; match option_lo{ Some(lo) =>{ self.a_sub_b_into_c::<1, ONCE>(lo, hi, &mut tmpa); // Ensures unsafe blocks are "safe". let ptr_hi: *mut Poly = *hi as *const Poly as *mut Poly; let ptr_lo: *mut Poly = *lo as *const Poly as *mut Poly; assert!(ptr_hi != ptr_lo, "something went seriously wrong"); unsafe{ self.a_add_b_into_b::(hi, transmute(ptr_lo)); } } None =>{ unsafe{ polys.insert(j, transmute(*hi as *const Poly as *mut Poly)); } }, } polys.remove(&(j+t)); } None =>{}, } let option_lo: Option<&&mut Poly> = polys.get(&i); let option_hi: Option<&&mut Poly> = polys.get(&(i+t)); match option_lo{ Some(lo) =>{ let gal_el: usize = self.galois_element(1<<(i-1), i == 0, log_nth_root); if hi_exists{ self.automorphism::(&tmpa, gal_el, 2<(*lo, gal_el, nth_root, &mut tmpa); } unsafe{ self.a_add_b_into_b::(&tmpa, transmute(*lo as *const Poly as *mut Poly)); } } None =>{ match option_hi{ Some(hi) =>{ let gal_el: usize = self.galois_element(1<<(i-1), i == 0, log_nth_root); self.automorphism::(*hi, gal_el, nth_root, &mut tmpa); unsafe{ self.a_sub_b_into_a::<1, ONCE>(&tmpa, transmute(*hi as *const Poly as *mut Poly)) } } None =>{} } } } } } *polys.get(&0).unwrap() } } // Returns the largest fn max_pow2_gap(vec: &[usize]) -> usize{ let mut gap: usize = usize::MAX; for i in 1..vec.len(){ let (l, r) = (vec[i-1], vec[i]); assert!(l > r, "invalid input vec: not sorted"); gap = min(gap, r-l); if gap == 1{ break; } }; 1 << gap.trailing_zeros() }