mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-08 23:21:29 +01:00
RLWExRGSW error grwoth behaves weird for primes > 30 bits
This commit is contained in:
@@ -756,7 +756,7 @@ where
|
|||||||
let mut rgsw_si = M::zeros(self.parameters.d_rgsw * 3, ring_size);
|
let mut rgsw_si = M::zeros(self.parameters.d_rgsw * 3, ring_size);
|
||||||
secret_key_encrypt_rgsw(
|
secret_key_encrypt_rgsw(
|
||||||
&mut rgsw_si,
|
&mut rgsw_si,
|
||||||
&m,
|
m.as_ref(),
|
||||||
&d_rgsw_gadget_vec,
|
&d_rgsw_gadget_vec,
|
||||||
sk_rlwe.values(),
|
sk_rlwe.values(),
|
||||||
&self.rlwe_modop,
|
&self.rlwe_modop,
|
||||||
@@ -1635,8 +1635,8 @@ mod tests {
|
|||||||
ntt::NttBackendU64,
|
ntt::NttBackendU64,
|
||||||
random::DEFAULT_RNG,
|
random::DEFAULT_RNG,
|
||||||
rgsw::{
|
rgsw::{
|
||||||
secret_key_encrypt_rlwe, RgswCiphertextEvaluationDomain, SeededRgswCiphertext,
|
self, measure_noise, secret_key_encrypt_rlwe, tests::_measure_noise_rgsw,
|
||||||
SeededRlweCiphertext,
|
RgswCiphertextEvaluationDomain, SeededRgswCiphertext, SeededRlweCiphertext,
|
||||||
},
|
},
|
||||||
utils::negacyclic_mul,
|
utils::negacyclic_mul,
|
||||||
};
|
};
|
||||||
@@ -1803,7 +1803,257 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trial_mp() {
|
fn mp_key_correcntess() {
|
||||||
|
let bool_evaluator =
|
||||||
|
BoolEvaluator::<Vec<Vec<u64>>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS);
|
||||||
|
|
||||||
|
let no_of_parties = 5;
|
||||||
|
let parties = (0..no_of_parties)
|
||||||
|
.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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// test LWE ksk from RLWE -> LWE
|
||||||
|
if false {
|
||||||
|
let lwe_q = bool_evaluator.parameters.lwe_q;
|
||||||
|
let lwe_logq = bool_evaluator.parameters.lwe_logq;
|
||||||
|
let lwe_n = bool_evaluator.parameters.lwe_n;
|
||||||
|
let rlwe_n = bool_evaluator.parameters.rlwe_n;
|
||||||
|
let logp = 2;
|
||||||
|
let lwe_modop = &bool_evaluator.lwe_modop;
|
||||||
|
let mut rng = DefaultSecureRng::new();
|
||||||
|
|
||||||
|
let m = 1;
|
||||||
|
let encoded_m = m << (lwe_logq - logp);
|
||||||
|
|
||||||
|
// Encrypt
|
||||||
|
let mut lwe_ct = vec![0u64; rlwe_n + 1];
|
||||||
|
encrypt_lwe(
|
||||||
|
&mut lwe_ct,
|
||||||
|
&encoded_m,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
lwe_modop,
|
||||||
|
&mut rng,
|
||||||
|
);
|
||||||
|
|
||||||
|
// key switch
|
||||||
|
let lwe_decomposer = &bool_evaluator.decomposer_lwe;
|
||||||
|
let mut lwe_out = vec![0u64; lwe_n + 1];
|
||||||
|
lwe_key_switch(
|
||||||
|
&mut lwe_out,
|
||||||
|
&lwe_ct,
|
||||||
|
&server_key_eval.lwe_ksk,
|
||||||
|
lwe_modop,
|
||||||
|
lwe_decomposer,
|
||||||
|
);
|
||||||
|
|
||||||
|
let encoded_m_back = decrypt_lwe(&lwe_out, ideal_client_key.sk_lwe.values(), lwe_modop);
|
||||||
|
let m_back =
|
||||||
|
((encoded_m_back as f64 * (1 << logp) as f64) / (lwe_q as f64)).round() as u64;
|
||||||
|
dbg!(m_back, m);
|
||||||
|
|
||||||
|
let noise = measure_noise_lwe(
|
||||||
|
&lwe_out,
|
||||||
|
ideal_client_key.sk_lwe.values(),
|
||||||
|
lwe_modop,
|
||||||
|
&encoded_m,
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("Noise: {noise}");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let rlwe_n = bool_evaluator.parameters.rlwe_n;
|
||||||
|
let rlwe_q = bool_evaluator.parameters.rlwe_q;
|
||||||
|
let gadget_vec = gadget_vector(
|
||||||
|
bool_evaluator.parameters.rlwe_logq,
|
||||||
|
bool_evaluator.parameters.logb_rgsw,
|
||||||
|
bool_evaluator.parameters.d_rgsw,
|
||||||
|
);
|
||||||
|
let rlwe_nttop = &bool_evaluator.rlwe_nttop;
|
||||||
|
|
||||||
|
for i in 0..20 {
|
||||||
|
// measure noise in RGSW(s[i])
|
||||||
|
let si = ideal_client_key.sk_lwe.values[i];
|
||||||
|
let mut si_poly = vec![0u64; rlwe_n];
|
||||||
|
if si < 0 {
|
||||||
|
si_poly[rlwe_n - (si.abs() as usize)] = rlwe_q - 1;
|
||||||
|
} else {
|
||||||
|
si_poly[(si.abs() as usize)] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rgsw_si = server_key_eval.rgsw_cts[i].clone();
|
||||||
|
rgsw_si
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|ri| rlwe_nttop.backward(ri.as_mut()));
|
||||||
|
|
||||||
|
println!("####### Noise in RGSW(X^s_{i}) #######");
|
||||||
|
let noise = _measure_noise_rgsw(
|
||||||
|
&rgsw_si,
|
||||||
|
&si_poly,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&gadget_vec,
|
||||||
|
rlwe_q,
|
||||||
|
);
|
||||||
|
println!("####### ##################### #######");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if false {
|
||||||
|
let rlwe_q = bool_evaluator.parameters.rlwe_q;
|
||||||
|
let rlwe_n = bool_evaluator.parameters.rlwe_n;
|
||||||
|
let logp = 3;
|
||||||
|
let p = 1 << logp;
|
||||||
|
let rlwe_modop = &bool_evaluator.rlwe_modop;
|
||||||
|
let rlwe_nttop = &bool_evaluator.rlwe_nttop;
|
||||||
|
let d_rgsw = bool_evaluator.parameters.d_rgsw;
|
||||||
|
|
||||||
|
let mut rng = DefaultSecureRng::new();
|
||||||
|
let mut m = vec![0u64; rlwe_n];
|
||||||
|
RandomUniformDist::random_fill(&mut rng, &p, m.as_mut_slice());
|
||||||
|
|
||||||
|
// Encode message m
|
||||||
|
let encoded_m = m
|
||||||
|
.iter()
|
||||||
|
.map(|el| ((*el as f64 * rlwe_q as f64) / (p as f64)).round() as u64)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
// Encrypt encoded m -> RLWE(m)
|
||||||
|
let mut rlwe_seed = [0u8; 32];
|
||||||
|
rng.fill_bytes(&mut rlwe_seed);
|
||||||
|
let mut seeded_rlwe_ct = SeededRlweCiphertext::empty(rlwe_n, rlwe_seed, rlwe_q);
|
||||||
|
let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
|
||||||
|
secret_key_encrypt_rlwe(
|
||||||
|
&encoded_m,
|
||||||
|
&mut seeded_rlwe_ct.data,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
rlwe_modop,
|
||||||
|
rlwe_nttop,
|
||||||
|
&mut rlwe_prng,
|
||||||
|
&mut rng,
|
||||||
|
);
|
||||||
|
// public_key_encrypt_rgsw(out_rgsw, m, public_key, gadget_vector, mod_op,
|
||||||
|
// ntt_op, rng);
|
||||||
|
let mut rlwe_ct =
|
||||||
|
RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_rlwe_ct);
|
||||||
|
|
||||||
|
for index in 0..200 {
|
||||||
|
// RLWE(m*X^{s[i]}) = RLWE(m) x RGSW(X^{s[i]})
|
||||||
|
let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n]; d_rgsw + 2];
|
||||||
|
let rlwe_decomposer = &bool_evaluator.decomposer_rlwe;
|
||||||
|
rlwe_by_rgsw(
|
||||||
|
&mut rlwe_ct,
|
||||||
|
server_key_eval.rgsw_ct_lwe_si(index),
|
||||||
|
// &rgsw_ct.data,
|
||||||
|
&mut scratch_matrix_dplus2_ring,
|
||||||
|
rlwe_decomposer,
|
||||||
|
rlwe_nttop,
|
||||||
|
rlwe_modop,
|
||||||
|
);
|
||||||
|
|
||||||
|
// decrypt RLWE(m*X^{s[i]}) to get encoded m[X]*X^{s[i]}
|
||||||
|
let mut encoded_m_back = vec![0u64; rlwe_n];
|
||||||
|
decrypt_rlwe(
|
||||||
|
&rlwe_ct,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&mut encoded_m_back,
|
||||||
|
rlwe_nttop,
|
||||||
|
rlwe_modop,
|
||||||
|
);
|
||||||
|
let m_back = encoded_m_back
|
||||||
|
.iter()
|
||||||
|
.map(|el| (((*el as f64 * p as f64) / (rlwe_q as f64)).round() as u64) % p)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
// calculate m[X]X^{s[i]} in plain
|
||||||
|
let mut si_poly = vec![0u64; rlwe_n];
|
||||||
|
// dbg!(ideal_client_key.sk_lwe.values());
|
||||||
|
let secret_el_i = ideal_client_key.sk_lwe.values[index];
|
||||||
|
dbg!(secret_el_i);
|
||||||
|
if secret_el_i < 0 {
|
||||||
|
si_poly[rlwe_n - secret_el_i.abs() as usize] = p - 1;
|
||||||
|
} else {
|
||||||
|
si_poly[secret_el_i.abs() as usize] = 1;
|
||||||
|
}
|
||||||
|
let mul = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % p as u128) as u64;
|
||||||
|
let expected_m = negacyclic_mul(&m, &si_poly, mul, p);
|
||||||
|
|
||||||
|
// measure noise
|
||||||
|
{
|
||||||
|
let encoded_m_ideal = expected_m
|
||||||
|
.iter()
|
||||||
|
.map(|el| ((*el as f64 * rlwe_q as f64) / (p as f64)).round() as u64)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let noise = measure_noise(
|
||||||
|
&rlwe_ct,
|
||||||
|
&encoded_m_ideal,
|
||||||
|
rlwe_nttop,
|
||||||
|
rlwe_modop,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
);
|
||||||
|
println!("Noise RLWE(m X^s_{index}) = RLWE(m) x RGSW(X^s_{index}): {noise}")
|
||||||
|
}
|
||||||
|
// println!("M:{:?}", m);
|
||||||
|
// assert_eq!(expected_m, m_back);
|
||||||
|
|
||||||
|
// println!("M_back:{:?} \n Expected_m:{:?}", m_back,
|
||||||
|
// expected_m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trial12() {
|
||||||
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);
|
||||||
|
|
||||||
@@ -1862,238 +2112,67 @@ mod tests {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// test LWE ksk from RLWE -> LWE
|
// PBS
|
||||||
// {
|
let mut scratch_lwen_plus1 = vec![0u64; bool_evaluator.parameters.lwe_n + 1];
|
||||||
// let lwe_q = bool_evaluator.parameters.lwe_q;
|
let mut scratch_matrix_dplus2_ring = vec![
|
||||||
// let lwe_logq = bool_evaluator.parameters.lwe_logq;
|
vec![0u64; bool_evaluator.parameters.rlwe_n];
|
||||||
// let lwe_n = bool_evaluator.parameters.lwe_n;
|
bool_evaluator.parameters.d_rgsw + 2
|
||||||
// let rlwe_n = bool_evaluator.parameters.rlwe_n;
|
];
|
||||||
// let logp = 2;
|
|
||||||
// let lwe_modop = &bool_evaluator.lwe_modop;
|
|
||||||
// let mut rng = DefaultSecureRng::new();
|
|
||||||
|
|
||||||
// let m = 1;
|
let mut m0 = true;
|
||||||
// let encoded_m = m << (lwe_logq - logp);
|
let mut m1 = false;
|
||||||
|
|
||||||
// // Encrypt
|
for _ in 0..100 {
|
||||||
// let mut lwe_ct = vec![0u64; rlwe_n + 1];
|
let lwe0 = bool_evaluator.pk_encrypt(&collective_pk.key, m0);
|
||||||
// encrypt_lwe(
|
let lwe1 = bool_evaluator.pk_encrypt(&collective_pk.key, m1);
|
||||||
// &mut lwe_ct,
|
|
||||||
// &encoded_m,
|
|
||||||
// ideal_client_key.sk_rlwe.values(),
|
|
||||||
// lwe_modop,
|
|
||||||
// &mut rng,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // key switch
|
let lwe_out = bool_evaluator.nand(
|
||||||
// let lwe_decomposer = &bool_evaluator.decomposer_lwe;
|
&lwe0,
|
||||||
// let mut lwe_out = vec![0u64; lwe_n + 1];
|
&lwe1,
|
||||||
// lwe_key_switch(
|
&server_key_eval,
|
||||||
// &mut lwe_out,
|
&mut scratch_lwen_plus1,
|
||||||
// &lwe_ct,
|
|
||||||
// &server_key_eval.lwe_ksk,
|
|
||||||
// lwe_modop,
|
|
||||||
// lwe_decomposer,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let encoded_m_back = decrypt_lwe(&lwe_out,
|
|
||||||
// ideal_client_key.sk_lwe.values(), lwe_modop); let m_back =
|
|
||||||
// ((encoded_m_back as f64 * (1 << logp) as f64) / (lwe_q as
|
|
||||||
// f64)).round() as u64; dbg!(m_back, m);
|
|
||||||
|
|
||||||
// let noise = measure_noise_lwe(
|
|
||||||
// &lwe_out,
|
|
||||||
// ideal_client_key.sk_lwe.values(),
|
|
||||||
// lwe_modop,
|
|
||||||
// &encoded_m,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// println!("Noise: {noise}");
|
|
||||||
// }
|
|
||||||
|
|
||||||
{
|
|
||||||
let rlwe_q = bool_evaluator.parameters.rlwe_q;
|
|
||||||
let rlwe_n = bool_evaluator.parameters.rlwe_n;
|
|
||||||
let logp = 2;
|
|
||||||
let p = 1 << logp;
|
|
||||||
let rlwe_modop = &bool_evaluator.rlwe_modop;
|
|
||||||
let rlwe_nttop = &bool_evaluator.rlwe_nttop;
|
|
||||||
let d_rgsw = bool_evaluator.parameters.d_rgsw;
|
|
||||||
|
|
||||||
let mut rng = DefaultSecureRng::new();
|
|
||||||
let mut m = vec![0u64; rlwe_n];
|
|
||||||
RandomUniformDist::random_fill(&mut rng, &p, m.as_mut_slice());
|
|
||||||
|
|
||||||
// Encode message m
|
|
||||||
let encoded_m = m
|
|
||||||
.iter()
|
|
||||||
.map(|el| ((*el as f64 * rlwe_q as f64) / (p as f64)).round() as u64)
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
// Encrypt encoded m -> RLWE(m)
|
|
||||||
let mut rlwe_seed = [0u8; 32];
|
|
||||||
rng.fill_bytes(&mut rlwe_seed);
|
|
||||||
let mut seeded_rlwe_ct = SeededRlweCiphertext::empty(rlwe_n, rlwe_seed, rlwe_q);
|
|
||||||
let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
|
|
||||||
secret_key_encrypt_rlwe(
|
|
||||||
&encoded_m,
|
|
||||||
&mut seeded_rlwe_ct.data,
|
|
||||||
ideal_client_key.sk_rlwe.values(),
|
|
||||||
rlwe_modop,
|
|
||||||
rlwe_nttop,
|
|
||||||
&mut rlwe_prng,
|
|
||||||
&mut rng,
|
|
||||||
);
|
|
||||||
// public_key_encrypt_rgsw(out_rgsw, m, public_key, gadget_vector, mod_op,
|
|
||||||
// ntt_op, rng)
|
|
||||||
let mut rlwe_ct =
|
|
||||||
RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_rlwe_ct);
|
|
||||||
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
let mut rgsw_ct = {
|
|
||||||
let rgsw_seed = [0u8; 32];
|
|
||||||
let mut rgsw_prng = DefaultSecureRng::new_seeded(rgsw_seed);
|
|
||||||
let mut rgsw_ct = SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(
|
|
||||||
rlwe_n, d_rgsw, rgsw_seed, rlwe_q,
|
|
||||||
);
|
|
||||||
let mut si_poly = vec![0u64; rlwe_n];
|
|
||||||
// dbg!(ideal_client_key.sk_lwe.values());
|
|
||||||
let secret_el_i = ideal_client_key.sk_lwe.values[index];
|
|
||||||
dbg!(secret_el_i);
|
|
||||||
if secret_el_i < 0 {
|
|
||||||
si_poly[rlwe_n - secret_el_i.abs() as usize] = rlwe_q - 1;
|
|
||||||
} else {
|
|
||||||
si_poly[secret_el_i.abs() as usize] = 1;
|
|
||||||
}
|
|
||||||
secret_key_encrypt_rgsw(
|
|
||||||
&mut rgsw_ct.data,
|
|
||||||
&si_poly,
|
|
||||||
&gadget_vector(
|
|
||||||
bool_evaluator.parameters.rlwe_logq,
|
|
||||||
bool_evaluator.parameters.logb_rgsw,
|
|
||||||
d_rgsw,
|
|
||||||
),
|
|
||||||
ideal_client_key.sk_rlwe.values(),
|
|
||||||
rlwe_modop,
|
|
||||||
rlwe_nttop,
|
|
||||||
&mut rgsw_prng,
|
|
||||||
&mut rng,
|
|
||||||
);
|
|
||||||
|
|
||||||
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(&rgsw_ct)
|
|
||||||
};
|
|
||||||
|
|
||||||
// RLWE(m*X^{s[i]}) = RLWE(m) x RGSW(X^{s[i]})
|
|
||||||
let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n]; d_rgsw + 2];
|
|
||||||
let rlwe_decomposer = &bool_evaluator.decomposer_rlwe;
|
|
||||||
rlwe_by_rgsw(
|
|
||||||
&mut rlwe_ct,
|
|
||||||
server_key_eval.rgsw_ct_lwe_si(index),
|
|
||||||
// &rgsw_ct.data,
|
|
||||||
&mut scratch_matrix_dplus2_ring,
|
&mut scratch_matrix_dplus2_ring,
|
||||||
rlwe_decomposer,
|
|
||||||
rlwe_nttop,
|
|
||||||
rlwe_modop,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// decrypt RLWE(m*X^{s[i]}) to get encoded m[X]*X^{s[i]}
|
let m_expected = !(m0 & m1);
|
||||||
let mut encoded_m_back = vec![0u64; rlwe_n];
|
|
||||||
decrypt_rlwe(
|
|
||||||
&rlwe_ct,
|
|
||||||
ideal_client_key.sk_rlwe.values(),
|
|
||||||
&mut encoded_m_back,
|
|
||||||
rlwe_nttop,
|
|
||||||
rlwe_modop,
|
|
||||||
);
|
|
||||||
let m_back = encoded_m_back
|
|
||||||
.iter()
|
|
||||||
.map(|el| (((*el as f64 * p as f64) / (rlwe_q as f64)).round() as u64) % p)
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
// calculate m[X]X^{s[i]} in plain
|
// measure noise
|
||||||
let mut si_poly = vec![0u64; rlwe_n];
|
{
|
||||||
// dbg!(ideal_client_key.sk_lwe.values());
|
// Trace PBS
|
||||||
let secret_el_i = ideal_client_key.sk_lwe.values[index];
|
PBSTracer::with_local(|t| {
|
||||||
dbg!(secret_el_i);
|
t.trace(
|
||||||
if secret_el_i < 0 {
|
&MP_BOOL_PARAMS,
|
||||||
si_poly[rlwe_n - secret_el_i.abs() as usize] = p - 1;
|
&ideal_client_key.sk_lwe.values(),
|
||||||
} else {
|
&ideal_client_key.sk_rlwe.values(),
|
||||||
si_poly[secret_el_i.abs() as usize] = 1;
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let ideal_m = if m_expected {
|
||||||
|
bool_evaluator.rlweq_by8
|
||||||
|
} else {
|
||||||
|
bool_evaluator.parameters.rlwe_q - bool_evaluator.rlweq_by8
|
||||||
|
};
|
||||||
|
let noise = measure_noise_lwe(
|
||||||
|
&lwe_out,
|
||||||
|
ideal_client_key.sk_rlwe.values(),
|
||||||
|
&bool_evaluator.rlwe_modop,
|
||||||
|
&ideal_m,
|
||||||
|
);
|
||||||
|
println!("Noise: {noise}");
|
||||||
}
|
}
|
||||||
let mul = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % p as u128) as u64;
|
|
||||||
let expected_m = negacyclic_mul(&m, &si_poly, mul, p);
|
// multi-party decrypt
|
||||||
assert_eq!(expected_m, m_back);
|
let decryption_shares = parties
|
||||||
// println!("M:{:?}", m);
|
.iter()
|
||||||
// println!("M_back:{:?} \n Expected_m:{:?}", m_back, expected_m);
|
.map(|k| bool_evaluator.multi_party_decryption_share(&lwe_out, k))
|
||||||
|
.collect_vec();
|
||||||
|
let m_back = bool_evaluator.multi_party_decrypt(&decryption_shares, &lwe_out);
|
||||||
|
|
||||||
|
let m_back = bool_evaluator.sk_decrypt(&lwe_out, &ideal_client_key);
|
||||||
|
|
||||||
|
dbg!(m_expected, m_back);
|
||||||
|
m1 = m0;
|
||||||
|
m0 = m_back;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // PBS
|
|
||||||
// let mut scratch_lwen_plus1 = vec![0u64;
|
|
||||||
// bool_evaluator.parameters.lwe_n + 1];
|
|
||||||
// let mut scratch_matrix_dplus2_ring = vec![
|
|
||||||
// vec![0u64; bool_evaluator.parameters.rlwe_n];
|
|
||||||
// bool_evaluator.parameters.d_rgsw + 2
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// let mut m0 = true;
|
|
||||||
// let mut m1 = false;
|
|
||||||
|
|
||||||
// for _ in 0..100 {
|
|
||||||
// let lwe0 = bool_evaluator.pk_encrypt(&collective_pk.key, m0);
|
|
||||||
// let lwe1 = bool_evaluator.pk_encrypt(&collective_pk.key, m1);
|
|
||||||
|
|
||||||
// let lwe_out = bool_evaluator.nand(
|
|
||||||
// &lwe0,
|
|
||||||
// &lwe1,
|
|
||||||
// &server_key_eval,
|
|
||||||
// &mut scratch_lwen_plus1,
|
|
||||||
// &mut scratch_matrix_dplus2_ring,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// let m_expected = !(m0 & m1);
|
|
||||||
|
|
||||||
// // measure noise
|
|
||||||
// {
|
|
||||||
// // Trace PBS
|
|
||||||
// PBSTracer::with_local(|t| {
|
|
||||||
// t.trace(
|
|
||||||
// &MP_BOOL_PARAMS,
|
|
||||||
// &ideal_client_key.sk_lwe.values(),
|
|
||||||
// &ideal_client_key.sk_rlwe.values(),
|
|
||||||
// )
|
|
||||||
// });
|
|
||||||
|
|
||||||
// let ideal_m = if m_expected {
|
|
||||||
// bool_evaluator.rlweq_by8
|
|
||||||
// } else {
|
|
||||||
// bool_evaluator.parameters.rlwe_q -
|
|
||||||
// bool_evaluator.rlweq_by8 };
|
|
||||||
// let noise = measure_noise_lwe(
|
|
||||||
// &lwe_out,
|
|
||||||
// ideal_client_key.sk_rlwe.values(),
|
|
||||||
// &bool_evaluator.rlwe_modop,
|
|
||||||
// &ideal_m,
|
|
||||||
// );
|
|
||||||
// println!("Noise: {noise}");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // multi-party decrypt
|
|
||||||
// // let decryption_shares = parties
|
|
||||||
// // .iter()
|
|
||||||
// // .map(|k|
|
|
||||||
// bool_evaluator.multi_party_decryption_share(&lwe_out, k))
|
|
||||||
// // .collect_vec();
|
|
||||||
// // let m_back =
|
|
||||||
// bool_evaluator.multi_party_decrypt(&decryption_shares, //
|
|
||||||
// &lwe_out);
|
|
||||||
|
|
||||||
// let m_back = bool_evaluator.sk_decrypt(&lwe_out,
|
|
||||||
// &ideal_client_key);
|
|
||||||
|
|
||||||
// dbg!(m_expected, m_back);
|
|
||||||
// m1 = m0;
|
|
||||||
// m0 = m_back;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pub(super) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
|
|||||||
lwe_logq: 16,
|
lwe_logq: 16,
|
||||||
br_q: 1 << 10,
|
br_q: 1 << 10,
|
||||||
rlwe_n: 1 << 10,
|
rlwe_n: 1 << 10,
|
||||||
lwe_n: 493,
|
lwe_n: 200,
|
||||||
d_rgsw: 3,
|
d_rgsw: 3,
|
||||||
logb_rgsw: 8,
|
logb_rgsw: 8,
|
||||||
d_lwe: 3,
|
d_lwe: 3,
|
||||||
@@ -38,15 +38,15 @@ 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: 2305843009213616129u64,
|
rlwe_q: 1152921504606830593,
|
||||||
rlwe_logq: 61,
|
rlwe_logq: 60,
|
||||||
lwe_q: 1 << 25,
|
lwe_q: 1 << 25,
|
||||||
lwe_logq: 25,
|
lwe_logq: 25,
|
||||||
br_q: 1 << 11,
|
br_q: 1 << 11,
|
||||||
rlwe_n: 1 << 11,
|
rlwe_n: 1 << 11,
|
||||||
lwe_n: 500,
|
lwe_n: 500,
|
||||||
d_rgsw: 7,
|
d_rgsw: 10,
|
||||||
logb_rgsw: 8,
|
logb_rgsw: 6,
|
||||||
d_lwe: 5,
|
d_lwe: 5,
|
||||||
logb_lwe: 5,
|
logb_lwe: 5,
|
||||||
g: 5,
|
g: 5,
|
||||||
@@ -59,7 +59,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn find_prime() {
|
fn find_prime() {
|
||||||
let bits = 61;
|
let bits = 60;
|
||||||
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);
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ impl<T: PrimInt + WrappingSub + Debug> Decomposer for DefaultDecomposer<T> {
|
|||||||
let mut value = round_value(*value, self.ignore_bits);
|
let mut value = round_value(*value, self.ignore_bits);
|
||||||
|
|
||||||
let q = self.q;
|
let q = self.q;
|
||||||
if value >= (q >> 1) {
|
// if value >= (q >> 1) {
|
||||||
value = value.wrapping_sub(&q);
|
// value = value.wrapping_sub(&q);
|
||||||
}
|
// }
|
||||||
|
|
||||||
let logb = self.logb;
|
let logb = self.logb;
|
||||||
let b = T::one() << logb; // base
|
let b = T::one() << logb; // base
|
||||||
@@ -105,7 +105,7 @@ impl<T: PrimInt + WrappingSub + Debug> Decomposer for DefaultDecomposer<T> {
|
|||||||
for i in 0..self.d {
|
for i in 0..self.d {
|
||||||
let mut limb = ((value >> (logb * i)) & full_mask) + carry;
|
let mut limb = ((value >> (logb * i)) & full_mask) + carry;
|
||||||
carry = T::zero();
|
carry = T::zero();
|
||||||
if limb > b_by2 {
|
if limb >= b_by2 {
|
||||||
limb = (q + limb) - b;
|
limb = (q + limb) - b;
|
||||||
carry = T::one();
|
carry = T::one();
|
||||||
}
|
}
|
||||||
@@ -122,6 +122,11 @@ impl<T: PrimInt + WrappingSub + Debug> Decomposer for DefaultDecomposer<T> {
|
|||||||
// carry = carry >> (logb - 1);
|
// carry = carry >> (logb - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out[self.d - 1] = out[self.d - 1] + (carry << logb);
|
||||||
|
if out[self.d - 1] > q {
|
||||||
|
out[self.d - 1] = out[self.d - 1] - q;
|
||||||
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,15 +158,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decomposition_works() {
|
fn decomposition_works() {
|
||||||
let logq = 15;
|
let logq = 60;
|
||||||
let logb = 3;
|
let logb = 5;
|
||||||
let d = 5;
|
let d = 12;
|
||||||
|
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
// q is prime of bits logq and i is true, other q = 1<<logq
|
// q is prime of bits logq and i is true, other q = 1<<logq
|
||||||
// FIXME: Test fails when q is prime, albeit the difference is minute
|
// FIXME: Test fails when q is prime, albeit the difference is minute
|
||||||
for i in [true] {
|
for i in [true, false] {
|
||||||
let q = if i {
|
let q = if i {
|
||||||
generate_prime(logq, 1 << 4, 1u64 << logq).unwrap()
|
generate_prime(logq, 1 << 4, 1u64 << logq).unwrap()
|
||||||
} else {
|
} else {
|
||||||
@@ -175,7 +180,7 @@ mod tests {
|
|||||||
let value_back = decomposer.recompose(&limbs, &modq_op);
|
let value_back = decomposer.recompose(&limbs, &modq_op);
|
||||||
let rounded_value =
|
let rounded_value =
|
||||||
round_value(value, decomposer.ignore_bits) << decomposer.ignore_bits;
|
round_value(value, decomposer.ignore_bits) << decomposer.ignore_bits;
|
||||||
// dbg!(rounded_value, value, value_back);
|
// dbg!(&limbs, q);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
rounded_value, value_back,
|
rounded_value, value_back,
|
||||||
"Expected {rounded_value} got {value_back} for q={q}"
|
"Expected {rounded_value} got {value_back} for q={q}"
|
||||||
|
|||||||
359
src/rgsw.rs
359
src/rgsw.rs
@@ -859,14 +859,20 @@ pub(crate) fn rgsw_by_rgsw_inplace<
|
|||||||
|
|
||||||
// RGSW x RGSW
|
// RGSW x RGSW
|
||||||
izip!(
|
izip!(
|
||||||
rgsw1_nsm.iter().take(d_rgsw).chain(rgsw1_m).take(d_rgsw),
|
rgsw1_nsm
|
||||||
rgsw1_nsm.iter().skip(d_rgsw).chain(rgsw1_m).skip(d_rgsw),
|
.iter()
|
||||||
|
.take(d_rgsw)
|
||||||
|
.chain(rgsw1_m.iter().take(d_rgsw)),
|
||||||
|
rgsw1_nsm
|
||||||
|
.iter()
|
||||||
|
.skip(d_rgsw)
|
||||||
|
.chain(rgsw1_m.iter().skip(d_rgsw)),
|
||||||
rlwe_dash_space_nsm_parta
|
rlwe_dash_space_nsm_parta
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.chain(rlwe_dash_space_m_parta),
|
.chain(rlwe_dash_space_m_parta.iter_mut()),
|
||||||
rlwe_dash_space_nsm_partb
|
rlwe_dash_space_nsm_partb
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.chain(rlwe_dash_space_m_partb),
|
.chain(rlwe_dash_space_m_partb.iter_mut()),
|
||||||
)
|
)
|
||||||
.for_each(|(rlwe_a, rlwe_b, rlwe_out_a, rlwe_out_b)| {
|
.for_each(|(rlwe_a, rlwe_b, rlwe_out_a, rlwe_out_b)| {
|
||||||
// Part A
|
// Part A
|
||||||
@@ -928,7 +934,7 @@ pub(crate) fn secret_key_encrypt_rgsw<
|
|||||||
NttOp: Ntt<Element = Mmut::MatElement>,
|
NttOp: Ntt<Element = Mmut::MatElement>,
|
||||||
>(
|
>(
|
||||||
out_rgsw: &mut Mmut,
|
out_rgsw: &mut Mmut,
|
||||||
m: &Mmut::R,
|
m: &[Mmut::MatElement],
|
||||||
gadget_vector: &[Mmut::MatElement],
|
gadget_vector: &[Mmut::MatElement],
|
||||||
s: &[S],
|
s: &[S],
|
||||||
mod_op: &ModOp,
|
mod_op: &ModOp,
|
||||||
@@ -1300,7 +1306,7 @@ where
|
|||||||
let mut max_diff_bits = f64::MIN;
|
let mut max_diff_bits = f64::MIN;
|
||||||
m_plus_e.as_ref().iter().for_each(|v| {
|
m_plus_e.as_ref().iter().for_each(|v| {
|
||||||
let mut v = *v;
|
let mut v = *v;
|
||||||
|
println!("{:?}", v);
|
||||||
if v >= (q >> 1) {
|
if v >= (q >> 1) {
|
||||||
// v is -ve
|
// v is -ve
|
||||||
v = q - v;
|
v = q - v;
|
||||||
@@ -1317,14 +1323,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
pub(crate) mod tests {
|
||||||
use std::{ops::Mul, vec};
|
use std::{ops::Mul, vec};
|
||||||
|
|
||||||
use itertools::{izip, Itertools};
|
use itertools::{izip, Itertools};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{ArithmeticOps, ModInit, ModularOpsU64},
|
backend::{ModInit, ModularOpsU64, VectorOps},
|
||||||
decomposer::{gadget_vector, DefaultDecomposer},
|
decomposer::{gadget_vector, DefaultDecomposer},
|
||||||
ntt::{self, Ntt, NttBackendU64, NttInit},
|
ntt::{self, Ntt, NttBackendU64, NttInit},
|
||||||
random::{DefaultSecureRng, NewWithSeed, RandomUniformDist},
|
random::{DefaultSecureRng, NewWithSeed, RandomUniformDist},
|
||||||
@@ -1333,7 +1339,7 @@ mod tests {
|
|||||||
RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, RlwePublicKey,
|
RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, RlwePublicKey,
|
||||||
SeededAutoKey, SeededRgswCiphertext, SeededRlweCiphertext, SeededRlwePublicKey,
|
SeededAutoKey, SeededRgswCiphertext, SeededRlweCiphertext, SeededRlwePublicKey,
|
||||||
},
|
},
|
||||||
utils::{generate_prime, negacyclic_mul},
|
utils::{generate_prime, negacyclic_mul, TryConvertFrom},
|
||||||
Matrix, Secret,
|
Matrix, Secret,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1405,7 +1411,7 @@ mod tests {
|
|||||||
let ring_size = 1 << 9;
|
let ring_size = 1 << 9;
|
||||||
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 = 9;
|
let d_rgsw = 10;
|
||||||
let logb = 5;
|
let logb = 5;
|
||||||
|
|
||||||
let mut rng = DefaultSecureRng::new_seeded([0u8; 32]);
|
let mut rng = DefaultSecureRng::new_seeded([0u8; 32]);
|
||||||
@@ -1419,39 +1425,18 @@ mod tests {
|
|||||||
|
|
||||||
let ntt_op = NttBackendU64::new(q, ring_size as usize);
|
let ntt_op = NttBackendU64::new(q, ring_size as usize);
|
||||||
let mod_op = ModularOpsU64::new(q);
|
let mod_op = ModularOpsU64::new(q);
|
||||||
|
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
||||||
|
|
||||||
// Encrypt m1 as RGSW(m1)
|
// Encrypt m1 as RGSW(m1)
|
||||||
let rgsw_ct = {
|
let rgsw_ct = {
|
||||||
//TODO(Jay): Figure out better way to test secret key and public key variant of
|
//TODO(Jay): Figure out better way to test secret key and public key variant of
|
||||||
// RGSW ciphertext encryption within the same test
|
// RGSW ciphertext encryption within the same test
|
||||||
|
|
||||||
if false {
|
if true {
|
||||||
// RGSW(m1) encryption using secret key
|
// Encryption m1 as RGSW(m1) using secret key
|
||||||
let mut rgsw_seed = [0u8; 32];
|
_sk_encrypt_rgsw(&m1, s.values(), &gadget_vector, &mod_op, &ntt_op)
|
||||||
rng.fill_bytes(&mut rgsw_seed);
|
|
||||||
let mut seeded_rgsw_ct = SeededRgswCiphertext::<Vec<Vec<u64>>, [u8; 32]>::empty(
|
|
||||||
ring_size as usize,
|
|
||||||
d_rgsw,
|
|
||||||
rgsw_seed,
|
|
||||||
q,
|
|
||||||
);
|
|
||||||
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
|
|
||||||
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
|
||||||
secret_key_encrypt_rgsw(
|
|
||||||
&mut seeded_rgsw_ct.data,
|
|
||||||
&m1,
|
|
||||||
&gadget_vector,
|
|
||||||
s.values(),
|
|
||||||
&mod_op,
|
|
||||||
&ntt_op,
|
|
||||||
&mut p_rng,
|
|
||||||
&mut rng,
|
|
||||||
);
|
|
||||||
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
|
|
||||||
&seeded_rgsw_ct,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// RGSW(m1) encryption using public key
|
// Encrypt m1 as RGSW(m1) as public key
|
||||||
|
|
||||||
// first create public key
|
// first create public key
|
||||||
let mut pk_seed = [0u8; 32];
|
let mut pk_seed = [0u8; 32];
|
||||||
@@ -1469,22 +1454,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
let pk = RlwePublicKey::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_pk);
|
let pk = RlwePublicKey::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_pk);
|
||||||
|
|
||||||
// public key encrypt RGSW(m1)
|
let rgsw_ct = _pk_encrypt_rgsw(&m1, &pk, &gadget_vector, &mod_op, &ntt_op);
|
||||||
let mut rgsw_ct = vec![vec![0u64; ring_size as usize]; d_rgsw * 4];
|
|
||||||
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
|
||||||
public_key_encrypt_rgsw(
|
|
||||||
&mut rgsw_ct,
|
|
||||||
&m1,
|
|
||||||
&pk.data,
|
|
||||||
&gadget_vector,
|
|
||||||
&mod_op,
|
|
||||||
&ntt_op,
|
|
||||||
&mut rng,
|
|
||||||
);
|
|
||||||
|
|
||||||
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
|
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
|
||||||
&RgswCiphertext {
|
&RgswCiphertext {
|
||||||
data: rgsw_ct,
|
data: rgsw_ct.data,
|
||||||
modulus: q,
|
modulus: q,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -1543,6 +1516,18 @@ mod tests {
|
|||||||
|
|
||||||
let mul_mod = |v0: &u64, v1: &u64| (v0 * v1) % p;
|
let mul_mod = |v0: &u64, v1: &u64| (v0 * v1) % p;
|
||||||
let m0m1 = negacyclic_mul(&m0, &m1, mul_mod, p);
|
let m0m1 = negacyclic_mul(&m0, &m1, mul_mod, p);
|
||||||
|
|
||||||
|
{
|
||||||
|
// measure noise
|
||||||
|
let encoded_m_ideal = m0m1
|
||||||
|
.iter()
|
||||||
|
.map(|v| (((*v as f64) * q as f64) / (p as f64)).round() as u64)
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let noise = measure_noise(&rlwe_in_ct, &encoded_m_ideal, &ntt_op, &mod_op, s.values());
|
||||||
|
println!("Noise RLWE(m0m1)(= RLWE(m0)xRGSW(m1)) : {noise}");
|
||||||
|
}
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
m0m1 == m0m1_back,
|
m0m1 == m0m1_back,
|
||||||
"Expected {:?} \n Got {:?}",
|
"Expected {:?} \n Got {:?}",
|
||||||
@@ -1551,6 +1536,52 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rlwe_by_rgsw_noise_growth() {
|
||||||
|
let logq = 31;
|
||||||
|
let ring_size = 1 << 9;
|
||||||
|
let q = generate_prime(logq, ring_size * 2, 1u64 << logq).unwrap();
|
||||||
|
let d_rgsw = 6;
|
||||||
|
let logb = 5;
|
||||||
|
|
||||||
|
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
|
let ntt_op = NttBackendU64::new(q, ring_size as usize);
|
||||||
|
let mod_op = ModularOpsU64::new(q);
|
||||||
|
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
||||||
|
let decomposer = DefaultDecomposer::new(q, logb, d_rgsw);
|
||||||
|
|
||||||
|
let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) % (q as u128)) as u64;
|
||||||
|
|
||||||
|
let mut carry_m = vec![0u64; ring_size as usize];
|
||||||
|
carry_m[thread_rng().gen_range(0..ring_size) as usize] = 1;
|
||||||
|
let mut rlwe = vec![vec![0u64; ring_size as usize], carry_m.clone()];
|
||||||
|
let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from_raw(rlwe, true);
|
||||||
|
|
||||||
|
let mut scratch_matrix_dplus2_ring = vec![vec![0u64; ring_size as usize]; d_rgsw + 2];
|
||||||
|
for i in 0..1usize {
|
||||||
|
// Encrypt monomial as RGSW
|
||||||
|
let mut m = vec![0u64; ring_size as usize];
|
||||||
|
m[thread_rng().gen_range(0..ring_size) as usize] = if i & 1 == 1 { 1 } else { q - 1 };
|
||||||
|
let rgsw_ct = _sk_encrypt_rgsw(&m, s.values(), &gadget_vector, &mod_op, &ntt_op);
|
||||||
|
|
||||||
|
// RLWE(carry_m * m) = RLWE(carry_m) x RGSW(m)
|
||||||
|
rlwe_by_rgsw(
|
||||||
|
&mut rlwe,
|
||||||
|
&rgsw_ct.data,
|
||||||
|
&mut scratch_matrix_dplus2_ring,
|
||||||
|
&decomposer,
|
||||||
|
&ntt_op,
|
||||||
|
&mod_op,
|
||||||
|
);
|
||||||
|
|
||||||
|
carry_m = negacyclic_mul(&carry_m, &m, mul_mod, q);
|
||||||
|
let noise = measure_noise(&rlwe, &carry_m, &ntt_op, &mod_op, s.values());
|
||||||
|
|
||||||
|
println!("Noise RLWE(carry_m) after {i}^th iteration: {noise}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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>,
|
||||||
@@ -1583,15 +1614,112 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encrypts m as RGSW ciphertext RGSW(m) using supplied secret key. Returns
|
||||||
|
/// unseeded RGSW ciphertext in coefficient domain
|
||||||
|
fn _sk_encrypt_rgsw(
|
||||||
|
m: &[u64],
|
||||||
|
s: &[i32],
|
||||||
|
gadget_vector: &[u64],
|
||||||
|
mod_op: &ModularOpsU64,
|
||||||
|
ntt_op: &NttBackendU64,
|
||||||
|
) -> RgswCiphertextEvaluationDomain<Vec<Vec<u64>>, DefaultSecureRng, NttBackendU64> {
|
||||||
|
let ring_size = s.len();
|
||||||
|
assert!(m.len() == s.len());
|
||||||
|
|
||||||
|
let d_rgsw = gadget_vector.len();
|
||||||
|
let q = mod_op.modulus();
|
||||||
|
|
||||||
|
let mut rng = DefaultSecureRng::new();
|
||||||
|
let mut rgsw_seed = [0u8; 32];
|
||||||
|
rng.fill_bytes(&mut rgsw_seed);
|
||||||
|
let mut seeded_rgsw_ct = SeededRgswCiphertext::<Vec<Vec<u64>>, [u8; 32]>::empty(
|
||||||
|
ring_size as usize,
|
||||||
|
d_rgsw,
|
||||||
|
rgsw_seed,
|
||||||
|
q,
|
||||||
|
);
|
||||||
|
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
|
||||||
|
secret_key_encrypt_rgsw(
|
||||||
|
&mut seeded_rgsw_ct.data,
|
||||||
|
m,
|
||||||
|
&gadget_vector,
|
||||||
|
s,
|
||||||
|
mod_op,
|
||||||
|
ntt_op,
|
||||||
|
&mut p_rng,
|
||||||
|
&mut rng,
|
||||||
|
);
|
||||||
|
|
||||||
|
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(&seeded_rgsw_ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prints noise in RGSW ciphertext RGSW(m).
|
||||||
|
///
|
||||||
|
/// - rgsw_ct: RGSW ciphertext in coefficient domain
|
||||||
|
pub(crate) fn _measure_noise_rgsw(
|
||||||
|
rgsw_ct: &[Vec<u64>],
|
||||||
|
m: &[u64],
|
||||||
|
s: &[i32],
|
||||||
|
gadget_vector: &[u64],
|
||||||
|
q: u64,
|
||||||
|
) {
|
||||||
|
let d_rgsw = gadget_vector.len();
|
||||||
|
let ring_size = s.len();
|
||||||
|
assert!(Matrix::dimension(&rgsw_ct) == (d_rgsw * 2 * 2, ring_size));
|
||||||
|
assert!(m.len() == ring_size);
|
||||||
|
|
||||||
|
let mod_op = ModularOpsU64::new(q);
|
||||||
|
let ntt_op = NttBackendU64::new(q, ring_size);
|
||||||
|
|
||||||
|
let mul_mod = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % q as u128) as u64;
|
||||||
|
let s_poly = Vec::<u64>::try_convert_from(s, &q);
|
||||||
|
let mut neg_s = s_poly.clone();
|
||||||
|
mod_op.elwise_neg_mut(neg_s.as_mut());
|
||||||
|
let neg_sm0m1 = negacyclic_mul(&neg_s, &m, mul_mod, q);
|
||||||
|
for i in 0..2 {
|
||||||
|
for j in 0..d_rgsw {
|
||||||
|
let ideal_m = {
|
||||||
|
if i == 0 {
|
||||||
|
// RLWE(\beta^j -s * m)
|
||||||
|
let mut beta_neg_sm0m1 = vec![0u64; ring_size as usize];
|
||||||
|
mod_op.elwise_scalar_mul(
|
||||||
|
beta_neg_sm0m1.as_mut(),
|
||||||
|
&neg_sm0m1,
|
||||||
|
&gadget_vector[j],
|
||||||
|
);
|
||||||
|
beta_neg_sm0m1
|
||||||
|
} else {
|
||||||
|
// RLWE(\beta^j m)
|
||||||
|
let mut beta_m0m1 = vec![0u64; ring_size as usize];
|
||||||
|
mod_op.elwise_scalar_mul(beta_m0m1.as_mut(), &m, &gadget_vector[j]);
|
||||||
|
beta_m0m1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rlwe = vec![vec![0u64; ring_size as usize]; 2];
|
||||||
|
rlwe[0].copy_from_slice(rgsw_ct.get_row_slice((i * 2 * d_rgsw) + j));
|
||||||
|
rlwe[1].copy_from_slice(rgsw_ct.get_row_slice((i * 2 * d_rgsw) + d_rgsw + j));
|
||||||
|
let noise = measure_noise(&rlwe, &ideal_m, &ntt_op, &mod_op, s);
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
println!(r"Noise RLWE(\beta^{j} -sm0m1): {noise}");
|
||||||
|
} else {
|
||||||
|
println!(r"Noise RLWE(\beta^{j} m0m1): {noise}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// m0m1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rgsw_by_rgsw() {
|
fn pk_rgsw_by_rgsw() {
|
||||||
let logq = 50;
|
let logq = 60;
|
||||||
let logp = 2;
|
let logp = 2;
|
||||||
let ring_size = 1 << 4;
|
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 = 10;
|
let d_rgsw = 15;
|
||||||
let logb = 5;
|
let logb = 4;
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@@ -1619,43 +1747,104 @@ mod tests {
|
|||||||
RlwePublicKey::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_pk)
|
RlwePublicKey::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_pk)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut m0 = vec![0u64; ring_size as usize];
|
let mut carry_m = vec![0u64; ring_size as usize];
|
||||||
m0[thread_rng().gen_range(0..ring_size) as usize] = 1;
|
carry_m[thread_rng().gen_range(0..ring_size) as usize] = 1;
|
||||||
let mut m1 = vec![0u64; ring_size as usize];
|
|
||||||
m1[thread_rng().gen_range(0..ring_size) as usize] = 1;
|
|
||||||
|
|
||||||
// RGSW(m0)
|
// RGSW(carry_m)
|
||||||
let rgsw_m0 = _pk_encrypt_rgsw(&m0, &public_key, &gadget_vector, &mod_op, &ntt_op);
|
let rgsw_carrym = _pk_encrypt_rgsw(&carry_m, &public_key, &gadget_vector, &mod_op, &ntt_op);
|
||||||
// RGSW(m1)
|
let mut rgsw_carrym =
|
||||||
let rgsw_m1 = _pk_encrypt_rgsw(&m0, &public_key, &gadget_vector, &mod_op, &ntt_op);
|
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
|
||||||
|
&rgsw_carrym,
|
||||||
let mut rgsw_m0_eval =
|
);
|
||||||
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(&rgsw_m0);
|
|
||||||
|
|
||||||
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)];
|
||||||
rgsw_by_rgsw_inplace(
|
|
||||||
&mut rgsw_m0_eval.data,
|
|
||||||
&rgsw_m1.data,
|
|
||||||
&decomposer,
|
|
||||||
&mut scratch_matrix_d_plus_rgsw_by_ring,
|
|
||||||
&ntt_op,
|
|
||||||
&mod_op,
|
|
||||||
);
|
|
||||||
dbg!(&rgsw_m0_eval.data);
|
|
||||||
|
|
||||||
// RLWE(m0m1)
|
for i in 0..10 {
|
||||||
let mut rlwe_m0m1 = vec![vec![0u64; ring_size as usize]; 2];
|
let mut m = vec![0u64; ring_size as usize];
|
||||||
rlwe_m0m1[0].copy_from_slice(rgsw_m0_eval.get_row_slice(2 * d_rgsw));
|
m[thread_rng().gen_range(0..ring_size) as usize] = q - 1;
|
||||||
rlwe_m0m1[1].copy_from_slice(rgsw_m0_eval.get_row_slice(3 * d_rgsw));
|
let rgsw_m = _pk_encrypt_rgsw(&m, &public_key, &gadget_vector, &mod_op, &ntt_op);
|
||||||
rlwe_m0m1.iter_mut().for_each(|ri| ntt_op.backward(ri));
|
|
||||||
|
|
||||||
// m0m1
|
rgsw_by_rgsw_inplace(
|
||||||
let mul = |a: &u64, b: &u64| ((*a as u128 * *b as u128) % q as u128) as u64;
|
&mut rgsw_carrym.data,
|
||||||
let m0m1 = negacyclic_mul(&m0, &m1, mul, q);
|
&rgsw_m.data,
|
||||||
|
&decomposer,
|
||||||
|
&mut scratch_matrix_d_plus_rgsw_by_ring,
|
||||||
|
&ntt_op,
|
||||||
|
&mod_op,
|
||||||
|
);
|
||||||
|
|
||||||
let noise = measure_noise(&rlwe_m0m1, &m0m1, &ntt_op, &mod_op, s.values());
|
// measure noise
|
||||||
dbg!(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);
|
||||||
|
println!("########### Noise RGSW(carrym) in {i}^th loop ###########");
|
||||||
|
let mut rgsw_carrym_clone = rgsw_carrym.data.clone();
|
||||||
|
rgsw_carrym_clone
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|ri| ntt_op.backward(ri.as_mut()));
|
||||||
|
_measure_noise_rgsw(&rgsw_carrym_clone, &carry_m, s.values(), &gadget_vector, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sk_rgsw_by_rgsw() {
|
||||||
|
let logq = 60;
|
||||||
|
let logp = 2;
|
||||||
|
let ring_size = 1 << 11;
|
||||||
|
let q = generate_prime(logq, ring_size, 1u64 << logq).unwrap();
|
||||||
|
let p = 1u64 << logp;
|
||||||
|
let d_rgsw = 15;
|
||||||
|
let logb = 4;
|
||||||
|
|
||||||
|
let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
|
||||||
|
|
||||||
|
let mut rng = DefaultSecureRng::new();
|
||||||
|
let ntt_op = NttBackendU64::new(q, ring_size as usize);
|
||||||
|
let mod_op = ModularOpsU64::new(q);
|
||||||
|
let gadget_vector = gadget_vector(logq, logb, d_rgsw);
|
||||||
|
let decomposer = DefaultDecomposer::new(q, logb, d_rgsw);
|
||||||
|
|
||||||
|
let mut carry_m = vec![0u64; ring_size as usize];
|
||||||
|
carry_m[thread_rng().gen_range(0..ring_size) as usize] = 1;
|
||||||
|
|
||||||
|
// RGSW(carry_m)
|
||||||
|
let mut rgsw_carrym =
|
||||||
|
_sk_encrypt_rgsw(&carry_m, s.values(), &gadget_vector, &mod_op, &ntt_op);
|
||||||
|
|
||||||
|
let mut scratch_matrix_d_plus_rgsw_by_ring =
|
||||||
|
vec![vec![0u64; ring_size as usize]; d_rgsw + (d_rgsw * 4)];
|
||||||
|
|
||||||
|
for i in 0..1 {
|
||||||
|
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 };
|
||||||
|
let rgsw_m = {
|
||||||
|
let mut rgsw_eval =
|
||||||
|
_sk_encrypt_rgsw(&m, s.values(), &gadget_vector, &mod_op, &ntt_op).data;
|
||||||
|
rgsw_eval
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|ri| ntt_op.backward(ri.as_mut()));
|
||||||
|
rgsw_eval
|
||||||
|
};
|
||||||
|
|
||||||
|
rgsw_by_rgsw_inplace(
|
||||||
|
&mut rgsw_carrym.data,
|
||||||
|
&rgsw_m,
|
||||||
|
&decomposer,
|
||||||
|
&mut scratch_matrix_d_plus_rgsw_by_ring,
|
||||||
|
&ntt_op,
|
||||||
|
&mod_op,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
println!("########### Noise RGSW(carrym) in {i}^th loop ###########");
|
||||||
|
let mut rgsw_carrym_clone = rgsw_carrym.data.clone();
|
||||||
|
rgsw_carrym_clone
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|ri| ntt_op.backward(ri.as_mut()));
|
||||||
|
_measure_noise_rgsw(&rgsw_carrym_clone, &carry_m, s.values(), &gadget_vector, q);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user