added Map based on FnvHashMap, and AutoPermMap, generalized gal_el

This commit is contained in:
Jean-Philippe Bossuat
2025-01-16 16:08:22 +01:00
parent 7c8f2f3a63
commit 7c654d2464
10 changed files with 111 additions and 45 deletions

View File

@@ -16,6 +16,7 @@ rand_distr = "0.4.3"
sprs = "0.11.2"
sampling = { path = "../sampling" }
utils = { path = "../utils" }
[[bench]]
name = "ntt"

View File

@@ -1,4 +1,29 @@
use crate::modulus::WordOps;
use crate::ring::Ring;
use num::Unsigned;
use utils::map::Map;
pub struct AutoPermMap(Map<usize, AutoPerm>);
impl AutoPermMap {
pub fn new() -> Self {
Self {
0: Map::<usize, AutoPerm>::new(),
}
}
pub fn insert(&mut self, perm: AutoPerm) {
self.0.insert(perm.gal_el, perm);
}
pub fn gen<O: Unsigned, const NTT: bool>(&mut self, ring: &Ring<O>, gen_1: usize, gen_2: bool) {
self.insert(AutoPerm::new::<O, NTT>(ring, gen_1, gen_2))
}
pub fn get(&self, gal_el: &usize) -> Option<&AutoPerm> {
self.0.get(gal_el)
}
}
pub struct AutoPerm {
pub gal_el: usize,
@@ -9,29 +34,21 @@ impl AutoPerm {
/// Returns a lookup table for the automorphism X^{i} -> X^{i * k mod nth_root}.
/// Method will panic if n or nth_root are not power-of-two.
/// Method will panic if gal_el is not coprime with nth_root.
pub fn new<const NTT: bool>(n: usize, gal_el: usize, nth_root: usize) -> Self {
assert!(n & (n - 1) == 0, "invalid n={}: not a power-of-two", n);
assert!(
nth_root & (nth_root - 1) == 0,
"invalid nth_root={}: not a power-of-two",
n
);
assert!(
gal_el & 1 == 1,
"invalid gal_el={}: not coprime with nth_root={}",
gal_el,
nth_root
);
pub fn new<O: Unsigned, const NTT: bool>(ring: &Ring<O>, gen_1: usize, gen_2: bool) -> Self {
let n = ring.n();
let cyclotomic_order = ring.cyclotomic_order();
let gal_el = ring.galois_element(gen_1, gen_2);
let mut permutation: Vec<usize> = Vec::with_capacity(n);
if NTT {
let mask = nth_root - 1;
let log_nth_root_half: u32 = nth_root.log2() as u32 - 1;
let mask = cyclotomic_order - 1;
let log_cyclotomic_order_half: u32 = cyclotomic_order.log2() as u32 - 1;
for i in 0..n {
let i_rev: usize = 2 * i.reverse_bits_msb(log_nth_root_half) + 1;
let i_rev: usize = 2 * i.reverse_bits_msb(log_cyclotomic_order_half) + 1;
let gal_el_i: usize = ((gal_el * i_rev) & mask) >> 1;
permutation.push(gal_el_i.reverse_bits_msb(log_nth_root_half));
permutation.push(gal_el_i.reverse_bits_msb(log_cyclotomic_order_half));
}
} else {
let log_n: usize = n.log2();

View File

@@ -1,15 +1,16 @@
pub mod impl_u64;
use crate::dft::DFT;
use crate::modulus::prime::Prime;
use crate::modulus::WordOps;
use crate::poly::{Poly, PolyRNS};
use crate::GALOISGENERATOR;
use num::traits::Unsigned;
use std::rc::Rc;
pub struct Ring<O: Unsigned> {
pub n: usize,
pub modulus: Prime<O>,
pub cyclotomic_order: usize,
pub dft: Box<dyn DFT<O>>,
}
@@ -25,6 +26,33 @@ impl<O: Unsigned> Ring<O> {
pub fn new_poly(&self) -> Poly<u64> {
Poly::<u64>::new(self.n())
}
pub fn cyclotomic_order(&self) -> usize {
self.cyclotomic_order
}
// Returns GALOISGENERATOR^gen_1 * (-1)^gen_2 mod 2^log_nth_root.
pub fn galois_element(&self, gen_1: usize, gen_2: bool) -> usize {
let mut gal_el: usize = 1;
let mut gen_1_pow: usize = GALOISGENERATOR;
let mut e: usize = gen_1;
while e > 0 {
if e & 1 == 1 {
gal_el = gal_el.wrapping_mul(gen_1_pow);
}
gen_1_pow = gen_1_pow.wrapping_mul(gen_1_pow);
e >>= 1;
}
let nth_root = 1 << self.cyclotomic_order;
gal_el &= nth_root - 1;
if gen_2 {
return nth_root - gal_el;
}
gal_el
}
}
pub struct RingRNS<O: Unsigned>(pub Vec<Rc<Ring<O>>>);

View File

@@ -7,7 +7,6 @@ use crate::modulus::{BARRETT, REDUCEMOD};
use crate::poly::Poly;
use crate::ring::Ring;
use crate::CHUNK;
use crate::GALOISGENERATOR;
use num_bigint::BigInt;
use num_traits::ToPrimitive;
@@ -17,6 +16,7 @@ impl Ring<u64> {
Self {
n: n,
modulus: prime.clone(),
cyclotomic_order: n << 1,
dft: Box::new(Table::<u64>::new(prime, n << 1)),
}
}
@@ -40,29 +40,6 @@ impl Ring<u64> {
.enumerate()
.for_each(|(i, v)| *v = (&coeffs[i] % &q_big).to_u64().unwrap());
}
// Returns GALOISGENERATOR^gen_1 * (-1)^gen_2 mod 2^log_nth_root.
pub fn galois_element(&self, gen_1: usize, gen_2: bool, log_nth_root: usize) -> usize {
let mut gal_el: usize = 1;
let mut gen_1_pow: usize = GALOISGENERATOR;
let mut e: usize = gen_1;
while e > 0 {
if e & 1 == 1 {
gal_el = gal_el.wrapping_mul(gen_1_pow);
}
gen_1_pow = gen_1_pow.wrapping_mul(gen_1_pow);
e >>= 1;
}
let nth_root = 1 << log_nth_root;
gal_el &= nth_root - 1;
if gen_2 {
return nth_root - gal_el;
}
gal_el
}
}
impl Ring<u64> {

View File

@@ -77,9 +77,10 @@ fn test_automorphism_from_perm_u64<const NTT: bool>(ring: &Ring<u64>, nth_root:
ring.ntt_inplace::<false>(&mut p0);
}
let gal_el: usize = 2 * nth_root - 1;
let gen_1 = 0;
let gen_2 = true;
let auto_perm = AutoPerm::new::<NTT>(n, gal_el, nth_root);
let auto_perm = AutoPerm::new::<_, NTT>(&ring, gen_1, gen_2);
ring.a_apply_automorphism_from_perm_into_b::<NTT>(&p0, &auto_perm, &mut p1);