mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-09 15:41:30 +01:00
fix test vector to q/8
This commit is contained in:
@@ -2,9 +2,7 @@ use std::{
|
|||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
hash::Hash,
|
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
thread::panicking,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use itertools::{izip, partition, Itertools};
|
use itertools::{izip, partition, Itertools};
|
||||||
@@ -45,6 +43,7 @@ trait PbsKey {
|
|||||||
/// LWE ksk to key switch from RLWE secret to LWE secret
|
/// LWE ksk to key switch from RLWE secret to LWE secret
|
||||||
fn lwe_ksk(&self) -> &Self::M;
|
fn lwe_ksk(&self) -> &Self::M;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PbsParameters {
|
trait PbsParameters {
|
||||||
type Element;
|
type Element;
|
||||||
type D: Decomposer<Element = Self::Element>;
|
type D: Decomposer<Element = Self::Element>;
|
||||||
@@ -570,6 +569,7 @@ where
|
|||||||
embedding_factor: usize,
|
embedding_factor: usize,
|
||||||
nand_test_vec: M::R,
|
nand_test_vec: M::R,
|
||||||
rlweq_by8: M::MatElement,
|
rlweq_by8: M::MatElement,
|
||||||
|
rlwe_qby4: M::MatElement,
|
||||||
rlwe_auto_maps: Vec<(Vec<usize>, Vec<bool>)>,
|
rlwe_auto_maps: Vec<(Vec<usize>, Vec<bool>)>,
|
||||||
_phantom: PhantomData<M>,
|
_phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
@@ -582,7 +582,7 @@ where
|
|||||||
+ VectorOps<Element = M::MatElement>,
|
+ VectorOps<Element = M::MatElement>,
|
||||||
M::MatElement: PrimInt + Debug + Display + NumInfo + FromPrimitive + WrappingSub,
|
M::MatElement: PrimInt + Debug + Display + NumInfo + FromPrimitive + WrappingSub,
|
||||||
M: MatrixEntity + MatrixMut,
|
M: MatrixEntity + MatrixMut,
|
||||||
M::R: TryConvertFrom<[i32], Parameters = M::MatElement> + RowEntity,
|
M::R: TryConvertFrom<[i32], Parameters = M::MatElement> + RowEntity + Debug,
|
||||||
M: TryConvertFrom<[i32], Parameters = M::MatElement>,
|
M: TryConvertFrom<[i32], Parameters = M::MatElement>,
|
||||||
<M as Matrix>::R: RowMut,
|
<M as Matrix>::R: RowMut,
|
||||||
DefaultSecureRng: RandomGaussianDist<[M::MatElement], Parameters = M::MatElement>
|
DefaultSecureRng: RandomGaussianDist<[M::MatElement], Parameters = M::MatElement>
|
||||||
@@ -630,7 +630,6 @@ where
|
|||||||
let q = parameters.br_q;
|
let q = parameters.br_q;
|
||||||
let qby2 = q >> 1;
|
let qby2 = q >> 1;
|
||||||
let qby8 = q >> 3;
|
let qby8 = q >> 3;
|
||||||
let qby16 = q >> 4;
|
|
||||||
let mut nand_test_vec = M::R::zeros(qby2);
|
let mut nand_test_vec = M::R::zeros(qby2);
|
||||||
// Q/8 (Q: rlwe_q)
|
// Q/8 (Q: rlwe_q)
|
||||||
let rlwe_qby8 =
|
let rlwe_qby8 =
|
||||||
@@ -646,14 +645,14 @@ where
|
|||||||
nand_test_vec.as_mut()[i] = false_m_el;
|
nand_test_vec.as_mut()[i] = false_m_el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Rotate and negate by q/16
|
// // Rotate and negate by q/8
|
||||||
let mut tmp = M::R::zeros(qby2);
|
// let mut tmp = M::R::zeros(qby2);
|
||||||
tmp.as_mut()[..qby2 - qby16].copy_from_slice(&nand_test_vec.as_ref()[qby16..]);
|
// tmp.as_mut()[..qby2 - qby8].copy_from_slice(&nand_test_vec.as_ref()[qby8..]);
|
||||||
tmp.as_mut()[qby2 - qby16..].copy_from_slice(&nand_test_vec.as_ref()[..qby16]);
|
// tmp.as_mut()[qby2 - qby8..].copy_from_slice(&nand_test_vec.as_ref()[..qby8]);
|
||||||
tmp.as_mut()[qby2 - qby16..].iter_mut().for_each(|v| {
|
// tmp.as_mut()[qby2 - qby8..].iter_mut().for_each(|v| {
|
||||||
*v = parameters.rlwe_q - *v;
|
// *v = parameters.rlwe_q - *v;
|
||||||
});
|
// });
|
||||||
let nand_test_vec = tmp;
|
// let nand_test_vec = tmp;
|
||||||
|
|
||||||
// v(X) -> v(X^{-g})
|
// v(X) -> v(X^{-g})
|
||||||
let (auto_map_index, auto_map_sign) = generate_auto_map(qby2, -(g as isize));
|
let (auto_map_index, auto_map_sign) = generate_auto_map(qby2, -(g as isize));
|
||||||
@@ -680,6 +679,9 @@ where
|
|||||||
rlwe_auto_maps.push(generate_auto_map(ring_size, i))
|
rlwe_auto_maps.push(generate_auto_map(ring_size, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let rlwe_qby4 =
|
||||||
|
M::MatElement::from_f64((parameters.rlwe_q.to_f64().unwrap() / 4.0).round()).unwrap();
|
||||||
|
|
||||||
BoolEvaluator {
|
BoolEvaluator {
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
decomposer_lwe,
|
decomposer_lwe,
|
||||||
@@ -691,6 +693,7 @@ where
|
|||||||
rlwe_nttop,
|
rlwe_nttop,
|
||||||
nand_test_vec: nand_test_vec_autog,
|
nand_test_vec: nand_test_vec_autog,
|
||||||
rlweq_by8: rlwe_qby8,
|
rlweq_by8: rlwe_qby8,
|
||||||
|
rlwe_qby4: rlwe_qby4,
|
||||||
rlwe_auto_maps,
|
rlwe_auto_maps,
|
||||||
|
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
@@ -1116,8 +1119,11 @@ where
|
|||||||
// );
|
// );
|
||||||
// let c1_noise =
|
// let c1_noise =
|
||||||
// measure_noise_lwe(c1, ck.sk_rlwe.values(), &self.rlwe_modop,
|
// measure_noise_lwe(c1, ck.sk_rlwe.values(), &self.rlwe_modop,
|
||||||
// &(self.rlweq_by8)); println!("c0 noise: {c0_noise}; c1 noise:
|
// &(self.rlweq_by8)); println!(
|
||||||
// {c1_noise}"); });
|
// "c0 noise: {c0_noise}; c1 noise:
|
||||||
|
// {c1_noise}"
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
let mut c_out = M::R::zeros(c0.as_ref().len());
|
let mut c_out = M::R::zeros(c0.as_ref().len());
|
||||||
let modop = &self.rlwe_modop;
|
let modop = &self.rlwe_modop;
|
||||||
@@ -1130,7 +1136,7 @@ where
|
|||||||
*o = modop.add(i0, i1);
|
*o = modop.add(i0, i1);
|
||||||
});
|
});
|
||||||
// +Q/8
|
// +Q/8
|
||||||
c_out.as_mut()[0] = modop.add(&c_out.as_ref()[0], &self.rlweq_by8);
|
c_out.as_mut()[0] = modop.add(&c_out.as_ref()[0], &self.rlwe_qby4);
|
||||||
|
|
||||||
// ClientKey::with_local(|ck| {
|
// ClientKey::with_local(|ck| {
|
||||||
// let noise = measure_noise_lwe(
|
// let noise = measure_noise_lwe(
|
||||||
@@ -1364,6 +1370,15 @@ fn pbs<
|
|||||||
let br_qf64 = br_q.to_f64().unwrap();
|
let br_qf64 = br_q.to_f64().unwrap();
|
||||||
let rlwe_n = parameters.rlwe_n();
|
let rlwe_n = parameters.rlwe_n();
|
||||||
|
|
||||||
|
PBSTracer::with_local_mut(|t| {
|
||||||
|
let out = lwe_in
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_u64().unwrap())
|
||||||
|
.collect_vec();
|
||||||
|
t.ct_rlwe_q_mod = out;
|
||||||
|
});
|
||||||
|
|
||||||
// moddown Q -> Q_ks
|
// moddown Q -> Q_ks
|
||||||
lwe_in.as_mut().iter_mut().for_each(|v| {
|
lwe_in.as_mut().iter_mut().for_each(|v| {
|
||||||
*v =
|
*v =
|
||||||
@@ -1590,6 +1605,7 @@ struct PBSTracer<M>
|
|||||||
where
|
where
|
||||||
M: Matrix + Default,
|
M: Matrix + Default,
|
||||||
{
|
{
|
||||||
|
pub(crate) ct_rlwe_q_mod: M::R,
|
||||||
pub(crate) ct_lwe_q_mod: M::R,
|
pub(crate) ct_lwe_q_mod: M::R,
|
||||||
pub(crate) ct_lwe_q_mod_after_ksk: M::R,
|
pub(crate) ct_lwe_q_mod_after_ksk: M::R,
|
||||||
pub(crate) ct_br_q_mod: Vec<u64>,
|
pub(crate) ct_br_q_mod: Vec<u64>,
|
||||||
@@ -1600,21 +1616,26 @@ impl PBSTracer<Vec<Vec<u64>>> {
|
|||||||
assert!(parameters.rlwe_n == sk_rlwe.len());
|
assert!(parameters.rlwe_n == sk_rlwe.len());
|
||||||
assert!(parameters.lwe_n == sk_lwe.len());
|
assert!(parameters.lwe_n == sk_lwe.len());
|
||||||
|
|
||||||
|
let modop_rlweq = ModularOpsU64::new(parameters.rlwe_q as u64);
|
||||||
|
// noise after mod down Q -> Q_ks
|
||||||
|
let m_back0 = decrypt_lwe(&self.ct_rlwe_q_mod, sk_rlwe, &modop_rlweq);
|
||||||
|
|
||||||
let modop_lweq = ModularOpsU64::new(parameters.lwe_q as u64);
|
let modop_lweq = ModularOpsU64::new(parameters.lwe_q as u64);
|
||||||
// noise after mod down Q -> Q_ks
|
// noise after mod down Q -> Q_ks
|
||||||
let m_back0 = decrypt_lwe(&self.ct_lwe_q_mod, sk_rlwe, &modop_lweq);
|
let m_back1 = decrypt_lwe(&self.ct_lwe_q_mod, sk_rlwe, &modop_lweq);
|
||||||
// noise after key switch from RLWE -> LWE
|
// noise after key switch from RLWE -> LWE
|
||||||
let m_back1 = decrypt_lwe(&self.ct_lwe_q_mod_after_ksk, sk_lwe, &modop_lweq);
|
let m_back2 = decrypt_lwe(&self.ct_lwe_q_mod_after_ksk, sk_lwe, &modop_lweq);
|
||||||
|
|
||||||
// noise after mod down odd from Q_ks -> q
|
// noise after mod down odd from Q_ks -> q
|
||||||
let modop_br_q = ModularOpsU64::new(parameters.br_q as u64);
|
let modop_br_q = ModularOpsU64::new(parameters.br_q as u64);
|
||||||
let m_back2 = decrypt_lwe(&self.ct_br_q_mod, sk_lwe, &modop_br_q);
|
let m_back3 = decrypt_lwe(&self.ct_br_q_mod, sk_lwe, &modop_br_q);
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"
|
"
|
||||||
M after mod down Q -> Q_ks: {m_back0},
|
M initial mod Q: {m_back0},
|
||||||
M after key switch from RLWE -> LWE: {m_back1},
|
M after mod down Q -> Q_ks: {m_back1},
|
||||||
M after mod dwon Q_ks -> q: {m_back2}
|
M after key switch from RLWE -> LWE: {m_back2},
|
||||||
|
M after mod dwon Q_ks -> q: {m_back3}
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1639,6 +1660,7 @@ impl WithLocal for PBSTracer<Vec<Vec<u64>>> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
use rand_distr::Uniform;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::ModularOpsU64,
|
backend::ModularOpsU64,
|
||||||
@@ -1708,6 +1730,7 @@ mod tests {
|
|||||||
let mut m1 = true;
|
let mut m1 = true;
|
||||||
let mut ct0 = bool_evaluator.sk_encrypt(m0, &client_key);
|
let mut ct0 = bool_evaluator.sk_encrypt(m0, &client_key);
|
||||||
let mut ct1 = bool_evaluator.sk_encrypt(m1, &client_key);
|
let mut ct1 = bool_evaluator.sk_encrypt(m1, &client_key);
|
||||||
|
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let ct_back = bool_evaluator.nand(
|
let ct_back = bool_evaluator.nand(
|
||||||
&ct0,
|
&ct0,
|
||||||
@@ -1721,6 +1744,45 @@ mod tests {
|
|||||||
|
|
||||||
// Trace and measure PBS noise
|
// Trace and measure PBS noise
|
||||||
{
|
{
|
||||||
|
let noise0 = {
|
||||||
|
let ideal = if m0 {
|
||||||
|
bool_evaluator.rlweq_by8
|
||||||
|
} else {
|
||||||
|
bool_evaluator.rlwe_q() - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let n = measure_noise_lwe(
|
||||||
|
&ct0,
|
||||||
|
client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal,
|
||||||
|
);
|
||||||
|
let v = decrypt_lwe(
|
||||||
|
&ct0,
|
||||||
|
client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
);
|
||||||
|
(n, v)
|
||||||
|
};
|
||||||
|
let noise1 = {
|
||||||
|
let ideal = if m1 {
|
||||||
|
bool_evaluator.rlweq_by8
|
||||||
|
} else {
|
||||||
|
bool_evaluator.rlwe_q() - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let n = measure_noise_lwe(
|
||||||
|
&ct1,
|
||||||
|
client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal,
|
||||||
|
);
|
||||||
|
let v = decrypt_lwe(
|
||||||
|
&ct1,
|
||||||
|
client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
);
|
||||||
|
(n, v)
|
||||||
|
};
|
||||||
|
|
||||||
// Trace PBS
|
// Trace PBS
|
||||||
PBSTracer::with_local(|t| {
|
PBSTracer::with_local(|t| {
|
||||||
t.trace(
|
t.trace(
|
||||||
@@ -1731,21 +1793,32 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Calculate noise in ciphertext post PBS
|
// Calculate noise in ciphertext post PBS
|
||||||
let ideal = if m_out {
|
let noise_out = {
|
||||||
bool_evaluator.rlweq_by8
|
let ideal = if m_out {
|
||||||
} else {
|
bool_evaluator.rlweq_by8
|
||||||
bool_evaluator.rlwe_q() - bool_evaluator.rlweq_by8
|
} else {
|
||||||
|
bool_evaluator.rlwe_q() - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let n = measure_noise_lwe(
|
||||||
|
&ct_back,
|
||||||
|
client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal,
|
||||||
|
);
|
||||||
|
let v = decrypt_lwe(
|
||||||
|
&ct_back,
|
||||||
|
client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
);
|
||||||
|
(n, v)
|
||||||
};
|
};
|
||||||
let noise = measure_noise_lwe(
|
dbg!(m0, m1, m_out);
|
||||||
&ct_back,
|
println!(
|
||||||
client_key.sk_rlwe.values(),
|
"ct0 (noise, message): {:?} \n ct1 (noise, message): {:?} \n PBS (noise, message): {:?}", noise0, noise1, noise_out
|
||||||
&bool_evaluator.rlwe_modop,
|
|
||||||
&ideal,
|
|
||||||
);
|
);
|
||||||
println!("PBS noise: {noise}");
|
|
||||||
}
|
}
|
||||||
let m_back = bool_evaluator.sk_decrypt(&ct_back, &client_key);
|
let m_back = bool_evaluator.sk_decrypt(&ct_back, &client_key);
|
||||||
assert_eq!(m_out, m_back);
|
assert!(m_out == m_back, "Expected {m_out}, got {m_back}");
|
||||||
println!("----------");
|
println!("----------");
|
||||||
|
|
||||||
m1 = m0;
|
m1 = m0;
|
||||||
@@ -1761,7 +1834,7 @@ mod tests {
|
|||||||
let bool_evaluator =
|
let bool_evaluator =
|
||||||
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
||||||
|
|
||||||
let no_of_parties = 5;
|
let no_of_parties = 500;
|
||||||
let parties = (0..no_of_parties)
|
let parties = (0..no_of_parties)
|
||||||
.map(|_| bool_evaluator.client_key())
|
.map(|_| bool_evaluator.client_key())
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
@@ -1773,6 +1846,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
println!("{:?}", &ideal_rlwe_sk);
|
||||||
|
|
||||||
let mut m = true;
|
let mut m = true;
|
||||||
for i in 0..100 {
|
for i in 0..100 {
|
||||||
let pk_cr_seed = [0u8; 32];
|
let pk_cr_seed = [0u8; 32];
|
||||||
@@ -1814,18 +1889,68 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ms() {
|
||||||
|
let logbig_q = 50;
|
||||||
|
let logsmall_q = 20;
|
||||||
|
let big_q = 1 << logbig_q;
|
||||||
|
let small_q = 1 << logsmall_q;
|
||||||
|
let lwe_n = 493;
|
||||||
|
|
||||||
|
let no_of_parties = 10;
|
||||||
|
let parties_lwe_sk = (0..no_of_parties)
|
||||||
|
.map(|_| LweSecret::random(lwe_n >> 1, lwe_n))
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
// Ideal secrets
|
||||||
|
let mut ideal_lwe_sk = vec![0i32; lwe_n];
|
||||||
|
parties_lwe_sk.iter().for_each(|k| {
|
||||||
|
izip!(ideal_lwe_sk.iter_mut(), k.values()).for_each(|(ideal_i, s_i)| {
|
||||||
|
*ideal_i = *ideal_i + s_i;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut rng = DefaultSecureRng::new();
|
||||||
|
|
||||||
|
let logp = 3;
|
||||||
|
let modop_bigq = ModularOpsU64::new(big_q);
|
||||||
|
let modop_smallq = ModularOpsU64::new(small_q);
|
||||||
|
|
||||||
|
for i in 0..100 {
|
||||||
|
let m = thread_rng().sample(Uniform::new(0u64, (1u64 << logp)));
|
||||||
|
let bigq_m = m << (logbig_q - logp);
|
||||||
|
let smallq_m = m << (logsmall_q - logp);
|
||||||
|
|
||||||
|
// encrypt
|
||||||
|
let mut lwe_ct = vec![0u64; lwe_n + 1];
|
||||||
|
encrypt_lwe(&mut lwe_ct, &bigq_m, &ideal_lwe_sk, &modop_bigq, &mut rng);
|
||||||
|
|
||||||
|
let noise = measure_noise_lwe(&lwe_ct, &ideal_lwe_sk, &modop_bigq, &bigq_m);
|
||||||
|
println!("Noise Before: {noise}");
|
||||||
|
|
||||||
|
// mod switch
|
||||||
|
let lwe_ct_ms = lwe_ct
|
||||||
|
.iter()
|
||||||
|
.map(|v| (((*v as f64) * small_q as f64) / (big_q as f64)).round() as u64)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let noise = measure_noise_lwe(&lwe_ct_ms, &ideal_lwe_sk, &modop_smallq, &smallq_m);
|
||||||
|
println!("Noise After: {noise}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_party_lwe_keyswitch() {
|
fn multi_party_lwe_keyswitch() {
|
||||||
let lwe_logq = 18;
|
let lwe_logq = 18;
|
||||||
let lwe_q = 1 << lwe_logq;
|
let lwe_q = 1 << lwe_logq;
|
||||||
let d_lwe = 4;
|
let d_lwe = 1;
|
||||||
let logb_lwe = 4;
|
let logb_lwe = 6;
|
||||||
let lwe_gadgect_vec = gadget_vector(lwe_logq, logb_lwe, d_lwe);
|
let lwe_gadgect_vec = gadget_vector(lwe_logq, logb_lwe, d_lwe);
|
||||||
let lweq_modop = ModularOpsU64::new(lwe_q);
|
let lweq_modop = ModularOpsU64::new(lwe_q);
|
||||||
let logp = 2;
|
let logp = 2;
|
||||||
|
|
||||||
let from_lwe_n = 2048;
|
let from_lwe_n = 2048;
|
||||||
let to_lwe_n = 583;
|
let to_lwe_n = 500;
|
||||||
|
|
||||||
let no_of_parties = 10;
|
let no_of_parties = 10;
|
||||||
let parties_from_lwe_sk = (0..no_of_parties)
|
let parties_from_lwe_sk = (0..no_of_parties)
|
||||||
@@ -1835,12 +1960,26 @@ mod tests {
|
|||||||
.map(|_| LweSecret::random(to_lwe_n >> 1, to_lwe_n))
|
.map(|_| LweSecret::random(to_lwe_n >> 1, to_lwe_n))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
|
// Ideal secrets
|
||||||
|
let mut ideal_from_lwe_sk = vec![0i32; from_lwe_n];
|
||||||
|
parties_from_lwe_sk.iter().for_each(|k| {
|
||||||
|
izip!(ideal_from_lwe_sk.iter_mut(), k.values()).for_each(|(ideal_i, s_i)| {
|
||||||
|
*ideal_i = *ideal_i + s_i;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let mut ideal_to_lwe_sk = vec![0i32; to_lwe_n];
|
||||||
|
parties_to_lwe_sk.iter().for_each(|k| {
|
||||||
|
izip!(ideal_to_lwe_sk.iter_mut(), k.values()).for_each(|(ideal_i, s_i)| {
|
||||||
|
*ideal_i = *ideal_i + s_i;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Generate Lwe KSK share
|
// Generate Lwe KSK share
|
||||||
let mut rng = DefaultSecureRng::new();
|
let mut rng = DefaultSecureRng::new();
|
||||||
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 lwe_ksk_shares =
|
let lwe_ksk_shares = izip!(parties_from_lwe_sk.iter(), parties_to_lwe_sk.iter())
|
||||||
izip!(parties_from_lwe_sk.iter(), parties_to_lwe_sk.iter()).map(|(from_sk, to_sk)| {
|
.map(|(from_sk, to_sk)| {
|
||||||
let mut ksk_out = vec![0u64; from_lwe_n * d_lwe];
|
let mut ksk_out = vec![0u64; from_lwe_n * d_lwe];
|
||||||
let mut p_rng = DefaultSecureRng::new_seeded(ksk_seed);
|
let mut p_rng = DefaultSecureRng::new_seeded(ksk_seed);
|
||||||
lwe_ksk_keygen(
|
lwe_ksk_keygen(
|
||||||
@@ -1853,11 +1992,12 @@ mod tests {
|
|||||||
&mut rng,
|
&mut rng,
|
||||||
);
|
);
|
||||||
ksk_out
|
ksk_out
|
||||||
});
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
// Create collective LWE ksk
|
// Create collective LWE ksk
|
||||||
let mut sum_partb = vec![0u64; d_lwe * from_lwe_n];
|
let mut sum_partb = vec![0u64; d_lwe * from_lwe_n];
|
||||||
lwe_ksk_shares.for_each(|share| {
|
lwe_ksk_shares.iter().for_each(|share| {
|
||||||
lweq_modop.elwise_add_mut(sum_partb.as_mut_slice(), share.as_slice())
|
lweq_modop.elwise_add_mut(sum_partb.as_mut_slice(), share.as_slice())
|
||||||
});
|
});
|
||||||
let mut lwe_ksk = vec![vec![0u64; to_lwe_n + 1]; d_lwe * from_lwe_n];
|
let mut lwe_ksk = vec![vec![0u64; to_lwe_n + 1]; d_lwe * from_lwe_n];
|
||||||
@@ -1867,71 +2007,34 @@ mod tests {
|
|||||||
lwe_i[0] = *part_bi;
|
lwe_i[0] = *part_bi;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Collective pk
|
for i in 0..128 {
|
||||||
// let collective_pk = _collecitve_public_key_gen(
|
println!("############## ITERATION {i} ##############");
|
||||||
// lwe_q,
|
|
||||||
// &parties_from_lwe_sk
|
|
||||||
// .iter()
|
|
||||||
// .map(|s| RlweSecret {
|
|
||||||
// values: s.values.clone(),
|
|
||||||
// })
|
|
||||||
// .collect_vec(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Encrypt m as LWE ciphertext
|
// Encrypt m
|
||||||
// let m = 1;
|
let m = 1;
|
||||||
// let lwe_ct = {
|
let mut lwe_ct = vec![0u64; from_lwe_n + 1];
|
||||||
// let nttop = NttBackendU64::new(lwe_q, from_lwe_n);
|
encrypt_lwe(&mut lwe_ct, &m, &ideal_from_lwe_sk, &lweq_modop, &mut rng);
|
||||||
// let modop = ModularOpsU64::new(lwe_q);
|
|
||||||
// let mut rlwe_out = vec![vec![0u64]; from_lwe_n];
|
|
||||||
// let mut m_vec = vec![0u64; from_lwe_n];
|
|
||||||
// m_vec[0] = m;
|
|
||||||
// public_key_encrypt_rlwe(
|
|
||||||
// &mut rlwe_out,
|
|
||||||
// &collective_pk,
|
|
||||||
// &m_vec,
|
|
||||||
// &modop,
|
|
||||||
// &nttop,
|
|
||||||
// &mut rng,
|
|
||||||
// );
|
|
||||||
// let mut lwe_ct = vec![0u64; from_lwe_n + 1];
|
|
||||||
// sample_extract(&mut lwe_ct, &rlwe_out, &modop, 0);
|
|
||||||
// lwe_ct
|
|
||||||
// };
|
|
||||||
// Encrypt m
|
|
||||||
let m = 1;
|
|
||||||
let mut ideal_from_lwe_sk = vec![0i32; from_lwe_n];
|
|
||||||
parties_from_lwe_sk.iter().for_each(|k| {
|
|
||||||
izip!(ideal_from_lwe_sk.iter_mut(), k.values()).for_each(|(ideal_i, s_i)| {
|
|
||||||
*ideal_i = *ideal_i + s_i;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
let mut lwe_ct = vec![0u64; from_lwe_n + 1];
|
|
||||||
encrypt_lwe(&mut lwe_ct, &m, &ideal_from_lwe_sk, &lweq_modop, &mut rng);
|
|
||||||
|
|
||||||
// Key switch
|
let noise = measure_noise_lwe(&lwe_ct, &ideal_from_lwe_sk, &lweq_modop, &m);
|
||||||
let lwe_ct_key_switched = {
|
println!("Noise before key switch: {noise}");
|
||||||
let mut lwe_ct_key_switched = vec![0u64; to_lwe_n + 1];
|
|
||||||
let decomposer = DefaultDecomposer::new(lwe_q, logb_lwe, d_lwe);
|
|
||||||
lwe_key_switch(
|
|
||||||
&mut lwe_ct_key_switched,
|
|
||||||
&lwe_ct,
|
|
||||||
&lwe_ksk,
|
|
||||||
&lweq_modop,
|
|
||||||
&decomposer,
|
|
||||||
);
|
|
||||||
lwe_ct_key_switched
|
|
||||||
};
|
|
||||||
|
|
||||||
// Measure noise
|
// Key switch
|
||||||
let mut ideal_to_lwe_sk = vec![0i32; to_lwe_n];
|
let lwe_ct_key_switched = {
|
||||||
parties_to_lwe_sk.iter().for_each(|k| {
|
let mut lwe_ct_key_switched = vec![0u64; to_lwe_n + 1];
|
||||||
izip!(ideal_to_lwe_sk.iter_mut(), k.values()).for_each(|(ideal_i, s_i)| {
|
let decomposer = DefaultDecomposer::new(lwe_q, logb_lwe, d_lwe);
|
||||||
*ideal_i = *ideal_i + s_i;
|
lwe_key_switch(
|
||||||
});
|
&mut lwe_ct_key_switched,
|
||||||
});
|
&lwe_ct,
|
||||||
let noise = measure_noise_lwe(&lwe_ct_key_switched, &ideal_to_lwe_sk, &lweq_modop, &m);
|
&lwe_ksk,
|
||||||
println!("Noise: {noise}");
|
&lweq_modop,
|
||||||
|
&decomposer,
|
||||||
|
);
|
||||||
|
lwe_ct_key_switched
|
||||||
|
};
|
||||||
|
|
||||||
|
let noise = measure_noise_lwe(&lwe_ct_key_switched, &ideal_to_lwe_sk, &lweq_modop, &m);
|
||||||
|
println!("Noise after key switch: {noise}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _collecitve_public_key_gen(rlwe_q: u64, parties_rlwe_sk: &[RlweSecret]) -> Vec<Vec<u64>> {
|
fn _collecitve_public_key_gen(rlwe_q: u64, parties_rlwe_sk: &[RlweSecret]) -> Vec<Vec<u64>> {
|
||||||
@@ -1966,7 +2069,7 @@ mod tests {
|
|||||||
vec![pk_part_a, pk_part_b]
|
vec![pk_part_a, pk_part_b]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _multi_party_keygen(
|
fn _multi_party_all_keygen(
|
||||||
bool_evaluator: &BoolEvaluator<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>,
|
bool_evaluator: &BoolEvaluator<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>,
|
||||||
no_of_parties: usize,
|
no_of_parties: usize,
|
||||||
) -> (
|
) -> (
|
||||||
@@ -2053,7 +2156,7 @@ mod tests {
|
|||||||
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
||||||
|
|
||||||
let (_, collective_pk, _, _, server_key_eval, ideal_client_key) =
|
let (_, collective_pk, _, _, server_key_eval, ideal_client_key) =
|
||||||
_multi_party_keygen(&bool_evaluator, 2);
|
_multi_party_all_keygen(&bool_evaluator, 20);
|
||||||
|
|
||||||
let lwe_q = bool_evaluator.parameters.lwe_q;
|
let lwe_q = bool_evaluator.parameters.lwe_q;
|
||||||
let rlwe_q = bool_evaluator.parameters.rlwe_q;
|
let rlwe_q = bool_evaluator.parameters.rlwe_q;
|
||||||
@@ -2067,7 +2170,7 @@ mod tests {
|
|||||||
let rlwe_decomposer = &bool_evaluator.decomposer_rlwe;
|
let rlwe_decomposer = &bool_evaluator.decomposer_rlwe;
|
||||||
|
|
||||||
// test LWE ksk from RLWE -> LWE
|
// test LWE ksk from RLWE -> LWE
|
||||||
if true {
|
if false {
|
||||||
let logp = 2;
|
let logp = 2;
|
||||||
let mut rng = DefaultSecureRng::new();
|
let mut rng = DefaultSecureRng::new();
|
||||||
|
|
||||||
@@ -2111,7 +2214,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Measure noise in RGSW ciphertexts of ideal LWE secrets
|
// Measure noise in RGSW ciphertexts of ideal LWE secrets
|
||||||
if false {
|
if true {
|
||||||
let gadget_vec = gadget_vector(
|
let gadget_vec = gadget_vector(
|
||||||
bool_evaluator.parameters.rlwe_logq,
|
bool_evaluator.parameters.rlwe_logq,
|
||||||
bool_evaluator.parameters.logb_rgsw,
|
bool_evaluator.parameters.logb_rgsw,
|
||||||
@@ -2147,7 +2250,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// measure noise grwoth in RLWExRGSW
|
// measure noise grwoth in RLWExRGSW
|
||||||
if false {
|
if true {
|
||||||
let mut rng = DefaultSecureRng::new();
|
let mut rng = DefaultSecureRng::new();
|
||||||
let mut carry_m = vec![0u64; rlwe_n];
|
let mut carry_m = vec![0u64; rlwe_n];
|
||||||
RandomUniformDist::random_fill(&mut rng, &rlwe_q, carry_m.as_mut_slice());
|
RandomUniformDist::random_fill(&mut rng, &rlwe_q, carry_m.as_mut_slice());
|
||||||
@@ -2160,7 +2263,7 @@ mod tests {
|
|||||||
let mul_mod =
|
let mul_mod =
|
||||||
|v0: &u64, v1: &u64| (((*v0 as u128 * *v1 as u128) % (rlwe_q as u128)) as u64);
|
|v0: &u64, v1: &u64| (((*v0 as u128 * *v1 as u128) % (rlwe_q as u128)) as u64);
|
||||||
|
|
||||||
for i in 0..450 {
|
for i in 0..bool_evaluator.parameters.lwe_n {
|
||||||
rlwe_by_rgsw(
|
rlwe_by_rgsw(
|
||||||
&mut rlwe_ct,
|
&mut rlwe_ct,
|
||||||
server_key_eval.rgsw_ct_lwe_si(i),
|
server_key_eval.rgsw_ct_lwe_si(i),
|
||||||
@@ -2257,60 +2360,8 @@ mod tests {
|
|||||||
let bool_evaluator =
|
let bool_evaluator =
|
||||||
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
||||||
|
|
||||||
let no_of_parties = 20;
|
let (parties, collective_pk, _, _, server_key_eval, ideal_client_key) =
|
||||||
let parties = (0..no_of_parties)
|
_multi_party_all_keygen(&bool_evaluator, 50);
|
||||||
.map(|_| bool_evaluator.client_key())
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
// Collective public key
|
|
||||||
let pk_cr_seed = [0u8; 32];
|
|
||||||
let public_key_share = parties
|
|
||||||
.iter()
|
|
||||||
.map(|k| bool_evaluator.multi_party_public_key_share(pk_cr_seed, k))
|
|
||||||
.collect_vec();
|
|
||||||
let collective_pk = PublicKey::<Vec<Vec<u64>>, DefaultSecureRng, ModularOpsU64>::from(
|
|
||||||
public_key_share.as_slice(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Server key
|
|
||||||
let pbs_cr_seed = [1u8; 32];
|
|
||||||
let server_key_shares = parties
|
|
||||||
.iter()
|
|
||||||
.map(|k| bool_evaluator.multi_party_sever_key_share(pbs_cr_seed, &collective_pk.key, k))
|
|
||||||
.collect_vec();
|
|
||||||
let seeded_server_key =
|
|
||||||
aggregate_multi_party_server_key_shares::<_, _, _, ModularOpsU64, NttBackendU64>(
|
|
||||||
&server_key_shares,
|
|
||||||
&bool_evaluator.decomposer_rlwe,
|
|
||||||
);
|
|
||||||
let server_key_eval = ServerKeyEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
|
|
||||||
&seeded_server_key,
|
|
||||||
);
|
|
||||||
|
|
||||||
// construct ideal rlwe sk for meauring noise
|
|
||||||
let ideal_client_key = {
|
|
||||||
let mut ideal_rlwe_sk = vec![0i32; bool_evaluator.rlwe_n()];
|
|
||||||
parties.iter().for_each(|k| {
|
|
||||||
izip!(ideal_rlwe_sk.iter_mut(), k.sk_rlwe.values()).for_each(|(ideal_i, s_i)| {
|
|
||||||
*ideal_i = *ideal_i + s_i;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
let mut ideal_lwe_sk = vec![0i32; bool_evaluator.lwe_n()];
|
|
||||||
parties.iter().for_each(|k| {
|
|
||||||
izip!(ideal_lwe_sk.iter_mut(), k.sk_lwe.values()).for_each(|(ideal_i, s_i)| {
|
|
||||||
*ideal_i = *ideal_i + s_i;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ClientKey {
|
|
||||||
sk_lwe: LweSecret {
|
|
||||||
values: ideal_lwe_sk,
|
|
||||||
},
|
|
||||||
sk_rlwe: RlweSecret {
|
|
||||||
values: ideal_rlwe_sk,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// PBS
|
// PBS
|
||||||
let mut scratch_lwen_plus1 = vec![0u64; bool_evaluator.parameters.lwe_n + 1];
|
let mut scratch_lwen_plus1 = vec![0u64; bool_evaluator.parameters.lwe_n + 1];
|
||||||
@@ -2322,10 +2373,10 @@ mod tests {
|
|||||||
let mut m0 = true;
|
let mut m0 = true;
|
||||||
let mut m1 = false;
|
let mut m1 = false;
|
||||||
|
|
||||||
for _ in 0..500 {
|
let mut lwe0 = bool_evaluator.pk_encrypt(&collective_pk.key, m0);
|
||||||
let lwe0 = bool_evaluator.pk_encrypt(&collective_pk.key, m0);
|
let mut lwe1 = bool_evaluator.pk_encrypt(&collective_pk.key, m1);
|
||||||
let lwe1 = bool_evaluator.pk_encrypt(&collective_pk.key, m1);
|
|
||||||
|
|
||||||
|
for _ in 0..2000 {
|
||||||
let lwe_out = bool_evaluator.nand(
|
let lwe_out = bool_evaluator.nand(
|
||||||
&lwe0,
|
&lwe0,
|
||||||
&lwe1,
|
&lwe1,
|
||||||
@@ -2338,6 +2389,45 @@ mod tests {
|
|||||||
|
|
||||||
// measure noise
|
// measure noise
|
||||||
{
|
{
|
||||||
|
let noise0 = {
|
||||||
|
let ideal = if m0 {
|
||||||
|
bool_evaluator.rlweq_by8
|
||||||
|
} else {
|
||||||
|
bool_evaluator.rlwe_q() - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let n = measure_noise_lwe(
|
||||||
|
&lwe0,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal,
|
||||||
|
);
|
||||||
|
let v = decrypt_lwe(
|
||||||
|
&lwe0,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
);
|
||||||
|
(n, v)
|
||||||
|
};
|
||||||
|
let noise1 = {
|
||||||
|
let ideal = if m1 {
|
||||||
|
bool_evaluator.rlweq_by8
|
||||||
|
} else {
|
||||||
|
bool_evaluator.rlwe_q() - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let n = measure_noise_lwe(
|
||||||
|
&lwe1,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal,
|
||||||
|
);
|
||||||
|
let v = decrypt_lwe(
|
||||||
|
&lwe1,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
);
|
||||||
|
(n, v)
|
||||||
|
};
|
||||||
|
|
||||||
// Trace PBS
|
// Trace PBS
|
||||||
PBSTracer::with_local(|t| {
|
PBSTracer::with_local(|t| {
|
||||||
t.trace(
|
t.trace(
|
||||||
@@ -2347,18 +2437,29 @@ mod tests {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let ideal_m = if m_expected {
|
let noise_out = {
|
||||||
bool_evaluator.rlweq_by8
|
let ideal_m = if m_expected {
|
||||||
} else {
|
bool_evaluator.rlweq_by8
|
||||||
bool_evaluator.parameters.rlwe_q - bool_evaluator.rlweq_by8
|
} else {
|
||||||
|
bool_evaluator.parameters.rlwe_q - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let n = measure_noise_lwe(
|
||||||
|
&lwe_out,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal_m,
|
||||||
|
);
|
||||||
|
let v = decrypt_lwe(
|
||||||
|
&lwe_out,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
);
|
||||||
|
(n, v)
|
||||||
};
|
};
|
||||||
let noise = measure_noise_lwe(
|
dbg!(m0, m1, m_expected);
|
||||||
&lwe_out,
|
println!(
|
||||||
ideal_client_key.sk_rlwe.values(),
|
"ct0 (noise, message): {:?} \n ct1 (noise, message): {:?} \n PBS (noise, message): {:?}", noise0, noise1, noise_out
|
||||||
&bool_evaluator.rlwe_modop,
|
|
||||||
&ideal_m,
|
|
||||||
);
|
);
|
||||||
println!("Noise: {noise}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// multi-party decrypt
|
// multi-party decrypt
|
||||||
@@ -2373,6 +2474,9 @@ mod tests {
|
|||||||
assert!(m_expected == m_back, "Expected {m_expected}, got {m_back}");
|
assert!(m_expected == m_back, "Expected {m_expected}, got {m_back}");
|
||||||
m1 = m0;
|
m1 = m0;
|
||||||
m0 = m_expected;
|
m0 = m_expected;
|
||||||
|
|
||||||
|
lwe1 = lwe0;
|
||||||
|
lwe0 = lwe_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,17 +38,16 @@ pub(super) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub(super) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
|
pub(super) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
|
||||||
rlwe_q: 18014398509404161,
|
rlwe_q: 1152921504606830593,
|
||||||
rlwe_logq: 54,
|
rlwe_logq: 60,
|
||||||
lwe_q: 1 << 18,
|
lwe_q: 1 << 20,
|
||||||
lwe_logq: 18,
|
lwe_logq: 20,
|
||||||
// TODO(Jay:) why does this fail when q=1<<11?
|
|
||||||
br_q: 1 << 11,
|
br_q: 1 << 11,
|
||||||
rlwe_n: 1 << 11,
|
rlwe_n: 1 << 11,
|
||||||
lwe_n: 200,
|
lwe_n: 500,
|
||||||
d_rgsw: 5,
|
d_rgsw: 4,
|
||||||
logb_rgsw: 10,
|
logb_rgsw: 12,
|
||||||
d_lwe: 4,
|
d_lwe: 5,
|
||||||
logb_lwe: 4,
|
logb_lwe: 4,
|
||||||
g: 5,
|
g: 5,
|
||||||
w: 1,
|
w: 1,
|
||||||
@@ -60,7 +59,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn find_prime() {
|
fn find_prime() {
|
||||||
let bits = 54;
|
let bits = 61;
|
||||||
let ring_size = 1 << 11;
|
let ring_size = 1 << 11;
|
||||||
let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
|
let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
|
||||||
dbg!(prime);
|
dbg!(prime);
|
||||||
|
|||||||
@@ -158,9 +158,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decomposition_works() {
|
fn decomposition_works() {
|
||||||
let logq = 60;
|
let logq = 55;
|
||||||
let logb = 5;
|
let logb = 9;
|
||||||
let d = 12;
|
let d = 6;
|
||||||
|
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let decomposer = DefaultDecomposer::new(q, logb, d);
|
let decomposer = DefaultDecomposer::new(q, logb, d);
|
||||||
let modq_op = ModularOpsU64::new(q);
|
let modq_op = ModularOpsU64::new(q);
|
||||||
for _ in 0..100 {
|
for _ in 0..1000 {
|
||||||
let value = rng.gen_range(0..q);
|
let value = rng.gen_range(0..q);
|
||||||
let limbs = decomposer.decompose(&value);
|
let limbs = decomposer.decompose(&value);
|
||||||
let value_back = decomposer.recompose(&limbs, &modq_op);
|
let value_back = decomposer.recompose(&limbs, &modq_op);
|
||||||
|
|||||||
@@ -176,8 +176,6 @@ pub fn lwe_ksk_keygen<
|
|||||||
b = operator.add(&b, &e);
|
b = operator.add(&b, &e);
|
||||||
|
|
||||||
*lwe_b = b;
|
*lwe_b = b;
|
||||||
|
|
||||||
// dbg!(&lwe.as_mut(), &f);
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -323,13 +321,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_switch_works() {
|
fn key_switch_works() {
|
||||||
let logq = 16;
|
let logq = 18;
|
||||||
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 = 493;
|
||||||
let d_ks = 3;
|
let d_ks = 3;
|
||||||
let logb = 4;
|
let logb = 6;
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ impl RandomGaussianDist<[u64]> for DefaultSecureRng {
|
|||||||
type Parameters = u64;
|
type Parameters = u64;
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
|
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u64]) {
|
||||||
izip!(
|
izip!(
|
||||||
rand_distr::Normal::new(0.0, 3.2f64)
|
rand_distr::Normal::new(0.0, 3.19f64)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.sample_iter(&mut self.rng),
|
.sample_iter(&mut self.rng),
|
||||||
container.iter_mut()
|
container.iter_mut()
|
||||||
@@ -162,7 +162,7 @@ impl RandomGaussianDist<[u32]> for DefaultSecureRng {
|
|||||||
type Parameters = u32;
|
type Parameters = u32;
|
||||||
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) {
|
fn random_fill(&mut self, parameters: &Self::Parameters, container: &mut [u32]) {
|
||||||
izip!(
|
izip!(
|
||||||
rand_distr::Normal::new(0.0, 3.2f32)
|
rand_distr::Normal::new(0.0, 3.19f32)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.sample_iter(&mut self.rng),
|
.sample_iter(&mut self.rng),
|
||||||
container.iter_mut()
|
container.iter_mut()
|
||||||
|
|||||||
352
src/rgsw.rs
352
src/rgsw.rs
@@ -463,130 +463,6 @@ pub(crate) fn generate_auto_map(ring_size: usize, k: isize) -> (Vec<usize>, Vec<
|
|||||||
(auto_map_index, auto_sign_index)
|
(auto_map_index, auto_sign_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates RLWE Key switching key to key switch ciphertext RLWE_{from_s}(m)
|
|
||||||
/// to RLWE_{to_s}(m).
|
|
||||||
///
|
|
||||||
/// Key switching equals
|
|
||||||
/// \sum decompose(c_1)_i * RLWE_{to_s}(\beta^i -from_s)
|
|
||||||
/// Hence, key switchin key equals RLWE'(-from_s) = RLWE(-from_s), RLWE(beta^1
|
|
||||||
/// -from_s), ..., RLWE(beta^{d-1} -from_s).
|
|
||||||
///
|
|
||||||
/// - ksk_out: Output Key switching key. Key switching key stores only part B
|
|
||||||
/// polynomials of ksk RLWE ciphertexts (i.e. RLWE'_B(-from_s)) in coefficient
|
|
||||||
/// domain
|
|
||||||
/// - neg_from_s: Negative of secret polynomial to key switch from
|
|
||||||
/// - to_s: secret polynomial to key switch to.
|
|
||||||
pub(crate) fn rlwe_ksk_gen<
|
|
||||||
Mmut: MatrixMut + MatrixEntity,
|
|
||||||
ModOp: ArithmeticOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>,
|
|
||||||
NttOp: Ntt<Element = Mmut::MatElement>,
|
|
||||||
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
|
||||||
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
|
||||||
>(
|
|
||||||
ksk_out: &mut Mmut,
|
|
||||||
neg_from_s: Mmut::R,
|
|
||||||
mut to_s: Mmut::R,
|
|
||||||
gadget_vector: &[Mmut::MatElement],
|
|
||||||
mod_op: &ModOp,
|
|
||||||
ntt_op: &NttOp,
|
|
||||||
p_rng: &mut PR,
|
|
||||||
rng: &mut R,
|
|
||||||
) where
|
|
||||||
<Mmut as Matrix>::R: RowMut,
|
|
||||||
{
|
|
||||||
let ring_size = neg_from_s.as_ref().len();
|
|
||||||
let d = gadget_vector.len();
|
|
||||||
assert!(ksk_out.dimension() == (d, ring_size));
|
|
||||||
|
|
||||||
let q = ArithmeticOps::modulus(mod_op);
|
|
||||||
|
|
||||||
ntt_op.forward(to_s.as_mut());
|
|
||||||
|
|
||||||
// RLWE'_{to_s}(-from_s)
|
|
||||||
let mut part_a = {
|
|
||||||
let mut a = Mmut::zeros(d, ring_size);
|
|
||||||
a.iter_rows_mut()
|
|
||||||
.for_each(|ai| RandomUniformDist::random_fill(p_rng, &q, ai.as_mut()));
|
|
||||||
a
|
|
||||||
};
|
|
||||||
izip!(
|
|
||||||
part_a.iter_rows_mut(),
|
|
||||||
ksk_out.iter_rows_mut(),
|
|
||||||
gadget_vector.iter(),
|
|
||||||
)
|
|
||||||
.for_each(|(ai, bi, beta_i)| {
|
|
||||||
// si * ai
|
|
||||||
ntt_op.forward(ai.as_mut());
|
|
||||||
mod_op.elwise_mul_mut(ai.as_mut(), to_s.as_ref());
|
|
||||||
ntt_op.backward(ai.as_mut());
|
|
||||||
|
|
||||||
// ei + to_s*ai
|
|
||||||
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
|
|
||||||
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
|
|
||||||
|
|
||||||
// beta_i * -from_s
|
|
||||||
// use ai as scratch space
|
|
||||||
mod_op.elwise_scalar_mul(ai.as_mut(), neg_from_s.as_ref(), beta_i);
|
|
||||||
|
|
||||||
// bi = ei + to_s*ai + beta_i*-from_s
|
|
||||||
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn galois_key_gen<
|
|
||||||
Mmut: MatrixMut + MatrixEntity,
|
|
||||||
ModOp: ArithmeticOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>,
|
|
||||||
NttOp: Ntt<Element = Mmut::MatElement>,
|
|
||||||
S,
|
|
||||||
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
|
||||||
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
|
||||||
>(
|
|
||||||
ksk_out: &mut Mmut,
|
|
||||||
s: &[S],
|
|
||||||
auto_k: isize,
|
|
||||||
gadget_vector: &[Mmut::MatElement],
|
|
||||||
mod_op: &ModOp,
|
|
||||||
ntt_op: &NttOp,
|
|
||||||
p_rng: &mut PR,
|
|
||||||
rng: &mut R,
|
|
||||||
) where
|
|
||||||
<Mmut as Matrix>::R: RowMut,
|
|
||||||
Mmut::R: TryConvertFrom<[S], Parameters = Mmut::MatElement> + RowEntity,
|
|
||||||
Mmut::MatElement: Copy + Sub<Output = Mmut::MatElement>,
|
|
||||||
{
|
|
||||||
let ring_size = s.len();
|
|
||||||
let (auto_map_index, auto_map_sign) = generate_auto_map(ring_size, auto_k);
|
|
||||||
|
|
||||||
let q = ArithmeticOps::modulus(mod_op);
|
|
||||||
|
|
||||||
// s(X) -> -s(X^k)
|
|
||||||
let s = Mmut::R::try_convert_from(s, &q);
|
|
||||||
let mut neg_s_auto = Mmut::R::zeros(s.as_ref().len());
|
|
||||||
izip!(s.as_ref(), auto_map_index.iter(), auto_map_sign.iter()).for_each(
|
|
||||||
|(el, to_index, sign)| {
|
|
||||||
// if sign is +ve (true), then negate because we need -s(X) (i.e. do the
|
|
||||||
// opposite than the usual case)
|
|
||||||
if *sign {
|
|
||||||
neg_s_auto.as_mut()[*to_index] = q - *el;
|
|
||||||
} else {
|
|
||||||
neg_s_auto.as_mut()[*to_index] = *el;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ksk from -s(X^k) to s(X)
|
|
||||||
rlwe_ksk_gen(
|
|
||||||
ksk_out,
|
|
||||||
neg_s_auto,
|
|
||||||
s,
|
|
||||||
gadget_vector,
|
|
||||||
mod_op,
|
|
||||||
ntt_op,
|
|
||||||
p_rng,
|
|
||||||
rng,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn routine<R: RowMut, ModOp: VectorOps<Element = R::Element>>(
|
pub(crate) fn routine<R: RowMut, ModOp: VectorOps<Element = R::Element>>(
|
||||||
write_to_row: &mut [R::Element],
|
write_to_row: &mut [R::Element],
|
||||||
matrix_a: &[R],
|
matrix_a: &[R],
|
||||||
@@ -958,8 +834,9 @@ pub(crate) fn secret_key_encrypt_rgsw<
|
|||||||
p_rng: &mut PR,
|
p_rng: &mut PR,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
<Mmut as Matrix>::R: RowMut + RowEntity + TryConvertFrom<[S], Parameters = Mmut::MatElement>,
|
<Mmut as Matrix>::R:
|
||||||
Mmut::MatElement: Copy,
|
RowMut + RowEntity + TryConvertFrom<[S], Parameters = Mmut::MatElement> + Debug,
|
||||||
|
Mmut::MatElement: Copy + Debug,
|
||||||
{
|
{
|
||||||
let d = gadget_vector.len();
|
let d = gadget_vector.len();
|
||||||
let q = mod_op.modulus();
|
let q = mod_op.modulus();
|
||||||
@@ -1149,6 +1026,130 @@ pub(crate) fn public_key_encrypt_rgsw<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates RLWE Key switching key to key switch ciphertext RLWE_{from_s}(m)
|
||||||
|
/// to RLWE_{to_s}(m).
|
||||||
|
///
|
||||||
|
/// Key switching equals
|
||||||
|
/// \sum decompose(c_1)_i * RLWE_{to_s}(\beta^i -from_s)
|
||||||
|
/// Hence, key switchin key equals RLWE'(-from_s) = RLWE(-from_s), RLWE(beta^1
|
||||||
|
/// -from_s), ..., RLWE(beta^{d-1} -from_s).
|
||||||
|
///
|
||||||
|
/// - ksk_out: Output Key switching key. Key switching key stores only part B
|
||||||
|
/// polynomials of ksk RLWE ciphertexts (i.e. RLWE'_B(-from_s)) in coefficient
|
||||||
|
/// domain
|
||||||
|
/// - neg_from_s: Negative of secret polynomial to key switch from
|
||||||
|
/// - to_s: secret polynomial to key switch to.
|
||||||
|
pub(crate) fn rlwe_ksk_gen<
|
||||||
|
Mmut: MatrixMut + MatrixEntity,
|
||||||
|
ModOp: ArithmeticOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>,
|
||||||
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
|
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
||||||
|
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
||||||
|
>(
|
||||||
|
ksk_out: &mut Mmut,
|
||||||
|
neg_from_s: Mmut::R,
|
||||||
|
mut to_s: Mmut::R,
|
||||||
|
gadget_vector: &[Mmut::MatElement],
|
||||||
|
mod_op: &ModOp,
|
||||||
|
ntt_op: &NttOp,
|
||||||
|
p_rng: &mut PR,
|
||||||
|
rng: &mut R,
|
||||||
|
) where
|
||||||
|
<Mmut as Matrix>::R: RowMut,
|
||||||
|
{
|
||||||
|
let ring_size = neg_from_s.as_ref().len();
|
||||||
|
let d = gadget_vector.len();
|
||||||
|
assert!(ksk_out.dimension() == (d, ring_size));
|
||||||
|
|
||||||
|
let q = ArithmeticOps::modulus(mod_op);
|
||||||
|
|
||||||
|
ntt_op.forward(to_s.as_mut());
|
||||||
|
|
||||||
|
// RLWE'_{to_s}(-from_s)
|
||||||
|
let mut part_a = {
|
||||||
|
let mut a = Mmut::zeros(d, ring_size);
|
||||||
|
a.iter_rows_mut()
|
||||||
|
.for_each(|ai| RandomUniformDist::random_fill(p_rng, &q, ai.as_mut()));
|
||||||
|
a
|
||||||
|
};
|
||||||
|
izip!(
|
||||||
|
part_a.iter_rows_mut(),
|
||||||
|
ksk_out.iter_rows_mut(),
|
||||||
|
gadget_vector.iter(),
|
||||||
|
)
|
||||||
|
.for_each(|(ai, bi, beta_i)| {
|
||||||
|
// si * ai
|
||||||
|
ntt_op.forward(ai.as_mut());
|
||||||
|
mod_op.elwise_mul_mut(ai.as_mut(), to_s.as_ref());
|
||||||
|
ntt_op.backward(ai.as_mut());
|
||||||
|
|
||||||
|
// ei + to_s*ai
|
||||||
|
RandomGaussianDist::random_fill(rng, &q, bi.as_mut());
|
||||||
|
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
|
||||||
|
|
||||||
|
// beta_i * -from_s
|
||||||
|
// use ai as scratch space
|
||||||
|
mod_op.elwise_scalar_mul(ai.as_mut(), neg_from_s.as_ref(), beta_i);
|
||||||
|
|
||||||
|
// bi = ei + to_s*ai + beta_i*-from_s
|
||||||
|
mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn galois_key_gen<
|
||||||
|
Mmut: MatrixMut + MatrixEntity,
|
||||||
|
ModOp: ArithmeticOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>,
|
||||||
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
|
S,
|
||||||
|
R: RandomGaussianDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
||||||
|
PR: RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
|
||||||
|
>(
|
||||||
|
ksk_out: &mut Mmut,
|
||||||
|
s: &[S],
|
||||||
|
auto_k: isize,
|
||||||
|
gadget_vector: &[Mmut::MatElement],
|
||||||
|
mod_op: &ModOp,
|
||||||
|
ntt_op: &NttOp,
|
||||||
|
p_rng: &mut PR,
|
||||||
|
rng: &mut R,
|
||||||
|
) where
|
||||||
|
<Mmut as Matrix>::R: RowMut,
|
||||||
|
Mmut::R: TryConvertFrom<[S], Parameters = Mmut::MatElement> + RowEntity,
|
||||||
|
Mmut::MatElement: Copy + Sub<Output = Mmut::MatElement>,
|
||||||
|
{
|
||||||
|
let ring_size = s.len();
|
||||||
|
let (auto_map_index, auto_map_sign) = generate_auto_map(ring_size, auto_k);
|
||||||
|
|
||||||
|
let q = ArithmeticOps::modulus(mod_op);
|
||||||
|
|
||||||
|
// s(X) -> -s(X^k)
|
||||||
|
let s = Mmut::R::try_convert_from(s, &q);
|
||||||
|
let mut neg_s_auto = Mmut::R::zeros(s.as_ref().len());
|
||||||
|
izip!(s.as_ref(), auto_map_index.iter(), auto_map_sign.iter()).for_each(
|
||||||
|
|(el, to_index, sign)| {
|
||||||
|
// if sign is +ve (true), then negate because we need -s(X) (i.e. do the
|
||||||
|
// opposite than the usual case)
|
||||||
|
if *sign {
|
||||||
|
neg_s_auto.as_mut()[*to_index] = q - *el;
|
||||||
|
} else {
|
||||||
|
neg_s_auto.as_mut()[*to_index] = *el;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ksk from -s(X^k) to s(X)
|
||||||
|
rlwe_ksk_gen(
|
||||||
|
ksk_out,
|
||||||
|
neg_s_auto,
|
||||||
|
s,
|
||||||
|
gadget_vector,
|
||||||
|
mod_op,
|
||||||
|
ntt_op,
|
||||||
|
p_rng,
|
||||||
|
rng,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Encrypt polynomial m(X) as RLWE ciphertext.
|
/// Encrypt polynomial m(X) as RLWE ciphertext.
|
||||||
///
|
///
|
||||||
/// - rlwe_out: returned RLWE ciphertext RLWE(m) in coefficient domain. RLWE
|
/// - rlwe_out: returned RLWE ciphertext RLWE(m) in coefficient domain. RLWE
|
||||||
@@ -1199,7 +1200,8 @@ pub(crate) fn secret_key_encrypt_rlwe<
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn public_key_encrypt_rlwe<
|
pub(crate) fn public_key_encrypt_rlwe<
|
||||||
M: MatrixMut,
|
M: Matrix,
|
||||||
|
Mmut: MatrixMut<MatElement = M::MatElement>,
|
||||||
ModOp: VectorOps<Element = M::MatElement>,
|
ModOp: VectorOps<Element = M::MatElement>,
|
||||||
NttOp: Ntt<Element = M::MatElement>,
|
NttOp: Ntt<Element = M::MatElement>,
|
||||||
S,
|
S,
|
||||||
@@ -1208,14 +1210,14 @@ pub(crate) fn public_key_encrypt_rlwe<
|
|||||||
+ RandomUniformDist<[u8], Parameters = u8>
|
+ RandomUniformDist<[u8], Parameters = u8>
|
||||||
+ RandomUniformDist<usize, Parameters = usize>,
|
+ RandomUniformDist<usize, Parameters = usize>,
|
||||||
>(
|
>(
|
||||||
rlwe_out: &mut M,
|
rlwe_out: &mut Mmut,
|
||||||
pk: &M,
|
pk: &M,
|
||||||
m: &[M::MatElement],
|
m: &[M::MatElement],
|
||||||
mod_op: &ModOp,
|
mod_op: &ModOp,
|
||||||
ntt_op: &NttOp,
|
ntt_op: &NttOp,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) where
|
) where
|
||||||
<M as Matrix>::R: RowMut + TryConvertFrom<[S], Parameters = M::MatElement> + RowEntity,
|
<Mmut as Matrix>::R: RowMut + TryConvertFrom<[S], Parameters = M::MatElement> + RowEntity,
|
||||||
M::MatElement: Copy,
|
M::MatElement: Copy,
|
||||||
S: Zero + Signed + Copy,
|
S: Zero + Signed + Copy,
|
||||||
{
|
{
|
||||||
@@ -1226,12 +1228,12 @@ pub(crate) fn public_key_encrypt_rlwe<
|
|||||||
|
|
||||||
let mut u = vec![S::zero(); ring_size];
|
let mut u = vec![S::zero(); ring_size];
|
||||||
fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
|
fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
|
||||||
let mut u = M::R::try_convert_from(&u, &q);
|
let mut u = Mmut::R::try_convert_from(&u, &q);
|
||||||
ntt_op.forward(u.as_mut());
|
ntt_op.forward(u.as_mut());
|
||||||
|
|
||||||
let mut ua = M::R::zeros(ring_size);
|
let mut ua = Mmut::R::zeros(ring_size);
|
||||||
ua.as_mut().copy_from_slice(pk.get_row_slice(0));
|
ua.as_mut().copy_from_slice(pk.get_row_slice(0));
|
||||||
let mut ub = M::R::zeros(ring_size);
|
let mut ub = Mmut::R::zeros(ring_size);
|
||||||
ub.as_mut().copy_from_slice(pk.get_row_slice(1));
|
ub.as_mut().copy_from_slice(pk.get_row_slice(1));
|
||||||
|
|
||||||
// a*u
|
// a*u
|
||||||
@@ -1419,8 +1421,9 @@ pub(crate) mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
decrypt_rlwe, galois_auto, galois_key_gen, generate_auto_map, rgsw_by_rgsw_inplace,
|
decrypt_rlwe, galois_auto, galois_key_gen, generate_auto_map, public_key_encrypt_rlwe,
|
||||||
rlwe_by_rgsw, secret_key_encrypt_rgsw, secret_key_encrypt_rlwe, RlweSecret,
|
rgsw_by_rgsw_inplace, rlwe_by_rgsw, secret_key_encrypt_rgsw, secret_key_encrypt_rlwe,
|
||||||
|
RlweSecret,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1477,6 +1480,9 @@ pub(crate) mod tests {
|
|||||||
.map(|v| (((*v as f64 * p as f64) / q as f64).round() as u64) % p)
|
.map(|v| (((*v as f64 * p as f64) / q as f64).round() as u64) % p)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
assert_eq!(m0, m_back);
|
assert_eq!(m0, m_back);
|
||||||
|
|
||||||
|
let noise = measure_noise(&rlwe_in_ct, &encoded_m, &ntt_op, &mod_op, s.values());
|
||||||
|
println!("Noise: {noise}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1642,11 +1648,11 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rlwe_by_rgsw_noise_growth() {
|
fn rlwe_by_rgsw_noise_growth() {
|
||||||
let logq = 60;
|
let logq = 28;
|
||||||
let ring_size = 1 << 11;
|
let ring_size = 1 << 10;
|
||||||
let q = generate_prime(logq, ring_size * 2, 1u64 << logq).unwrap();
|
let q = generate_prime(logq, ring_size * 2, 1u64 << logq).unwrap();
|
||||||
let d_rgsw = 7;
|
let d_rgsw = 2;
|
||||||
let logb = 8;
|
let logb = 7;
|
||||||
|
|
||||||
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
@@ -1685,6 +1691,7 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encrypt m as RGSW ciphertext RGSW(m) using supplied public key
|
||||||
fn _pk_encrypt_rgsw(
|
fn _pk_encrypt_rgsw(
|
||||||
m: &[u64],
|
m: &[u64],
|
||||||
public_key: &RlwePublicKey<Vec<Vec<u64>>, DefaultSecureRng>,
|
public_key: &RlwePublicKey<Vec<Vec<u64>>, DefaultSecureRng>,
|
||||||
@@ -1821,8 +1828,8 @@ pub(crate) mod tests {
|
|||||||
let ring_size = 1 << 11;
|
let ring_size = 1 << 11;
|
||||||
let q = generate_prime(logq, ring_size, 1u64 << logq).unwrap();
|
let q = generate_prime(logq, ring_size, 1u64 << logq).unwrap();
|
||||||
let p = 1u64 << logp;
|
let p = 1u64 << logp;
|
||||||
let d_rgsw = 15;
|
let d_rgsw = 3;
|
||||||
let logb = 4;
|
let logb = 15;
|
||||||
|
|
||||||
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
@@ -1832,6 +1839,8 @@ pub(crate) mod tests {
|
|||||||
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
||||||
let decomposer = DefaultDecomposer::new(q, logb, d_rgsw);
|
let decomposer = DefaultDecomposer::new(q, logb, d_rgsw);
|
||||||
|
|
||||||
|
let mul_mod = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % q as u128) as u64;
|
||||||
|
|
||||||
// Public Key
|
// Public Key
|
||||||
let public_key = {
|
let public_key = {
|
||||||
let mut pk_seed = [0u8; 32];
|
let mut pk_seed = [0u8; 32];
|
||||||
@@ -1856,11 +1865,23 @@ pub(crate) mod tests {
|
|||||||
// RGSW(carry_m)
|
// RGSW(carry_m)
|
||||||
let mut rgsw_carrym =
|
let mut rgsw_carrym =
|
||||||
_pk_encrypt_rgsw(&carry_m, &public_key, &gadget_vector, &mod_op, &ntt_op);
|
_pk_encrypt_rgsw(&carry_m, &public_key, &gadget_vector, &mod_op, &ntt_op);
|
||||||
|
// let mut rgsw_carrym = {
|
||||||
|
// let mut rgsw_eval =
|
||||||
|
// _sk_encrypt_rgsw(&carry_m, s.values(), &gadget_vector, &mod_op,
|
||||||
|
// &ntt_op); rgsw_eval
|
||||||
|
// .data
|
||||||
|
// .iter_mut()
|
||||||
|
// .for_each(|ri| ntt_op.backward(ri.as_mut()));
|
||||||
|
// rgsw_eval.data
|
||||||
|
// };
|
||||||
|
|
||||||
|
println!("########### Noise RGSW(carrym) at start ###########");
|
||||||
|
_measure_noise_rgsw(&rgsw_carrym.data, &carry_m, s.values(), &gadget_vector, q);
|
||||||
|
|
||||||
let mut scratch_matrix_d_plus_rgsw_by_ring =
|
let mut scratch_matrix_d_plus_rgsw_by_ring =
|
||||||
vec![vec![0u64; ring_size as usize]; d_rgsw + (d_rgsw * 4)];
|
vec![vec![0u64; ring_size as usize]; d_rgsw + (d_rgsw * 4)];
|
||||||
|
|
||||||
for i in 0..100 {
|
for i in 0..10 {
|
||||||
let mut m = vec![0u64; ring_size as usize];
|
let mut m = vec![0u64; ring_size as usize];
|
||||||
m[thread_rng().gen_range(0..ring_size) as usize] = q - 1;
|
m[thread_rng().gen_range(0..ring_size) as usize] = q - 1;
|
||||||
let rgsw_m = {
|
let rgsw_m = {
|
||||||
@@ -1879,22 +1900,54 @@ pub(crate) mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// measure noise
|
// measure noise
|
||||||
let mul_mod = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % q as u128) as u64;
|
|
||||||
carry_m = negacyclic_mul(&carry_m, &m, mul_mod, q);
|
carry_m = negacyclic_mul(&carry_m, &m, mul_mod, q);
|
||||||
println!("########### Noise RGSW(carrym) in {i}^th loop ###########");
|
println!("########### Noise RGSW(carrym) in {i}^th loop ###########");
|
||||||
_measure_noise_rgsw(&rgsw_carrym.data, &carry_m, s.values(), &gadget_vector, q);
|
_measure_noise_rgsw(&rgsw_carrym.data, &carry_m, s.values(), &gadget_vector, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// // RLWE(m) x RGSW(carry_m)
|
||||||
|
// let mut m = vec![0u64; ring_size as usize];
|
||||||
|
// RandomUniformDist::random_fill(&mut rng, &q, m.as_mut_slice());
|
||||||
|
// let mut rlwe_ct = RlweCiphertext::<_,
|
||||||
|
// DefaultSecureRng>::from_raw( vec![vec![0u64;
|
||||||
|
// ring_size as usize]; 2], false,
|
||||||
|
// );
|
||||||
|
// let mut scratch_matrix_dplus2_ring = vec![vec![0u64; ring_size as
|
||||||
|
// usize]; d_rgsw + 2]; public_key_encrypt_rlwe(
|
||||||
|
// &mut rlwe_ct,
|
||||||
|
// &public_key.data,
|
||||||
|
// &m,
|
||||||
|
// &mod_op,
|
||||||
|
// &ntt_op,
|
||||||
|
// &mut rng,
|
||||||
|
// );
|
||||||
|
// rlwe_by_rgsw(
|
||||||
|
// &mut rlwe_ct,
|
||||||
|
// &RgswCiphertextEvaluationDomain::<_, DefaultSecureRng,
|
||||||
|
// NttBackendU64>::from( &rgsw_carrym,
|
||||||
|
// )
|
||||||
|
// .data,
|
||||||
|
// &mut scratch_matrix_dplus2_ring,
|
||||||
|
// &decomposer,
|
||||||
|
// &ntt_op,
|
||||||
|
// &mod_op,
|
||||||
|
// );
|
||||||
|
// let m_expected = negacyclic_mul(&carry_m, &m, mul_mod, q);
|
||||||
|
// let noise = measure_noise(&rlwe_ct, &m_expected, &ntt_op,
|
||||||
|
// &mod_op, s.values()); println!("RLWE(m) x RGSW(carry_m):
|
||||||
|
// {noise}"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sk_rgsw_by_rgsw() {
|
fn sk_rgsw_by_rgsw() {
|
||||||
let logq = 31;
|
let logq = 60;
|
||||||
let logp = 2;
|
let logp = 2;
|
||||||
let ring_size = 1 << 10;
|
let ring_size = 1 << 11;
|
||||||
let q = generate_prime(logq, ring_size, 1u64 << logq).unwrap();
|
let q = generate_prime(logq, ring_size, 1u64 << logq).unwrap();
|
||||||
let p = 1u64 << logp;
|
let p = 1u64 << logp;
|
||||||
let d_rgsw = 4;
|
let d_rgsw = 3;
|
||||||
let logb = 7;
|
let logb = 15;
|
||||||
|
|
||||||
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
@@ -1918,11 +1971,13 @@ pub(crate) mod tests {
|
|||||||
.for_each(|ri| ntt_op.backward(ri.as_mut()));
|
.for_each(|ri| ntt_op.backward(ri.as_mut()));
|
||||||
rgsw_eval.data
|
rgsw_eval.data
|
||||||
};
|
};
|
||||||
|
println!("########### Noise RGSW(carrym) at start ###########");
|
||||||
|
_measure_noise_rgsw(&rgsw_carrym, &carry_m, s.values(), &gadget_vector, q);
|
||||||
|
|
||||||
let mut scratch_matrix_d_plus_rgsw_by_ring =
|
let mut scratch_matrix_d_plus_rgsw_by_ring =
|
||||||
vec![vec![0u64; ring_size as usize]; d_rgsw + (d_rgsw * 4)];
|
vec![vec![0u64; ring_size as usize]; d_rgsw + (d_rgsw * 4)];
|
||||||
|
|
||||||
for i in 0..1000 {
|
for i in 0..10 {
|
||||||
let mut m = vec![0u64; ring_size as usize];
|
let mut m = vec![0u64; ring_size as usize];
|
||||||
m[thread_rng().gen_range(0..ring_size) as usize] = if (i & 1) == 1 { q - 1 } else { 1 };
|
m[thread_rng().gen_range(0..ring_size) as usize] = if (i & 1) == 1 { q - 1 } else { 1 };
|
||||||
let rgsw_m = _sk_encrypt_rgsw(&m, s.values(), &gadget_vector, &mod_op, &ntt_op);
|
let rgsw_m = _sk_encrypt_rgsw(&m, s.values(), &gadget_vector, &mod_op, &ntt_op);
|
||||||
@@ -2057,9 +2112,6 @@ pub(crate) mod tests {
|
|||||||
println!("Ksk noise: {noise}");
|
println!("Ksk noise: {noise}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(Jay): Galios autormophism will incur high error unless we fix in
|
|
||||||
// accurate decomoposition of Decomposer when q is prime
|
|
||||||
assert_eq!(m_k_back, m_k);
|
assert_eq!(m_k_back, m_k);
|
||||||
// dbg!(m_k_back, m_k, q);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user