arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/math/src/ring/impl_u64/automorphism.rs
math/src/ring/impl_u64/automorphism.rsRaw
 1use crate::modulus::WordOps;
 2use crate::poly::Poly;
 3use crate::ring::Ring;
 4
 5/// Returns a lookup table for the automorphism X^{i} -> X^{i * k mod nth_root}.
 6/// Method will panic if n or nth_root are not power-of-two.
 7/// Method will panic if gal_el is not coprime with nth_root.
 8pub fn automorphism_index_ntt(n: usize, nth_root: u64, gal_el: u64) -> Vec<u64> {
 9    assert!(n & (n - 1) != 0, "invalid n={}: not a power-of-two", n);
10    assert!(
11        nth_root & (nth_root - 1) != 0,
12        "invalid nth_root={}: not a power-of-two",
13        n
14    );
15    assert!(
16        gal_el & 1 == 1,
17        "invalid gal_el={}: not coprime with nth_root={}",
18        gal_el,
19        nth_root
20    );
21
22    let mask = nth_root - 1;
23    let log_nth_root: u32 = nth_root.log2() as u32;
24    let mut index: Vec<u64> = Vec::with_capacity(n);
25    for i in 0..n {
26        let i_rev: usize = 2 * i.reverse_bits_msb(log_nth_root) + 1;
27        let gal_el_i: u64 = (gal_el * (i_rev as u64) & mask) >> 1;
28        index.push(gal_el_i.reverse_bits_msb(log_nth_root));
29    }
30    index
31}
32
33impl Ring<u64> {
34    pub fn automorphism(&self, a: Poly<u64>, gal_el: u64, b: &mut Poly<u64>) {
35        debug_assert!(
36            a.n() == b.n(),
37            "invalid inputs: a.n() = {} != b.n() = {}",
38            a.n(),
39            b.n()
40        );
41        debug_assert!(gal_el & 1 == 1, "invalid gal_el = {}: not odd", gal_el);
42
43        let n: usize = a.n();
44        let mask: u64 = (n - 1) as u64;
45        let log_n: usize = n.log2();
46        let q: u64 = self.modulus.q();
47        let b_vec: &mut _ = &mut b.0;
48        let a_vec: &_ = &a.0;
49
50        a_vec.iter().enumerate().for_each(|(i, ai)| {
51            let gal_el_i: u64 = i as u64 * gal_el;
52            let sign: u64 = (gal_el_i >> log_n) & 1;
53            let i_out: u64 = gal_el_i & mask;
54            b_vec[i_out as usize] = ai * (sign ^ 1) | (q - ai) * sign
55        });
56    }
57}