mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 05:06:44 +01:00
added Map based on FnvHashMap, and AutoPermMap, generalized gal_el
This commit is contained in:
14
Cargo.lock
generated
14
Cargo.lock
generated
@@ -198,6 +198,12 @@ version = "1.13.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -309,6 +315,7 @@ dependencies = [
|
|||||||
"rand_distr",
|
"rand_distr",
|
||||||
"sampling",
|
"sampling",
|
||||||
"sprs",
|
"sprs",
|
||||||
|
"utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -733,6 +740,13 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["math", "sampling"]
|
members = ["math", "sampling", "utils"]
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ rand_distr = "0.4.3"
|
|||||||
sprs = "0.11.2"
|
sprs = "0.11.2"
|
||||||
|
|
||||||
sampling = { path = "../sampling" }
|
sampling = { path = "../sampling" }
|
||||||
|
utils = { path = "../utils" }
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "ntt"
|
name = "ntt"
|
||||||
|
|||||||
@@ -1,4 +1,29 @@
|
|||||||
use crate::modulus::WordOps;
|
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 struct AutoPerm {
|
||||||
pub gal_el: usize,
|
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}.
|
/// 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 n or nth_root are not power-of-two.
|
||||||
/// Method will panic if gal_el is not coprime with nth_root.
|
/// 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 {
|
pub fn new<O: Unsigned, const NTT: bool>(ring: &Ring<O>, gen_1: usize, gen_2: bool) -> Self {
|
||||||
assert!(n & (n - 1) == 0, "invalid n={}: not a power-of-two", n);
|
let n = ring.n();
|
||||||
assert!(
|
let cyclotomic_order = ring.cyclotomic_order();
|
||||||
nth_root & (nth_root - 1) == 0,
|
|
||||||
"invalid nth_root={}: not a power-of-two",
|
let gal_el = ring.galois_element(gen_1, gen_2);
|
||||||
n
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
gal_el & 1 == 1,
|
|
||||||
"invalid gal_el={}: not coprime with nth_root={}",
|
|
||||||
gal_el,
|
|
||||||
nth_root
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut permutation: Vec<usize> = Vec::with_capacity(n);
|
let mut permutation: Vec<usize> = Vec::with_capacity(n);
|
||||||
|
|
||||||
if NTT {
|
if NTT {
|
||||||
let mask = nth_root - 1;
|
let mask = cyclotomic_order - 1;
|
||||||
let log_nth_root_half: u32 = nth_root.log2() as u32 - 1;
|
let log_cyclotomic_order_half: u32 = cyclotomic_order.log2() as u32 - 1;
|
||||||
for i in 0..n {
|
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;
|
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 {
|
} else {
|
||||||
let log_n: usize = n.log2();
|
let log_n: usize = n.log2();
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
pub mod impl_u64;
|
pub mod impl_u64;
|
||||||
|
|
||||||
use crate::dft::DFT;
|
use crate::dft::DFT;
|
||||||
use crate::modulus::prime::Prime;
|
use crate::modulus::prime::Prime;
|
||||||
use crate::modulus::WordOps;
|
use crate::modulus::WordOps;
|
||||||
use crate::poly::{Poly, PolyRNS};
|
use crate::poly::{Poly, PolyRNS};
|
||||||
|
use crate::GALOISGENERATOR;
|
||||||
use num::traits::Unsigned;
|
use num::traits::Unsigned;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Ring<O: Unsigned> {
|
pub struct Ring<O: Unsigned> {
|
||||||
pub n: usize,
|
pub n: usize,
|
||||||
pub modulus: Prime<O>,
|
pub modulus: Prime<O>,
|
||||||
|
pub cyclotomic_order: usize,
|
||||||
pub dft: Box<dyn DFT<O>>,
|
pub dft: Box<dyn DFT<O>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +26,33 @@ impl<O: Unsigned> Ring<O> {
|
|||||||
pub fn new_poly(&self) -> Poly<u64> {
|
pub fn new_poly(&self) -> Poly<u64> {
|
||||||
Poly::<u64>::new(self.n())
|
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>>>);
|
pub struct RingRNS<O: Unsigned>(pub Vec<Rc<Ring<O>>>);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use crate::modulus::{BARRETT, REDUCEMOD};
|
|||||||
use crate::poly::Poly;
|
use crate::poly::Poly;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::CHUNK;
|
use crate::CHUNK;
|
||||||
use crate::GALOISGENERATOR;
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
|
||||||
@@ -17,6 +16,7 @@ impl Ring<u64> {
|
|||||||
Self {
|
Self {
|
||||||
n: n,
|
n: n,
|
||||||
modulus: prime.clone(),
|
modulus: prime.clone(),
|
||||||
|
cyclotomic_order: n << 1,
|
||||||
dft: Box::new(Table::<u64>::new(prime, n << 1)),
|
dft: Box::new(Table::<u64>::new(prime, n << 1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,29 +40,6 @@ impl Ring<u64> {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.for_each(|(i, v)| *v = (&coeffs[i] % &q_big).to_u64().unwrap());
|
.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> {
|
impl Ring<u64> {
|
||||||
|
|||||||
@@ -77,9 +77,10 @@ fn test_automorphism_from_perm_u64<const NTT: bool>(ring: &Ring<u64>, nth_root:
|
|||||||
ring.ntt_inplace::<false>(&mut p0);
|
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);
|
ring.a_apply_automorphism_from_perm_into_b::<NTT>(&p0, &auto_perm, &mut p1);
|
||||||
|
|
||||||
|
|||||||
7
utils/Cargo.toml
Normal file
7
utils/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fnv = "1.0.7"
|
||||||
1
utils/src/lib.rs
Normal file
1
utils/src/lib.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod map;
|
||||||
20
utils/src/map.rs
Normal file
20
utils/src/map.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
use fnv::FnvHashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
pub struct Map<K, V>(pub FnvHashMap<K, V>);
|
||||||
|
|
||||||
|
impl<K: Eq + Hash, V> Map<K, V> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
0: FnvHashMap::<K, V>::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, k: K, data: V) -> Option<V> {
|
||||||
|
self.0.insert(k, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, k: &K) -> Option<&V> {
|
||||||
|
self.0.get(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user