From 9b86d5d14ca57f40e6b278a03b61d7090eb0106d Mon Sep 17 00:00:00 2001 From: Janmajaya Mall Date: Sat, 4 May 2024 20:11:40 +0530 Subject: [PATCH] multi-party NAND gate works --- src/bool/evaluator.rs | 230 ++++++++++++++++++++++------------------- src/bool/parameters.rs | 16 +-- src/rgsw.rs | 182 ++++++++++++++++++++++---------- 3 files changed, 255 insertions(+), 173 deletions(-) diff --git a/src/bool/evaluator.rs b/src/bool/evaluator.rs index 51044ab..7f748a8 100644 --- a/src/bool/evaluator.rs +++ b/src/bool/evaluator.rs @@ -192,7 +192,11 @@ fn aggregate_multi_party_server_key_shares< ModOp: VectorOps + ModInit, NttOp: Ntt + NttInit, >( - shares: &[CommonReferenceSeededMultiPartyServerKeyShare, S>], + mut shares: &[CommonReferenceSeededMultiPartyServerKeyShare< + M, + BoolParameters, + S, + >], d_rgsw_decomposer: &D, ) -> SeededMultiPartyServerKey> where @@ -241,20 +245,26 @@ where // rgsw ciphertext (most expensive part!) let lwe_n = parameters.lwe_n; let mut scratch_d_plus_rgsw_by_ring = M::zeros(d_rgsw + (d_rgsw * 4), rlwe_n); + let mut tmp_rgsw = M::zeros(d_rgsw * 2 * 2, rlwe_n); let rgsw_cts = (0..lwe_n) .into_iter() .map(|index| { // copy over rgsw ciphertext for index^th secret element from first share and - // send it to evaluation domain + // treat it as accumulating rgsw ciphertext let mut rgsw_i = shares[0].rgsw_cts[index].clone(); - rgsw_i - .iter_rows_mut() - .for_each(|ri| rlweq_nttop.forward(ri.as_mut())); shares.iter().skip(1).for_each(|si| { + // copy over si's RGSW[index] ciphertext and send to evaluation domain + izip!(tmp_rgsw.iter_rows_mut(), si.rgsw_cts[index].iter_rows()).for_each( + |(to_ri, from_ri)| { + to_ri.as_mut().copy_from_slice(from_ri.as_ref()); + rlweq_nttop.forward(to_ri.as_mut()) + }, + ); + rgsw_by_rgsw_inplace( &mut rgsw_i, - &si.rgsw_cts[index], + &tmp_rgsw, d_rgsw_decomposer, &mut scratch_d_plus_rgsw_by_ring, &rlweq_nttop, @@ -262,10 +272,6 @@ where ); }); - // send final rgsw ciphertext of secret element at index to coefficient domain - rgsw_i - .iter_rows_mut() - .for_each(|ri| rlweq_nttop.backward(ri.as_mut())); rgsw_i }) .collect_vec(); @@ -1629,14 +1635,17 @@ impl WithLocal for PBSTracer>> { #[cfg(test)] mod tests { + use rand::{thread_rng, Rng}; + use crate::{ backend::ModularOpsU64, bool, ntt::NttBackendU64, random::DEFAULT_RNG, rgsw::{ - self, measure_noise, secret_key_encrypt_rlwe, tests::_measure_noise_rgsw, - RgswCiphertextEvaluationDomain, SeededRgswCiphertext, SeededRlweCiphertext, + self, measure_noise, public_key_encrypt_rlwe, secret_key_encrypt_rlwe, + tests::_measure_noise_rgsw, RgswCiphertext, RgswCiphertextEvaluationDomain, + SeededRgswCiphertext, SeededRlweCiphertext, }, utils::negacyclic_mul, }; @@ -1807,7 +1816,7 @@ mod tests { let bool_evaluator = BoolEvaluator::>, u64, NttBackendU64, ModularOpsU64>::new(MP_BOOL_PARAMS); - let no_of_parties = 5; + let no_of_parties = 10; let parties = (0..no_of_parties) .map(|_| bool_evaluator.client_key()) .collect_vec(); @@ -1862,14 +1871,20 @@ mod tests { } }; + let lwe_q = bool_evaluator.parameters.lwe_q; + let rlwe_q = bool_evaluator.parameters.rlwe_q; + let d_rgsw = bool_evaluator.parameters.d_rgsw; + 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 lwe_modop = &bool_evaluator.lwe_modop; + let rlwe_nttop = &bool_evaluator.rlwe_nttop; + let rlwe_modop = &bool_evaluator.rlwe_modop; + let rlwe_decomposer = &bool_evaluator.decomposer_rlwe; + // 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; + if true { let logp = 2; - let lwe_modop = &bool_evaluator.lwe_modop; let mut rng = DefaultSecureRng::new(); let m = 1; @@ -1911,15 +1926,13 @@ mod tests { println!("Noise: {noise}"); } - { - let rlwe_n = bool_evaluator.parameters.rlwe_n; - let rlwe_q = bool_evaluator.parameters.rlwe_q; + // Measure noise in RGSW ciphertexts of ideal LWE secrets + if false { 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]) @@ -1937,7 +1950,7 @@ mod tests { .for_each(|ri| rlwe_nttop.backward(ri.as_mut())); println!("####### Noise in RGSW(X^s_{i}) #######"); - let noise = _measure_noise_rgsw( + _measure_noise_rgsw( &rgsw_si, &si_poly, ideal_client_key.sk_rlwe.values(), @@ -1948,106 +1961,107 @@ mod tests { } } + // measure noise grwoth in RLWExRGSW 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()); + let mut carry_m = vec![0u64; rlwe_n]; + RandomUniformDist::random_fill(&mut rng, &rlwe_q, carry_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(); + // RGSW(carrym) + let trivial_rlwect = vec![vec![0u64; rlwe_n], carry_m.clone()]; + let mut rlwe_ct = RlweCiphertext::<_, DefaultSecureRng>::from_raw(trivial_rlwect, true); - // 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::>, 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; + let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n]; d_rgsw + 2]; + let mul_mod = + |v0: &u64, v1: &u64| (((*v0 as u128 * *v1 as u128) % (rlwe_q as u128)) as u64); + + for i in 0..450 { rlwe_by_rgsw( &mut rlwe_ct, - server_key_eval.rgsw_ct_lwe_si(index), - // &rgsw_ct.data, + server_key_eval.rgsw_ct_lwe_si(i), &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( + // carry_m[X] * s_i[X] + 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; + } + carry_m = negacyclic_mul(&carry_m, &si_poly, mul_mod, rlwe_q); + + let noise = measure_noise( &rlwe_ct, - ideal_client_key.sk_rlwe.values(), - &mut encoded_m_back, + &carry_m, rlwe_nttop, rlwe_modop, + ideal_client_key.sk_rlwe.values(), ); - 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); + println!("Noise RLWE(carry_m) accumulating {i}^th secret monomial: {noise}"); + } + } - // 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, + // Check galois keys + if false { + let g = bool_evaluator.g() as isize; + let mut rng = DefaultSecureRng::new(); + let mut scratch_matrix_dplus2_ring = vec![vec![0u64; rlwe_n]; d_rgsw + 2]; + for i in [g, -g] { + let mut m = vec![0u64; rlwe_n]; + RandomUniformDist::random_fill(&mut rng, &rlwe_q, m.as_mut_slice()); + let mut rlwe_ct = { + let mut data = vec![vec![0u64; rlwe_n]; 2]; + public_key_encrypt_rlwe( + &mut data, + &collective_pk.key, + &m, rlwe_modop, - ideal_client_key.sk_rlwe.values(), + rlwe_nttop, + &mut rng, ); - println!("Noise RLWE(m X^s_{index}) = RLWE(m) x RGSW(X^s_{index}): {noise}") - } - // println!("M:{:?}", m); - // assert_eq!(expected_m, m_back); + RlweCiphertext::<_, DefaultSecureRng>::from_raw(data, false) + }; + + let auto_key = server_key_eval.galois_key_for_auto(i); + let (auto_map_index, auto_map_sign) = generate_auto_map(rlwe_n, i); + galois_auto( + &mut rlwe_ct, + auto_key, + &mut scratch_matrix_dplus2_ring, + &auto_map_index, + &auto_map_sign, + rlwe_modop, + rlwe_nttop, + rlwe_decomposer, + ); + + // send m(X) -> m(X^i) + let mut m_k = vec![0u64; rlwe_n]; + izip!(m.iter(), auto_map_index.iter(), auto_map_sign.iter()).for_each( + |(mi, to_index, to_sign)| { + if !to_sign { + m_k[*to_index] = rlwe_q - *mi; + } else { + m_k[*to_index] = *mi; + } + }, + ); + + // measure noise + let noise = measure_noise( + &rlwe_ct, + &m_k, + rlwe_nttop, + rlwe_modop, + ideal_client_key.sk_rlwe.values(), + ); - // println!("M_back:{:?} \n Expected_m:{:?}", m_back, - // expected_m); + println!("Noise after auto k={i}: {noise}"); } } } @@ -2122,7 +2136,7 @@ mod tests { let mut m0 = true; let mut m1 = false; - for _ in 0..100 { + for _ in 0..500 { let lwe0 = bool_evaluator.pk_encrypt(&collective_pk.key, m0); let lwe1 = bool_evaluator.pk_encrypt(&collective_pk.key, m1); @@ -2168,11 +2182,11 @@ mod tests { .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); + // let m_back = bool_evaluator.sk_decrypt(&lwe_out, &ideal_client_key); - dbg!(m_expected, m_back); + assert_eq!(m_expected, m_back); m1 = m0; - m0 = m_back; + m0 = m_expected; } } } diff --git a/src/bool/parameters.rs b/src/bool/parameters.rs index f8698dc..e2e68b7 100644 --- a/src/bool/parameters.rs +++ b/src/bool/parameters.rs @@ -28,10 +28,10 @@ pub(super) const SP_BOOL_PARAMS: BoolParameters = BoolParameters:: { lwe_logq: 16, br_q: 1 << 10, rlwe_n: 1 << 10, - lwe_n: 200, - d_rgsw: 3, - logb_rgsw: 8, - d_lwe: 3, + lwe_n: 493, + d_rgsw: 4, + logb_rgsw: 7, + d_lwe: 4, logb_lwe: 4, g: 5, w: 1, @@ -40,15 +40,15 @@ pub(super) const SP_BOOL_PARAMS: BoolParameters = BoolParameters:: { pub(super) const MP_BOOL_PARAMS: BoolParameters = BoolParameters:: { rlwe_q: 1152921504606830593, rlwe_logq: 60, - lwe_q: 1 << 25, - lwe_logq: 25, - br_q: 1 << 11, + lwe_q: 1 << 20, + lwe_logq: 20, + br_q: 1 << 12, rlwe_n: 1 << 11, lwe_n: 500, d_rgsw: 10, logb_rgsw: 6, d_lwe: 5, - logb_lwe: 5, + logb_lwe: 4, g: 5, w: 1, }; diff --git a/src/rgsw.rs b/src/rgsw.rs index e96a2cb..bcb3aa5 100644 --- a/src/rgsw.rs +++ b/src/rgsw.rs @@ -6,7 +6,7 @@ use std::{ }; use itertools::{izip, Itertools}; -use num_traits::{PrimInt, ToPrimitive, Zero}; +use num_traits::{PrimInt, Signed, ToPrimitive, Zero}; use crate::{ backend::{ArithmeticOps, VectorOps}, @@ -103,7 +103,7 @@ where } impl SeededRgswCiphertext { - fn from_raw(data: M, seed: S, modulus: M::MatElement) -> SeededRgswCiphertext { + pub(crate) fn from_raw(data: M, seed: S, modulus: M::MatElement) -> SeededRgswCiphertext { assert!(data.dimension().0 % 3 == 0); SeededRgswCiphertext { @@ -814,11 +814,22 @@ pub(crate) fn rlwe_by_rgsw< rlwe_in.set_not_trivial(); } -/// Inplace mutates rlwe_0_eval_domain to equal RGSW(m0m1) = RGSW(m0)xRGSW(m1) +/// Inplace mutates rlwe_0 to equal RGSW(m0m1) = RGSW(m0)xRGSW(m1) /// in evaluation domain /// -/// - rgsw_0_eval_domain: RGSW(m0) in evaluation domain -/// - rgsw_1: RGSW(m1) +/// Warning - +/// Pass a fresh RGSW ciphertext as the second operand, i.e. as `rgsw_1`. +/// This is to assure minimal error growth in the resulting RGSW ciphertext. +/// RGSWxRGSW boils down to d_rgsw*2 RLWExRGSW multiplications. Hence, the noise +/// growth in resulting ciphertext depends on the norm of second RGSW +/// ciphertext, not the first. This is useful in cases where one is accumulating +/// multiple RGSW ciphertexts into 1. In which case, pass the accumulating RGSW +/// ciphertext as rlwe_0 (the one with higher noise) and subsequent RGSW +/// ciphertexts, with lower noise, to be accumulated as second +/// operand. +/// +/// - rgsw_0: RGSW(m0) +/// - rgsw_1_eval: RGSW(m1) in Evaluation domain /// - scratch_matrix_d_plus_rgsw_by_ring: scratch space matrix of size /// (d+(d*4))xring_size, where d equals d_rgsw pub(crate) fn rgsw_by_rgsw_inplace< @@ -827,8 +838,8 @@ pub(crate) fn rgsw_by_rgsw_inplace< ModOp: VectorOps, NttOp: Ntt, >( - rgsw_0_eval_domain: &mut Mmut, - rgsw_1: &Mmut, + rgsw_0: &mut Mmut, + rgsw_1_eval: &Mmut, decomposer: &D, scratch_matrix_d_plus_rgsw_by_ring: &mut Mmut, ntt_op: &NttOp, @@ -838,9 +849,9 @@ pub(crate) fn rgsw_by_rgsw_inplace< Mmut::MatElement: Copy + Zero, { let d_rgsw = decomposer.d(); - assert!(rgsw_0_eval_domain.dimension().0 == 4 * d_rgsw); - let ring_size = rgsw_0_eval_domain.dimension().1; - assert!(rgsw_1.dimension() == (4 * d_rgsw, ring_size)); + assert!(rgsw_0.dimension().0 == 4 * d_rgsw); + let ring_size = rgsw_0.dimension().1; + assert!(rgsw_1_eval.dimension() == (4 * d_rgsw, ring_size)); assert!(scratch_matrix_d_plus_rgsw_by_ring.dimension() == (d_rgsw + (d_rgsw * 4), ring_size)); let (decomp_r_space, rgsw_space) = scratch_matrix_d_plus_rgsw_by_ring.split_at_row_mut(d_rgsw); @@ -854,19 +865,19 @@ pub(crate) fn rgsw_by_rgsw_inplace< rlwe_dash_space_nsm.split_at_mut(d_rgsw); let (rlwe_dash_space_m_parta, rlwe_dash_space_m_partb) = rlwe_dash_space_m.split_at_mut(d_rgsw); - let (rgsw0_nsm, rgsw0_m) = rgsw_0_eval_domain.split_at_row(d_rgsw * 2); - let (rgsw1_nsm, rgsw1_m) = rgsw_1.split_at_row(d_rgsw * 2); + let (rgsw0_nsm, rgsw0_m) = rgsw_0.split_at_row(d_rgsw * 2); + let (rgsw1_nsm, rgsw1_m) = rgsw_1_eval.split_at_row(d_rgsw * 2); // RGSW x RGSW izip!( - rgsw1_nsm + rgsw0_nsm .iter() .take(d_rgsw) - .chain(rgsw1_m.iter().take(d_rgsw)), - rgsw1_nsm + .chain(rgsw0_m.iter().take(d_rgsw)), + rgsw0_nsm .iter() .skip(d_rgsw) - .chain(rgsw1_m.iter().skip(d_rgsw)), + .chain(rgsw0_m.iter().skip(d_rgsw)), rlwe_dash_space_nsm_parta .iter_mut() .chain(rlwe_dash_space_m_parta.iter_mut()), @@ -883,13 +894,13 @@ pub(crate) fn rgsw_by_rgsw_inplace< routine( rlwe_out_a.as_mut(), decomp_r_space, - &rgsw0_nsm[..d_rgsw], + &rgsw1_nsm[..d_rgsw], mod_op, ); routine( rlwe_out_b.as_mut(), decomp_r_space, - &rgsw0_nsm[d_rgsw..], + &rgsw1_nsm[d_rgsw..], mod_op, ); @@ -901,20 +912,25 @@ pub(crate) fn rgsw_by_rgsw_inplace< routine( rlwe_out_a.as_mut(), decomp_r_space, - &rgsw0_m[..d_rgsw], + &rgsw1_m[..d_rgsw], mod_op, ); routine( rlwe_out_b.as_mut(), decomp_r_space, - &rgsw0_m[d_rgsw..], + &rgsw1_m[d_rgsw..], mod_op, ); }); // copy over RGSW(m0m1) into RGSW(m0) - izip!(rgsw_0_eval_domain.iter_rows_mut(), rgsw_space.iter()) - .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref())) + izip!(rgsw_0.iter_rows_mut(), rgsw_space.iter()) + .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref())); + + // send back to coefficient domain + rgsw_0 + .iter_rows_mut() + .for_each(|ri| ntt_op.backward(ri.as_mut())); } /// Encrypts message m as a RGSW ciphertext. @@ -1182,6 +1198,66 @@ pub(crate) fn secret_key_encrypt_rlwe< mod_op.elwise_add_mut(b_rlwe_out.as_mut(), sa.as_ref()); } +pub(crate) fn public_key_encrypt_rlwe< + M: MatrixMut, + ModOp: VectorOps, + NttOp: Ntt, + S, + R: RandomGaussianDist<[M::MatElement], Parameters = M::MatElement> + + RandomUniformDist<[M::MatElement], Parameters = M::MatElement> + + RandomUniformDist<[u8], Parameters = u8> + + RandomUniformDist, +>( + rlwe_out: &mut M, + pk: &M, + m: &[M::MatElement], + mod_op: &ModOp, + ntt_op: &NttOp, + rng: &mut R, +) where + ::R: RowMut + TryConvertFrom<[S], Parameters = M::MatElement> + RowEntity, + M::MatElement: Copy, + S: Zero + Signed + Copy, +{ + let ring_size = m.len(); + assert!(rlwe_out.dimension() == (2, ring_size)); + + let q = mod_op.modulus(); + + let mut u = vec![S::zero(); ring_size]; + fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng); + let mut u = M::R::try_convert_from(&u, &q); + ntt_op.forward(u.as_mut()); + + let mut ua = M::R::zeros(ring_size); + ua.as_mut().copy_from_slice(pk.get_row_slice(0)); + let mut ub = M::R::zeros(ring_size); + ub.as_mut().copy_from_slice(pk.get_row_slice(1)); + + // a*u + ntt_op.forward(ua.as_mut()); + mod_op.elwise_mul_mut(ua.as_mut(), u.as_ref()); + ntt_op.backward(ua.as_mut()); + + // b*u + ntt_op.forward(ub.as_mut()); + mod_op.elwise_mul_mut(ub.as_mut(), u.as_ref()); + ntt_op.backward(ub.as_mut()); + + // sample error + rlwe_out.iter_rows_mut().for_each(|ri| { + RandomGaussianDist::random_fill(rng, &q, ri.as_mut()); + }); + + // a*u + e0 + mod_op.elwise_add_mut(rlwe_out.get_row_mut(0), ua.as_ref()); + // b*u + e1 + mod_op.elwise_add_mut(rlwe_out.get_row_mut(1), ub.as_ref()); + + // b*u + e1 + m + mod_op.elwise_add_mut(rlwe_out.get_row_mut(1), m); +} + /// Generates RLWE public key pub(crate) fn gen_rlwe_public_key< Ro: RowMut + RowEntity, @@ -1778,19 +1854,20 @@ pub(crate) mod tests { carry_m[thread_rng().gen_range(0..ring_size) as usize] = 1; // RGSW(carry_m) - let rgsw_carrym = _pk_encrypt_rgsw(&carry_m, &public_key, &gadget_vector, &mod_op, &ntt_op); let mut rgsw_carrym = - RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from( - &rgsw_carrym, - ); + _pk_encrypt_rgsw(&carry_m, &public_key, &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..10 { + for i in 0..100 { let mut m = vec![0u64; ring_size as usize]; m[thread_rng().gen_range(0..ring_size) as usize] = q - 1; - let rgsw_m = _pk_encrypt_rgsw(&m, &public_key, &gadget_vector, &mod_op, &ntt_op); + let rgsw_m = { + RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from( + &_pk_encrypt_rgsw(&m, &public_key, &gadget_vector, &mod_op, &ntt_op), + ) + }; rgsw_by_rgsw_inplace( &mut rgsw_carrym.data, @@ -1805,23 +1882,19 @@ pub(crate) mod tests { 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); + _measure_noise_rgsw(&rgsw_carrym.data, &carry_m, s.values(), &gadget_vector, q); } } #[test] fn sk_rgsw_by_rgsw() { - let logq = 60; + let logq = 31; let logp = 2; - let ring_size = 1 << 11; + let ring_size = 1 << 10; let q = generate_prime(logq, ring_size, 1u64 << logq).unwrap(); let p = 1u64 << logp; - let d_rgsw = 15; - let logb = 4; + let d_rgsw = 4; + let logb = 7; let s = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize); @@ -1830,32 +1903,32 @@ pub(crate) mod tests { 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 = |a: &u64, b: &u64| ((*a as u128 * *b 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; // RGSW(carry_m) - let mut rgsw_carrym = - _sk_encrypt_rgsw(&carry_m, s.values(), &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 + }; 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 { + for i in 0..1000 { 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 - }; - + let rgsw_m = _sk_encrypt_rgsw(&m, s.values(), &gadget_vector, &mod_op, &ntt_op); rgsw_by_rgsw_inplace( - &mut rgsw_carrym.data, - &rgsw_m, + &mut rgsw_carrym, + &rgsw_m.data, &decomposer, &mut scratch_matrix_d_plus_rgsw_by_ring, &ntt_op, @@ -1863,14 +1936,9 @@ pub(crate) mod tests { ); // 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); + _measure_noise_rgsw(&rgsw_carrym, &carry_m, s.values(), &gadget_vector, q); } }