mirror of
https://github.com/arnaucube/poulpy.git
synced 2026-02-10 13:16:44 +01:00
Updated automorphism from permuation
This commit is contained in:
@@ -44,7 +44,7 @@ fn main() {
|
|||||||
p0.0[i] = i as u64
|
p0.0[i] = i as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
r.a_apply_automorphism_into_b::<false>(&p0, 2 * r.n - 1, nth_root, &mut p1);
|
r.a_apply_automorphism_native_into_b::<false>(&p0, 2 * r.n - 1, nth_root, &mut p1);
|
||||||
|
|
||||||
println!("{:?}", p1);
|
println!("{:?}", p1);
|
||||||
}
|
}
|
||||||
|
|||||||
52
math/src/automorphism.rs
Normal file
52
math/src/automorphism.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
use crate::modulus::WordOps;
|
||||||
|
|
||||||
|
pub struct AutomorphismPermutation {
|
||||||
|
pub gal_el: usize,
|
||||||
|
pub permutation: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AutomorphismPermutation {
|
||||||
|
/// 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<const NTT: bool>(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
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut permutation: Vec<usize> = Vec::with_capacity(n);
|
||||||
|
|
||||||
|
if NTT {
|
||||||
|
let mask = nth_root - 1;
|
||||||
|
let log_nth_root_half: u32 = nth_root.log2() as u32 - 1;
|
||||||
|
for i in 0..n {
|
||||||
|
let i_rev: usize = 2 * i.reverse_bits_msb(log_nth_root_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));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let log_n: usize = n.log2();
|
||||||
|
let mask: usize = (n - 1) as usize;
|
||||||
|
for i in 0..n {
|
||||||
|
let gal_el_i: usize = i as usize * gal_el;
|
||||||
|
let sign: usize = (gal_el_i >> log_n) & 1;
|
||||||
|
let i_out: usize = (gal_el_i & mask) | (sign << (usize::BITS - 1));
|
||||||
|
permutation.push(i_out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
gal_el: gal_el,
|
||||||
|
permutation: permutation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#![feature(bigint_helper_methods)]
|
#![feature(bigint_helper_methods)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|
||||||
|
pub mod automorphism;
|
||||||
pub mod dft;
|
pub mod dft;
|
||||||
pub mod modulus;
|
pub mod modulus;
|
||||||
pub mod num_bigint;
|
pub mod num_bigint;
|
||||||
|
|||||||
@@ -1,84 +1,44 @@
|
|||||||
|
use crate::automorphism::AutomorphismPermutation;
|
||||||
use crate::modulus::{ScalarOperations, ONCE};
|
use crate::modulus::{ScalarOperations, ONCE};
|
||||||
use crate::modulus::{WordOps, REDUCEMOD};
|
use crate::modulus::{WordOps, REDUCEMOD};
|
||||||
use crate::poly::Poly;
|
use crate::poly::Poly;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
|
|
||||||
/// 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<const NTT: bool>(n: usize, nth_root: usize, gal_el: usize) -> Vec<usize> {
|
|
||||||
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 mut index: Vec<usize> = Vec::with_capacity(n);
|
|
||||||
|
|
||||||
if NTT {
|
|
||||||
let mask = nth_root - 1;
|
|
||||||
let log_nth_root_half: u32 = nth_root.log2() as u32 - 1;
|
|
||||||
for i in 0..n {
|
|
||||||
let i_rev: usize = 2 * i.reverse_bits_msb(log_nth_root_half) + 1;
|
|
||||||
let gal_el_i: usize = ((gal_el * i_rev) & mask) >> 1;
|
|
||||||
index.push(gal_el_i.reverse_bits_msb(log_nth_root_half));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let log_n: usize = n.log2();
|
|
||||||
let mask: usize = (n - 1) as usize;
|
|
||||||
for i in 0..n {
|
|
||||||
let gal_el_i: usize = i as usize * gal_el;
|
|
||||||
let sign: usize = (gal_el_i >> log_n) & 1;
|
|
||||||
let i_out: usize = (gal_el_i & mask) | (sign << (usize::BITS - 1));
|
|
||||||
index.push(i_out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
index
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ring<u64> {
|
impl Ring<u64> {
|
||||||
// b <- auto(a)
|
// b <- auto(a)
|
||||||
pub fn a_apply_automorphism_into_b<const NTT: bool>(
|
pub fn a_apply_automorphism_native_into_b<const NTT: bool>(
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
gal_el: usize,
|
gal_el: usize,
|
||||||
nth_root: usize,
|
nth_root: usize,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
self.apply_automorphism_core::<0, ONCE, NTT>(a, gal_el, nth_root, b)
|
self.apply_automorphism_native_core::<0, ONCE, NTT>(a, gal_el, nth_root, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// b <- REDUCEMOD(b + auto(a))
|
// b <- REDUCEMOD(b + auto(a))
|
||||||
pub fn a_apply_automorphism_add_b_into_b<const REDUCE: REDUCEMOD, const NTT: bool>(
|
pub fn a_apply_automorphism_native_add_b_into_b<const REDUCE: REDUCEMOD, const NTT: bool>(
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
gal_el: usize,
|
gal_el: usize,
|
||||||
nth_root: usize,
|
nth_root: usize,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
self.apply_automorphism_core::<1, REDUCE, NTT>(a, gal_el, nth_root, b)
|
self.apply_automorphism_native_core::<1, REDUCE, NTT>(a, gal_el, nth_root, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// b <- REDUCEMOD(b - auto(a))
|
// b <- REDUCEMOD(b - auto(a))
|
||||||
pub fn a_apply_automorphism_sub_b_into_b<const REDUCE: REDUCEMOD, const NTT: bool>(
|
pub fn a_apply_automorphism_native_sub_b_into_b<const REDUCE: REDUCEMOD, const NTT: bool>(
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
gal_el: usize,
|
gal_el: usize,
|
||||||
nth_root: usize,
|
nth_root: usize,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
self.apply_automorphism_core::<2, REDUCE, NTT>(a, gal_el, nth_root, b)
|
self.apply_automorphism_native_core::<2, REDUCE, NTT>(a, gal_el, nth_root, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_automorphism_core<const MOD: u8, const REDUCE: REDUCEMOD, const NTT: bool>(
|
fn apply_automorphism_native_core<const MOD: u8, const REDUCE: REDUCEMOD, const NTT: bool>(
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
gal_el: usize,
|
gal_el: usize,
|
||||||
@@ -155,46 +115,40 @@ impl Ring<u64> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// b <- auto(a)
|
// b <- auto(a)
|
||||||
pub fn a_apply_automorphism_from_index_into_b<const NTT: bool>(
|
pub fn a_apply_automorphism_from_perm_into_b<const NTT: bool>(
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
idx: &[usize],
|
auto_perm: &AutomorphismPermutation,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
self.automorphism_from_index_core::<0, ONCE, NTT>(a, idx, b)
|
self.automorphism_from_perm_core::<0, ONCE, NTT>(a, auto_perm, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// b <- REDUCEMOD(b + auto(a))
|
// b <- REDUCEMOD(b + auto(a))
|
||||||
pub fn a_apply_automorphism_from_index_add_b_into_b<
|
pub fn a_apply_automorphism_from_perm_add_b_into_b<const REDUCE: REDUCEMOD, const NTT: bool>(
|
||||||
const REDUCE: REDUCEMOD,
|
|
||||||
const NTT: bool,
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
idx: &[usize],
|
auto_perm: &AutomorphismPermutation,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
self.automorphism_from_index_core::<1, REDUCE, NTT>(a, idx, b)
|
self.automorphism_from_perm_core::<1, REDUCE, NTT>(a, auto_perm, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// b <- REDUCEMOD(b - auto(a))
|
// b <- REDUCEMOD(b - auto(a))
|
||||||
pub fn a_apply_automorphism_from_index_sub_b_into_b<
|
pub fn a_apply_automorphism_from_perm_sub_b_into_b<const REDUCE: REDUCEMOD, const NTT: bool>(
|
||||||
const REDUCE: REDUCEMOD,
|
|
||||||
const NTT: bool,
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
idx: &[usize],
|
auto_perm: &AutomorphismPermutation,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
self.automorphism_from_index_core::<2, REDUCE, NTT>(a, idx, b)
|
self.automorphism_from_perm_core::<2, REDUCE, NTT>(a, auto_perm, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// b <- auto(a) if OVERWRITE else b <- REDUCEMOD(b + auto(a))
|
// b <- auto(a) if OVERWRITE else b <- REDUCEMOD(b + auto(a))
|
||||||
fn automorphism_from_index_core<const MOD: u8, const REDUCE: REDUCEMOD, const NTT: bool>(
|
fn automorphism_from_perm_core<const MOD: u8, const REDUCE: REDUCEMOD, const NTT: bool>(
|
||||||
&self,
|
&self,
|
||||||
a: &Poly<u64>,
|
a: &Poly<u64>,
|
||||||
idx: &[usize],
|
auto_perm: &AutomorphismPermutation,
|
||||||
b: &mut Poly<u64>,
|
b: &mut Poly<u64>,
|
||||||
) {
|
) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
@@ -207,6 +161,8 @@ impl Ring<u64> {
|
|||||||
let b_vec: &mut Vec<u64> = &mut b.0;
|
let b_vec: &mut Vec<u64> = &mut b.0;
|
||||||
let a_vec: &Vec<u64> = &a.0;
|
let a_vec: &Vec<u64> = &a.0;
|
||||||
|
|
||||||
|
let idx: &Vec<usize> = &auto_perm.permutation;
|
||||||
|
|
||||||
if NTT {
|
if NTT {
|
||||||
a_vec.iter().enumerate().for_each(|(i, ai)| match MOD {
|
a_vec.iter().enumerate().for_each(|(i, ai)| match MOD {
|
||||||
0 => b_vec[idx[i]] = *ai,
|
0 => b_vec[idx[i]] = *ai,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
|
use math::automorphism::AutomorphismPermutation;
|
||||||
use math::poly::Poly;
|
use math::poly::Poly;
|
||||||
use math::ring::Ring;
|
use math::ring::Ring;
|
||||||
|
|
||||||
@@ -10,11 +11,18 @@ fn automorphism_u64() {
|
|||||||
let q_power: usize = 1usize;
|
let q_power: usize = 1usize;
|
||||||
let ring: Ring<u64> = Ring::new(n, q_base, q_power);
|
let ring: Ring<u64> = Ring::new(n, q_base, q_power);
|
||||||
|
|
||||||
sub_test("test_automorphism_u64::<NTT:false>", || {
|
sub_test("test_automorphism_native_u64::<NTT:false>", || {
|
||||||
test_automorphism_u64::<false>(&ring, nth_root)
|
test_automorphism_native_u64::<false>(&ring, nth_root)
|
||||||
});
|
});
|
||||||
sub_test("test_automorphism_u64::<NTT:true>", || {
|
sub_test("test_automorphism_native_u64::<NTT:true>", || {
|
||||||
test_automorphism_u64::<true>(&ring, nth_root)
|
test_automorphism_native_u64::<true>(&ring, nth_root)
|
||||||
|
});
|
||||||
|
|
||||||
|
sub_test("test_automorphism_from_perm_u64::<NTT:false>", || {
|
||||||
|
test_automorphism_from_perm_u64::<false>(&ring, nth_root)
|
||||||
|
});
|
||||||
|
sub_test("test_automorphism_from_perm_u64::<NTT:true>", || {
|
||||||
|
test_automorphism_from_perm_u64::<true>(&ring, nth_root)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +31,7 @@ fn sub_test<F: FnOnce()>(name: &str, f: F) {
|
|||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_automorphism_u64<const NTT: bool>(ring: &Ring<u64>, nth_root: usize) {
|
fn test_automorphism_native_u64<const NTT: bool>(ring: &Ring<u64>, nth_root: usize) {
|
||||||
let n: usize = ring.n();
|
let n: usize = ring.n();
|
||||||
let q: u64 = ring.modulus.q;
|
let q: u64 = ring.modulus.q;
|
||||||
|
|
||||||
@@ -38,7 +46,42 @@ fn test_automorphism_u64<const NTT: bool>(ring: &Ring<u64>, nth_root: usize) {
|
|||||||
ring.ntt_inplace::<false>(&mut p0);
|
ring.ntt_inplace::<false>(&mut p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ring.a_apply_automorphism_into_b::<NTT>(&p0, 2 * n - 1, nth_root, &mut p1);
|
let gal_el: usize = 2 * nth_root - 1;
|
||||||
|
|
||||||
|
ring.a_apply_automorphism_native_into_b::<NTT>(&p0, gal_el, nth_root, &mut p1);
|
||||||
|
|
||||||
|
if NTT {
|
||||||
|
ring.intt_inplace::<false>(&mut p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
p0.0[0] = 0;
|
||||||
|
for i in 1..p0.n() {
|
||||||
|
p0.0[i] = q - (n - i) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
izip!(p0.0, p1.0).for_each(|(a, b)| assert_eq!(a, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_automorphism_from_perm_u64<const NTT: bool>(ring: &Ring<u64>, nth_root: usize) {
|
||||||
|
let n: usize = ring.n();
|
||||||
|
let q: u64 = ring.modulus.q;
|
||||||
|
|
||||||
|
let mut p0: Poly<u64> = ring.new_poly();
|
||||||
|
let mut p1: Poly<u64> = ring.new_poly();
|
||||||
|
|
||||||
|
for i in 0..p0.n() {
|
||||||
|
p0.0[i] = i as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
if NTT {
|
||||||
|
ring.ntt_inplace::<false>(&mut p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let gal_el: usize = 2 * nth_root - 1;
|
||||||
|
|
||||||
|
let auto_perm = AutomorphismPermutation::new::<NTT>(n, gal_el, nth_root);
|
||||||
|
|
||||||
|
ring.a_apply_automorphism_from_perm_into_b::<NTT>(&p0, &auto_perm, &mut p1);
|
||||||
|
|
||||||
if NTT {
|
if NTT {
|
||||||
ring.intt_inplace::<false>(&mut p1);
|
ring.intt_inplace::<false>(&mut p1);
|
||||||
|
|||||||
Reference in New Issue
Block a user