diff --git a/Cargo.lock b/Cargo.lock index b729521..1f71ab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,6 +198,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "getrandom" version = "0.2.15" @@ -309,6 +315,7 @@ dependencies = [ "rand_distr", "sampling", "sprs", + "utils", ] [[package]] @@ -733,6 +740,13 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "utils" +version = "0.1.0" +dependencies = [ + "fnv", +] + [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 634efaf..c13f7e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["math", "sampling"] +members = ["math", "sampling", "utils"] diff --git a/math/Cargo.toml b/math/Cargo.toml index 7a90af4..90a5161 100644 --- a/math/Cargo.toml +++ b/math/Cargo.toml @@ -16,6 +16,7 @@ rand_distr = "0.4.3" sprs = "0.11.2" sampling = { path = "../sampling" } +utils = { path = "../utils" } [[bench]] name = "ntt" diff --git a/math/src/automorphism.rs b/math/src/automorphism.rs index 6f985ff..417d46a 100644 --- a/math/src/automorphism.rs +++ b/math/src/automorphism.rs @@ -1,4 +1,29 @@ use crate::modulus::WordOps; +use crate::ring::Ring; +use num::Unsigned; +use utils::map::Map; + +pub struct AutoPermMap(Map); + +impl AutoPermMap { + pub fn new() -> Self { + Self { + 0: Map::::new(), + } + } + + pub fn insert(&mut self, perm: AutoPerm) { + self.0.insert(perm.gal_el, perm); + } + + pub fn gen(&mut self, ring: &Ring, gen_1: usize, gen_2: bool) { + self.insert(AutoPerm::new::(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(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(ring: &Ring, 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 = 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(); diff --git a/math/src/ring.rs b/math/src/ring.rs index 62dfb01..1387c9a 100644 --- a/math/src/ring.rs +++ b/math/src/ring.rs @@ -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 { pub n: usize, pub modulus: Prime, + pub cyclotomic_order: usize, pub dft: Box>, } @@ -25,6 +26,33 @@ impl Ring { pub fn new_poly(&self) -> Poly { Poly::::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(pub Vec>>); diff --git a/math/src/ring/impl_u64/ring.rs b/math/src/ring/impl_u64/ring.rs index 2f090e3..adc55af 100644 --- a/math/src/ring/impl_u64/ring.rs +++ b/math/src/ring/impl_u64/ring.rs @@ -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 { Self { n: n, modulus: prime.clone(), + cyclotomic_order: n << 1, dft: Box::new(Table::::new(prime, n << 1)), } } @@ -40,29 +40,6 @@ impl Ring { .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 { diff --git a/math/tests/automorphism.rs b/math/tests/automorphism.rs index 0adb306..ec7f7f2 100644 --- a/math/tests/automorphism.rs +++ b/math/tests/automorphism.rs @@ -77,9 +77,10 @@ fn test_automorphism_from_perm_u64(ring: &Ring, nth_root: ring.ntt_inplace::(&mut p0); } - let gal_el: usize = 2 * nth_root - 1; + let gen_1 = 0; + let gen_2 = true; - let auto_perm = AutoPerm::new::(n, gal_el, nth_root); + let auto_perm = AutoPerm::new::<_, NTT>(&ring, gen_1, gen_2); ring.a_apply_automorphism_from_perm_into_b::(&p0, &auto_perm, &mut p1); diff --git a/utils/Cargo.toml b/utils/Cargo.toml new file mode 100644 index 0000000..5f23bb6 --- /dev/null +++ b/utils/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "utils" +version = "0.1.0" +edition = "2021" + +[dependencies] +fnv = "1.0.7" \ No newline at end of file diff --git a/utils/src/lib.rs b/utils/src/lib.rs new file mode 100644 index 0000000..1d7f53b --- /dev/null +++ b/utils/src/lib.rs @@ -0,0 +1 @@ +pub mod map; diff --git a/utils/src/map.rs b/utils/src/map.rs new file mode 100644 index 0000000..9709ada --- /dev/null +++ b/utils/src/map.rs @@ -0,0 +1,20 @@ +use fnv::FnvHashMap; +use std::hash::Hash; + +pub struct Map(pub FnvHashMap); + +impl Map { + pub fn new() -> Self { + Self { + 0: FnvHashMap::::default(), + } + } + + pub fn insert(&mut self, k: K, data: V) -> Option { + self.0.insert(k, data) + } + + pub fn get(&self, k: &K) -> Option<&V> { + self.0.get(k) + } +}