mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
wip
This commit is contained in:
43
math/src/ring/impl_u64/automorphism.rs
Normal file
43
math/src/ring/impl_u64/automorphism.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use crate::modulus::WordOps;
|
||||
use crate::ring::Ring;
|
||||
use crate::poly::Poly;
|
||||
|
||||
/// 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 automorphism_index_ntt(n: usize, nth_root:u64, gal_el: u64) -> Vec<u64>{
|
||||
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);
|
||||
|
||||
let mask = nth_root-1;
|
||||
let log_nth_root: u32 = nth_root.log2() as u32;
|
||||
let mut index: Vec<u64> = Vec::with_capacity(n);
|
||||
for i in 0..n{
|
||||
let i_rev: usize = 2*i.reverse_bits_msb(log_nth_root)+1;
|
||||
let gal_el_i: u64 = (gal_el * (i_rev as u64) & mask)>>1;
|
||||
index.push(gal_el_i.reverse_bits_msb(log_nth_root));
|
||||
}
|
||||
index
|
||||
}
|
||||
|
||||
impl Ring<u64>{
|
||||
pub fn automorphism(&self, a:Poly<u64>, gal_el: u64, b:&mut Poly<u64>){
|
||||
debug_assert!(a.n() == b.n(), "invalid inputs: a.n() = {} != b.n() = {}", a.n(), b.n());
|
||||
debug_assert!(gal_el&1 == 1, "invalid gal_el = {}: not odd", gal_el);
|
||||
|
||||
let n: usize = a.n();
|
||||
let mask: u64 = (n-1) as u64;
|
||||
let log_n: usize = n.log2();
|
||||
let q: u64 = self.modulus.q();
|
||||
let b_vec: &mut _ = &mut b.0;
|
||||
let a_vec: &_ = &a.0;
|
||||
|
||||
a_vec.iter().enumerate().for_each(|(i, ai)|{
|
||||
let gal_el_i: u64 = i as u64 * gal_el;
|
||||
let sign: u64 = (gal_el_i>>log_n) & 1;
|
||||
let i_out: u64 = gal_el_i & mask;
|
||||
b_vec[i_out as usize] = ai * (sign^1) | (q - ai) * sign
|
||||
});
|
||||
}
|
||||
}
|
||||
3
math/src/ring/impl_u64/mod.rs
Normal file
3
math/src/ring/impl_u64/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod automorphism;
|
||||
pub mod ring;
|
||||
pub mod ring_rns;
|
||||
102
math/src/ring/impl_u64/ring.rs
Normal file
102
math/src/ring/impl_u64/ring.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
use crate::ring::Ring;
|
||||
use crate::dft::ntt::Table;
|
||||
use crate::modulus::prime::Prime;
|
||||
use crate::modulus::montgomery::Montgomery;
|
||||
use crate::poly::Poly;
|
||||
use crate::modulus::REDUCEMOD;
|
||||
use crate::modulus::VecOperations;
|
||||
use crate::CHUNK;
|
||||
|
||||
impl Ring<u64>{
|
||||
pub fn new(n:usize, q_base:u64, q_power:usize) -> Self{
|
||||
let prime: Prime<u64> = Prime::<u64>::new(q_base, q_power);
|
||||
Self {
|
||||
n: n,
|
||||
modulus: prime.clone(),
|
||||
dft: Box::new(Table::<u64>::new(prime, (2 * n) as u64)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn n(&self) -> usize{
|
||||
return self.n
|
||||
}
|
||||
|
||||
pub fn new_poly(&self) -> Poly<u64>{
|
||||
Poly::<u64>::new(self.n())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ring<u64>{
|
||||
pub fn ntt_inplace<const LAZY:bool>(&self, poly: &mut Poly<u64>){
|
||||
match LAZY{
|
||||
true => self.dft.forward_inplace_lazy(&mut poly.0),
|
||||
false => self.dft.forward_inplace(&mut poly.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intt_inplace<const LAZY:bool>(&self, poly: &mut Poly<u64>){
|
||||
match LAZY{
|
||||
true => self.dft.forward_inplace_lazy(&mut poly.0),
|
||||
false => self.dft.forward_inplace(&mut poly.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ntt<const LAZY:bool>(&self, poly_in: &Poly<u64>, poly_out: &mut Poly<u64>){
|
||||
poly_out.0.copy_from_slice(&poly_in.0);
|
||||
match LAZY{
|
||||
true => self.dft.backward_inplace_lazy(&mut poly_out.0),
|
||||
false => self.dft.backward_inplace(&mut poly_out.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intt<const LAZY:bool>(&self, poly_in: &Poly<u64>, poly_out: &mut Poly<u64>){
|
||||
poly_out.0.copy_from_slice(&poly_in.0);
|
||||
match LAZY{
|
||||
true => self.dft.backward_inplace_lazy(&mut poly_out.0),
|
||||
false => self.dft.backward_inplace(&mut poly_out.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ring<u64>{
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_inplace<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>){
|
||||
self.modulus.vec_add_unary_assign::<CHUNK, REDUCE>(&a.0, &mut b.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &Poly<u64>, c: &mut Poly<u64>){
|
||||
self.modulus.vec_add_binary_assign::<CHUNK, REDUCE>(&a.0, &b.0, &mut c.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub_inplace<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>){
|
||||
self.modulus.vec_sub_unary_assign::<CHUNK, REDUCE>(&a.0, &mut b.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &Poly<u64>, c: &mut Poly<u64>){
|
||||
self.modulus.vec_sub_binary_assign::<CHUNK, REDUCE>(&a.0, &b.0, &mut c.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn neg<const REDUCE: REDUCEMOD>(&self, a: &Poly<u64>, b: &mut Poly<u64>){
|
||||
self.modulus.vec_neg_binary_assign::<CHUNK, REDUCE>(&a.0, &mut b.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn neg_inplace<const REDUCE: REDUCEMOD>(&self, a: &mut Poly<u64>){
|
||||
self.modulus.vec_neg_unary_assign::<CHUNK, REDUCE>(&mut a.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mul_montgomery_external<const REDUCE:REDUCEMOD>(&self, a:&Poly<Montgomery<u64>>, b:&Poly<u64>, c: &mut Poly<u64>){
|
||||
self.modulus.vec_mul_montgomery_external_binary_assign::<CHUNK, REDUCE>(&a.0, &b.0, &mut c.0);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mul_montgomery_external_inplace<const REDUCE:REDUCEMOD>(&self, a:&Poly<Montgomery<u64>>, b:&mut Poly<u64>){
|
||||
self.modulus.vec_mul_montgomery_external_unary_assign::<CHUNK, REDUCE>(&a.0, &mut b.0);
|
||||
}
|
||||
}
|
||||
114
math/src/ring/impl_u64/ring_rns.rs
Normal file
114
math/src/ring/impl_u64/ring_rns.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
use crate::ring::{Ring, RingRNS};
|
||||
use crate::poly::PolyRNS;
|
||||
use crate::modulus::montgomery::Montgomery;
|
||||
use crate::modulus::REDUCEMOD;
|
||||
|
||||
impl RingRNS<u64>{
|
||||
pub fn new(n:usize, moduli: Vec<u64>) -> Self{
|
||||
assert!(!moduli.is_empty(), "moduli cannot be empty");
|
||||
let rings: Vec<Ring<u64>> = moduli
|
||||
.into_iter()
|
||||
.map(|prime: u64| Ring::new(n, prime, 1))
|
||||
.collect();
|
||||
RingRNS(rings)
|
||||
}
|
||||
|
||||
pub fn n(&self) -> usize{
|
||||
self.0[0].n()
|
||||
}
|
||||
|
||||
pub fn max_level(&self) -> usize{
|
||||
self.0.len()-1
|
||||
}
|
||||
}
|
||||
|
||||
impl RingRNS<u64>{
|
||||
|
||||
}
|
||||
|
||||
impl RingRNS<u64>{
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add<const LEVEL:usize, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &PolyRNS<u64>, c: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(c.n() >= self.n(), "c.n()={} < n={}", c.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
debug_assert!(c.level() >= LEVEL, "c.level()={} < LEVEL={}", c.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.add::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_inplace<const LEVEL:usize, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.add_inplace::<REDUCE>(&a.0[i], &mut b.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub<const LEVEL:usize, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &PolyRNS<u64>, c: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(c.n() >= self.n(), "c.n()={} < n={}", c.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
debug_assert!(c.level() >= LEVEL, "c.level()={} < LEVEL={}", c.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.sub::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sub_inplace<const LEVEL:usize, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.sub_inplace::<REDUCE>(&a.0[i], &mut b.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn neg<const LEVEL:usize, const REDUCE: REDUCEMOD>(&self, a: &PolyRNS<u64>, b: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.neg::<REDUCE>(&a.0[i], &mut b.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn neg_inplace<const LEVEL:usize, const REDUCE: REDUCEMOD>(&self, a: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.neg_inplace::<REDUCE>(&mut a.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mul_montgomery_external<const LEVEL:usize, const REDUCE:REDUCEMOD>(&self, a:&PolyRNS<Montgomery<u64>>, b:&PolyRNS<u64>, c: &mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(c.n() >= self.n(), "c.n()={} < n={}", c.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
debug_assert!(c.level() >= LEVEL, "c.level()={} < LEVEL={}", c.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.mul_montgomery_external::<REDUCE>(&a.0[i], &b.0[i], &mut c.0[i]));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn mul_montgomery_external_inplace<const LEVEL:usize, const REDUCE:REDUCEMOD>(&self, a:&PolyRNS<Montgomery<u64>>, b:&mut PolyRNS<u64>){
|
||||
debug_assert!(self.max_level() <= LEVEL, "max_level={} < LEVEL={}", self.max_level(), LEVEL);
|
||||
debug_assert!(a.n() >= self.n(), "a.n()={} < n={}", a.n(), self.n());
|
||||
debug_assert!(b.n() >= self.n(), "b.n()={} < n={}", b.n(), self.n());
|
||||
debug_assert!(a.level() >= LEVEL, "a.level()={} < LEVEL={}", a.level(), LEVEL);
|
||||
debug_assert!(b.level() >= LEVEL, "b.level()={} < LEVEL={}", b.level(), LEVEL);
|
||||
self.0.iter().take(LEVEL + 1).enumerate().for_each(|(i, ring)| ring.mul_montgomery_external_inplace::<REDUCE>(&a.0[i], &mut b.0[i]));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user