mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-10 08:01:30 +01:00
add modulus operator for power of 2 modulus
This commit is contained in:
@@ -3,9 +3,11 @@ use num_traits::ToPrimitive;
|
|||||||
use crate::{Matrix, Row, RowMut};
|
use crate::{Matrix, Row, RowMut};
|
||||||
|
|
||||||
mod modulus_u64;
|
mod modulus_u64;
|
||||||
|
mod power_of_2;
|
||||||
mod word_size;
|
mod word_size;
|
||||||
|
|
||||||
pub use modulus_u64::ModularOpsU64;
|
pub use modulus_u64::ModularOpsU64;
|
||||||
|
pub(crate) use power_of_2::ModulusPowerOf2;
|
||||||
pub use word_size::WordSizeModulus;
|
pub use word_size::WordSizeModulus;
|
||||||
|
|
||||||
pub trait Modulus {
|
pub trait Modulus {
|
||||||
|
|||||||
112
src/backend/power_of_2.rs
Normal file
112
src/backend/power_of_2.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
use itertools::izip;
|
||||||
|
|
||||||
|
use crate::{ArithmeticOps, ModInit, VectorOps};
|
||||||
|
|
||||||
|
use super::{GetModulus, Modulus};
|
||||||
|
|
||||||
|
pub(crate) struct ModulusPowerOf2<T> {
|
||||||
|
modulus: T,
|
||||||
|
/// Modulus mask: (1 << q) - 1
|
||||||
|
mask: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ArithmeticOps for ModulusPowerOf2<T> {
|
||||||
|
type Element = u64;
|
||||||
|
#[inline]
|
||||||
|
fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
|
||||||
|
(a.wrapping_add(*b)) & self.mask
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
|
||||||
|
(a.wrapping_sub(*b)) & self.mask
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn mul(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
|
||||||
|
(a.wrapping_mul(*b)) & self.mask
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn neg(&self, a: &Self::Element) -> Self::Element {
|
||||||
|
(0u64.wrapping_sub(*a)) & self.mask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VectorOps for ModulusPowerOf2<T> {
|
||||||
|
type Element = u64;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_add_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
|
||||||
|
izip!(a.iter_mut(), b.iter()).for_each(|(a0, b0)| *a0 = (a0.wrapping_add(*b0)) & self.mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_mul_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
|
||||||
|
izip!(a.iter_mut(), b.iter()).for_each(|(a0, b0)| *a0 = (a0.wrapping_mul(*b0)) & self.mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_neg_mut(&self, a: &mut [Self::Element]) {
|
||||||
|
a.iter_mut()
|
||||||
|
.for_each(|a0| *a0 = 0u64.wrapping_sub(*a0) & self.mask);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn elwise_sub_mut(&self, a: &mut [Self::Element], b: &[Self::Element]) {
|
||||||
|
izip!(a.iter_mut(), b.iter()).for_each(|(a0, b0)| *a0 = (a0.wrapping_sub(*b0)) & self.mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_fma_mut(&self, a: &mut [Self::Element], b: &[Self::Element], c: &[Self::Element]) {
|
||||||
|
izip!(a.iter_mut(), b.iter(), c.iter()).for_each(|(a0, b0, c0)| {
|
||||||
|
*a0 = a0.wrapping_add(b0.wrapping_mul(*c0)) & self.mask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_fma_scalar_mut(
|
||||||
|
&self,
|
||||||
|
a: &mut [Self::Element],
|
||||||
|
b: &[Self::Element],
|
||||||
|
c: &Self::Element,
|
||||||
|
) {
|
||||||
|
izip!(a.iter_mut(), b.iter()).for_each(|(a0, b0)| {
|
||||||
|
*a0 = a0.wrapping_add(b0.wrapping_mul(*c)) & self.mask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn elwise_scalar_mul_mut(&self, a: &mut [Self::Element], b: &Self::Element) {
|
||||||
|
a.iter_mut()
|
||||||
|
.for_each(|a0| *a0 = a0.wrapping_mul(*b) & self.mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &[Self::Element]) {
|
||||||
|
izip!(out.iter_mut(), a.iter(), b.iter()).for_each(|(o0, a0, b0)| {
|
||||||
|
*o0 = a0.wrapping_mul(*b0) & self.mask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elwise_scalar_mul(&self, out: &mut [Self::Element], a: &[Self::Element], b: &Self::Element) {
|
||||||
|
izip!(out.iter_mut(), a.iter()).for_each(|(o0, a0)| {
|
||||||
|
*o0 = a0.wrapping_mul(*b) & self.mask;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Modulus<Element = u64>> ModInit for ModulusPowerOf2<T> {
|
||||||
|
type M = T;
|
||||||
|
fn new(modulus: Self::M) -> Self {
|
||||||
|
assert!(!modulus.is_native());
|
||||||
|
assert!(modulus.q().unwrap().is_power_of_two());
|
||||||
|
let q = modulus.q().unwrap();
|
||||||
|
let mask = q - 1;
|
||||||
|
Self { modulus, mask }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Modulus<Element = u64>> GetModulus for ModulusPowerOf2<T> {
|
||||||
|
type Element = u64;
|
||||||
|
type M = T;
|
||||||
|
fn modulus(&self) -> &Self::M {
|
||||||
|
&self.modulus
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,14 +12,14 @@ use keys::*;
|
|||||||
use parameters::*;
|
use parameters::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::ModularOpsU64,
|
backend::{ModularOpsU64, ModulusPowerOf2},
|
||||||
ntt::NttBackendU64,
|
ntt::NttBackendU64,
|
||||||
random::{DefaultSecureRng, NewWithSeed},
|
random::{DefaultSecureRng, NewWithSeed},
|
||||||
utils::{Global, WithLocal},
|
utils::{Global, WithLocal},
|
||||||
};
|
};
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModularOpsU64<CiphertextModulus<u64>>, ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>>>> = RefCell::new(None);
|
static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator<Vec<Vec<u64>>, NttBackendU64, ModularOpsU64<CiphertextModulus<u64>>, ModulusPowerOf2<CiphertextModulus<u64>>, ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>>>> = RefCell::new(None);
|
||||||
|
|
||||||
}
|
}
|
||||||
static BOOL_SERVER_KEY: OnceLock<ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>> = OnceLock::new();
|
static BOOL_SERVER_KEY: OnceLock<ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>> = OnceLock::new();
|
||||||
@@ -138,7 +138,7 @@ impl WithLocal
|
|||||||
Vec<Vec<u64>>,
|
Vec<Vec<u64>>,
|
||||||
NttBackendU64,
|
NttBackendU64,
|
||||||
ModularOpsU64<CiphertextModulus<u64>>,
|
ModularOpsU64<CiphertextModulus<u64>>,
|
||||||
ModularOpsU64<CiphertextModulus<u64>>,
|
ModulusPowerOf2<CiphertextModulus<u64>>,
|
||||||
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mod test {
|
|||||||
use itertools::{izip, Itertools};
|
use itertools::{izip, Itertools};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ArithmeticOps, ModularOpsU64, Modulus},
|
backend::{ArithmeticOps, ModularOpsU64, Modulus, ModulusPowerOf2},
|
||||||
bool::{
|
bool::{
|
||||||
set_parameter_set, BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus,
|
set_parameter_set, BoolEncoding, BoolEvaluator, BooleanGates, CiphertextModulus,
|
||||||
ClientKey, PublicKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain,
|
ClientKey, PublicKey, ServerKeyEvaluationDomain, ShoupServerKeyEvaluationDomain,
|
||||||
@@ -24,7 +24,7 @@ mod test {
|
|||||||
Vec<Vec<u64>>,
|
Vec<Vec<u64>>,
|
||||||
NttBackendU64,
|
NttBackendU64,
|
||||||
ModularOpsU64<CiphertextModulus<u64>>,
|
ModularOpsU64<CiphertextModulus<u64>>,
|
||||||
ModularOpsU64<CiphertextModulus<u64>>,
|
ModulusPowerOf2<CiphertextModulus<u64>>,
|
||||||
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
|
||||||
>::new(SMALL_MP_BOOL_PARAMS);
|
>::new(SMALL_MP_BOOL_PARAMS);
|
||||||
|
|
||||||
@@ -103,9 +103,9 @@ mod test {
|
|||||||
// let mut stats = Stats::new();
|
// let mut stats = Stats::new();
|
||||||
|
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
// let now = std::time::Instant::now();
|
let now = std::time::Instant::now();
|
||||||
let c_out = evaluator.xor(&c_m0, &c_m1, &runtime_server_key);
|
let c_out = evaluator.xor(&c_m0, &c_m1, &runtime_server_key);
|
||||||
// println!("Gate time: {:?}", now.elapsed());
|
println!("Gate time: {:?}", now.elapsed());
|
||||||
|
|
||||||
// mp decrypt
|
// mp decrypt
|
||||||
let decryption_shares = cks
|
let decryption_shares = cks
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ impl<T: PrimInt + From<bool> + WrappingSub + Display> Iterator for DecomposerIte
|
|||||||
let carry_bool =
|
let carry_bool =
|
||||||
k_i > self.bby2 || (k_i == self.bby2 && ((self.value & T::one()) == T::one()));
|
k_i > self.bby2 || (k_i == self.bby2 && ((self.value & T::one()) == T::one()));
|
||||||
let carry = <T as From<bool>>::from(carry_bool);
|
let carry = <T as From<bool>>::from(carry_bool);
|
||||||
let neg_carry = (T::zero().wrapping_sub(&carry)) >> 9;
|
let neg_carry = (T::zero().wrapping_sub(&carry));
|
||||||
self.value = self.value + carry;
|
self.value = self.value + carry;
|
||||||
Some((neg_carry & self.q) + k_i - (carry << self.logb))
|
Some((neg_carry & self.q) + k_i - (carry << self.logb))
|
||||||
|
|
||||||
|
|||||||
21
src/lwe.rs
21
src/lwe.rs
@@ -285,7 +285,7 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ModInit, ModularOpsU64},
|
backend::{ModInit, ModularOpsU64, ModulusPowerOf2},
|
||||||
decomposer::{Decomposer, DefaultDecomposer},
|
decomposer::{Decomposer, DefaultDecomposer},
|
||||||
lwe::{lwe_key_switch, measure_noise_lwe},
|
lwe::{lwe_key_switch, measure_noise_lwe},
|
||||||
random::DefaultSecureRng,
|
random::DefaultSecureRng,
|
||||||
@@ -307,7 +307,7 @@ mod tests {
|
|||||||
let lwe_n = 1024;
|
let lwe_n = 1024;
|
||||||
let logp = 3;
|
let logp = 3;
|
||||||
|
|
||||||
let modq_op = ModularOpsU64::new(q);
|
let modq_op = ModulusPowerOf2::new(q);
|
||||||
let lwe_sk = LweSecret::random(lwe_n >> 1, lwe_n);
|
let lwe_sk = LweSecret::random(lwe_n >> 1, lwe_n);
|
||||||
|
|
||||||
let mut rng = DefaultSecureRng::new();
|
let mut rng = DefaultSecureRng::new();
|
||||||
@@ -333,22 +333,22 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_switch_works() {
|
fn key_switch_works() {
|
||||||
let logq = 18;
|
let logq = 20;
|
||||||
let logp = 2;
|
let logp = 2;
|
||||||
let q = 1u64 << logq;
|
let q = 1u64 << logq;
|
||||||
let lwe_in_n = 2048;
|
let lwe_in_n = 2048;
|
||||||
let lwe_out_n = 493;
|
let lwe_out_n = 600;
|
||||||
let d_ks = 3;
|
let d_ks = 5;
|
||||||
let logb = 6;
|
let logb = 4;
|
||||||
|
|
||||||
let lwe_sk_in = LweSecret::random(lwe_in_n >> 1, lwe_in_n);
|
let lwe_sk_in = LweSecret::random(lwe_in_n >> 1, lwe_in_n);
|
||||||
let lwe_sk_out = LweSecret::random(lwe_out_n >> 1, lwe_out_n);
|
let lwe_sk_out = LweSecret::random(lwe_out_n >> 1, lwe_out_n);
|
||||||
|
|
||||||
let mut rng = DefaultSecureRng::new();
|
let mut rng = DefaultSecureRng::new();
|
||||||
let modq_op = ModularOpsU64::new(q);
|
let modq_op = ModulusPowerOf2::new(q);
|
||||||
|
|
||||||
// genrate ksk
|
// genrate ksk
|
||||||
for _ in 0..K {
|
for _ in 0..1 {
|
||||||
let mut ksk_seed = [0u8; 32];
|
let mut ksk_seed = [0u8; 32];
|
||||||
rng.fill_bytes(&mut ksk_seed);
|
rng.fill_bytes(&mut ksk_seed);
|
||||||
let mut seeded_ksk =
|
let mut seeded_ksk =
|
||||||
@@ -381,8 +381,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// key switch from lwe_sk_in to lwe_sk_out
|
// key switch from lwe_sk_in to lwe_sk_out
|
||||||
let decomposer = DefaultDecomposer::new(1u64 << logq, logb, d_ks);
|
|
||||||
let mut lwe_out_ct = vec![0u64; lwe_out_n + 1];
|
let mut lwe_out_ct = vec![0u64; lwe_out_n + 1];
|
||||||
|
let now = std::time::Instant::now();
|
||||||
lwe_key_switch(
|
lwe_key_switch(
|
||||||
&mut lwe_out_ct,
|
&mut lwe_out_ct,
|
||||||
&lwe_in_ct,
|
&lwe_in_ct,
|
||||||
@@ -390,6 +390,7 @@ mod tests {
|
|||||||
&modq_op,
|
&modq_op,
|
||||||
&decomposer,
|
&decomposer,
|
||||||
);
|
);
|
||||||
|
println!("Time: {:?}", now.elapsed());
|
||||||
|
|
||||||
// decrypt lwe_out_ct using lwe_sk_out
|
// decrypt lwe_out_ct using lwe_sk_out
|
||||||
let encoded_m_back = decrypt_lwe(&lwe_out_ct, &lwe_sk_out.values(), &modq_op);
|
let encoded_m_back = decrypt_lwe(&lwe_out_ct, &lwe_sk_out.values(), &modq_op);
|
||||||
@@ -399,7 +400,7 @@ mod tests {
|
|||||||
let noise =
|
let noise =
|
||||||
measure_noise_lwe(&lwe_out_ct, lwe_sk_out.values(), &modq_op, &encoded_m);
|
measure_noise_lwe(&lwe_out_ct, lwe_sk_out.values(), &modq_op, &encoded_m);
|
||||||
println!("Noise: {noise}");
|
println!("Noise: {noise}");
|
||||||
assert_eq!(m, m_back, "Expected {m} but got {m_back}");
|
// assert_eq!(m, m_back, "Expected {m} but got {m_back}");
|
||||||
// dbg!(m, m_back);
|
// dbg!(m, m_back);
|
||||||
// dbg!(encoded_m, encoded_m_back);
|
// dbg!(encoded_m, encoded_m_back);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ pub(crate) fn pbs<
|
|||||||
});
|
});
|
||||||
|
|
||||||
// key switch RLWE secret to LWE secret
|
// key switch RLWE secret to LWE secret
|
||||||
|
// let now = std::time::Instant::now();
|
||||||
scratch_lwe_vec.as_mut().fill(M::MatElement::zero());
|
scratch_lwe_vec.as_mut().fill(M::MatElement::zero());
|
||||||
lwe_key_switch(
|
lwe_key_switch(
|
||||||
scratch_lwe_vec,
|
scratch_lwe_vec,
|
||||||
@@ -120,6 +121,7 @@ pub(crate) fn pbs<
|
|||||||
pbs_info.modop_lweq(),
|
pbs_info.modop_lweq(),
|
||||||
pbs_info.lwe_decomposer(),
|
pbs_info.lwe_decomposer(),
|
||||||
);
|
);
|
||||||
|
// println!("Time: {:?}", now.elapsed());
|
||||||
|
|
||||||
// odd mowdown Q_ks -> q
|
// odd mowdown Q_ks -> q
|
||||||
let g_k_dlog_map = pbs_info.g_k_dlog_map();
|
let g_k_dlog_map = pbs_info.g_k_dlog_map();
|
||||||
|
|||||||
Reference in New Issue
Block a user