mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 22:57:59 -05:00
feat(tfhe-ntt): Add custom root-of-unity for Solinas Prime
Those root-of-unity enable friendly twiddle generation with low hamming-weigth. And thus, enable to replace some multiplication with simple shift. Co-authored-by: Baptiste Roux <baptiste.roux@zama.ai>
This commit is contained in:
@@ -5,6 +5,7 @@ use aligned_vec::{avec, ABox};
|
|||||||
use pulp::*;
|
use pulp::*;
|
||||||
|
|
||||||
const RECURSION_THRESHOLD: usize = 1024;
|
const RECURSION_THRESHOLD: usize = 1024;
|
||||||
|
pub(crate) const SOLINAS_PRIME: u64 = ((1_u128 << 64) - (1_u128 << 32) + 1) as u64;
|
||||||
|
|
||||||
mod generic_solinas;
|
mod generic_solinas;
|
||||||
mod shoup;
|
mod shoup;
|
||||||
@@ -19,9 +20,9 @@ mod less_than_51bit;
|
|||||||
mod less_than_62bit;
|
mod less_than_62bit;
|
||||||
mod less_than_63bit;
|
mod less_than_63bit;
|
||||||
|
|
||||||
pub use generic_solinas::Solinas;
|
|
||||||
|
|
||||||
use self::generic_solinas::PrimeModulus;
|
use self::generic_solinas::PrimeModulus;
|
||||||
|
use crate::roots::find_root_solinas_64;
|
||||||
|
pub use generic_solinas::Solinas;
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
impl crate::V3 {
|
impl crate::V3 {
|
||||||
@@ -157,7 +158,29 @@ impl crate::V4 {
|
|||||||
|
|
||||||
fn init_negacyclic_twiddles(p: u64, n: usize, twid: &mut [u64], inv_twid: &mut [u64]) {
|
fn init_negacyclic_twiddles(p: u64, n: usize, twid: &mut [u64], inv_twid: &mut [u64]) {
|
||||||
let div = Div64::new(p);
|
let div = Div64::new(p);
|
||||||
let w = find_primitive_root64(div, 2 * n as u64).unwrap();
|
|
||||||
|
let w = if p == SOLINAS_PRIME {
|
||||||
|
// Used custom root-of-unity with Goldilocks prime
|
||||||
|
// Those root-of-unity enable generation of friendly twiddle will low hamming weight
|
||||||
|
// and enable replacement of multiplication with simple shift
|
||||||
|
match n {
|
||||||
|
32 => 8_u64,
|
||||||
|
64 => 2198989700608_u64,
|
||||||
|
128 => 14041890976876060974_u64,
|
||||||
|
256 => 14430643036723656017_u64,
|
||||||
|
512 => 4440654710286119610_u64,
|
||||||
|
1024 => 8816101479115663336_u64,
|
||||||
|
2048 => 10974926054405199669_u64,
|
||||||
|
4096 => 1206500561358145487_u64,
|
||||||
|
8192 => 10930245224889659871_u64,
|
||||||
|
16384 => 3333600369887534767_u64,
|
||||||
|
32768 => 15893793146607301539_u64,
|
||||||
|
_ => find_root_solinas_64(div, 2 * n as u64).unwrap(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
find_primitive_root64(div, 2 * n as u64).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut k = 0;
|
let mut k = 0;
|
||||||
let mut wk = 1u64;
|
let mut wk = 1u64;
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,22 @@ pub const fn find_primitive_root64(p: Div64, degree: u64) -> Option<u64> {
|
|||||||
Some(root)
|
Some(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the n-th root of unity in the solinas prime
|
||||||
|
///
|
||||||
|
/// Returns `None` if n == 0 or is greater than 2^32
|
||||||
|
pub const fn find_root_solinas_64(p: Div64, n: u64) -> Option<u64> {
|
||||||
|
if n == 0 || n > (1u64 << 32) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2^32th root of unity
|
||||||
|
const OMG_2_32: u64 = 16334397945464290598;
|
||||||
|
|
||||||
|
let pow = (1u64 << 32) / n;
|
||||||
|
|
||||||
|
Some(exp_mod64(p, OMG_2_32, pow))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -129,4 +145,29 @@ mod tests {
|
|||||||
}
|
}
|
||||||
assert_eq!(exp_mod64(p, root, deg), 1);
|
assert_eq!(exp_mod64(p, root, deg), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_primitive_root_solinas() {
|
||||||
|
let p = Div64::new(super::super::prime64::SOLINAS_PRIME);
|
||||||
|
let input_result = [
|
||||||
|
(32, 8_u64),
|
||||||
|
(64, 2198989700608_u64),
|
||||||
|
(128, 14041890976876060974_u64),
|
||||||
|
(256, 14430643036723656017_u64),
|
||||||
|
(512, 4440654710286119610_u64),
|
||||||
|
(1024, 8816101479115663336_u64),
|
||||||
|
(2048, 10974926054405199669_u64),
|
||||||
|
(4096, 1206500561358145487_u64),
|
||||||
|
(8192, 10930245224889659871_u64),
|
||||||
|
(16384, 3333600369887534767_u64),
|
||||||
|
(32768, 15893793146607301539_u64),
|
||||||
|
];
|
||||||
|
for (poly_size, expected_root) in input_result {
|
||||||
|
assert_eq!(
|
||||||
|
expected_root,
|
||||||
|
find_root_solinas_64(p, 2 * poly_size).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(exp_mod64(p, expected_root, 2 * poly_size), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user