arnaucube
arnaucube/poulpyPublic Self-hosted repository
poulpy/math/src/automorphism.rs
math/src/automorphism.rsRaw
 1use crate::modulus::WordOps;
 2
 3pub struct AutomorphismPermutation {
 4    pub gal_el: usize,
 5    pub permutation: Vec<usize>,
 6}
 7
 8impl AutomorphismPermutation {
 9    /// Returns a lookup table for the automorphism X^{i} -> X^{i * k mod nth_root}.
10    /// Method will panic if n or nth_root are not power-of-two.
11    /// Method will panic if gal_el is not coprime with nth_root.
12    pub fn new<const NTT: bool>(n: usize, gal_el: usize, nth_root: usize) -> Self {
13        assert!(n & (n - 1) == 0, "invalid n={}: not a power-of-two", n);
14        assert!(
15            nth_root & (nth_root - 1) == 0,
16            "invalid nth_root={}: not a power-of-two",
17            n
18        );
19        assert!(
20            gal_el & 1 == 1,
21            "invalid gal_el={}: not coprime with nth_root={}",
22            gal_el,
23            nth_root
24        );
25
26        let mut permutation: Vec<usize> = Vec::with_capacity(n);
27
28        if NTT {
29            let mask = nth_root - 1;
30            let log_nth_root_half: u32 = nth_root.log2() as u32 - 1;
31            for i in 0..n {
32                let i_rev: usize = 2 * i.reverse_bits_msb(log_nth_root_half) + 1;
33                let gal_el_i: usize = ((gal_el * i_rev) & mask) >> 1;
34                permutation.push(gal_el_i.reverse_bits_msb(log_nth_root_half));
35            }
36        } else {
37            let log_n: usize = n.log2();
38            let mask: usize = (n - 1) as usize;
39            for i in 0..n {
40                let gal_el_i: usize = i as usize * gal_el;
41                let sign: usize = (gal_el_i >> log_n) & 1;
42                let i_out: usize = (gal_el_i & mask) | (sign << (usize::BITS - 1));
43                permutation.push(i_out)
44            }
45        }
46
47        Self {
48            gal_el: gal_el,
49            permutation: permutation,
50        }
51    }
52}