Browse Source

test noise growth a bit more

par-agg-key-shares
Janmajaya Mall 11 months ago
parent
commit
9f229fe2a9
3 changed files with 340 additions and 0 deletions
  1. +1
    -0
      src/lib.rs
  2. +245
    -0
      src/noise.rs
  3. +94
    -0
      src/rgsw.rs

+ 1
- 0
src/lib.rs

@ -10,6 +10,7 @@ mod bool;
mod decomposer; mod decomposer;
mod lwe; mod lwe;
mod multi_party; mod multi_party;
mod noise;
mod ntt; mod ntt;
mod num; mod num;
mod random; mod random;

+ 245
- 0
src/noise.rs

@ -0,0 +1,245 @@
#[cfg(test)]
mod tests {
use rand::{thread_rng, Rng};
use crate::{
backend::{ArithmeticOps, ModInit, ModularOpsU64},
decomposer::{gadget_vector, Decomposer, DefaultDecomposer},
ntt::{Ntt, NttBackendU64, NttInit},
random::{DefaultSecureRng, RandomGaussianDist, RandomUniformDist},
rgsw::{
less1_rlwe_by_rgsw, measure_noise, rgsw_by_rgsw_inplace, rlwe_by_rgsw,
secret_key_encrypt_rgsw, secret_key_encrypt_rlwe, RgswCiphertext,
RgswCiphertextEvaluationDomain, RlweCiphertext, RlweSecret, SeededRgswCiphertext,
SeededRlweCiphertext,
},
utils::{generate_prime, negacyclic_mul},
Matrix, Row, Secret,
};
// Test B part with limbd -1 when variance of m is 1
#[test]
fn trial() {
let logq = 28;
let ring_size = 1 << 10;
let q = generate_prime(logq, (ring_size as u64) << 1, 1 << logq).unwrap();
let logb = 7;
let d0 = 3;
let d1 = d0 - 1;
let sk = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
let mut rng = DefaultSecureRng::new();
let gadget_vector = gadget_vector(logq, logb, d0);
for i in 0..100 {
// m should have norm 1
let mut m0 = vec![0u64; ring_size as usize];
m0[thread_rng().gen_range(0..ring_size)] = 1;
let modq_op = ModularOpsU64::new(q);
let nttq_op = NttBackendU64::new(q, ring_size);
// Encrypt RGSW(m0)
let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw =
SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size, d0, rgsw_seed, q);
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
secret_key_encrypt_rgsw(
&mut seeded_rgsw.data,
&m0,
&gadget_vector,
sk.values(),
&modq_op,
&nttq_op,
&mut p_rng,
&mut rng,
);
// Encrypt RLWE(m1)
let mut m1 = vec![0u64; ring_size];
RandomUniformDist::random_fill(&mut rng, &q, m1.as_mut_slice());
let mut rlwe_seed = [0u8; 32];
rng.fill_bytes(&mut rlwe_seed);
let mut seeded_rlwe: SeededRlweCiphertext<Vec<u64>, [u8; 32]> =
SeededRlweCiphertext::<Vec<u64>, _>::empty(ring_size, rlwe_seed, q);
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed);
secret_key_encrypt_rlwe(
&m1,
&mut seeded_rlwe.data,
sk.values(),
&modq_op,
&nttq_op,
&mut p_rng,
&mut rng,
);
let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_rlwe);
let rgsw = RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
&seeded_rgsw,
);
// RLWE(m0m1) = RLWE(m1) x RGSW(m0)
let mut scratch = vec![vec![0u64; ring_size]; d0 + 2];
let decomposer = DefaultDecomposer::new(q, logb, d0);
less1_rlwe_by_rgsw(
&mut rlwe,
&rgsw.data,
&mut scratch,
&decomposer,
&nttq_op,
&modq_op,
0,
1,
);
// rlwe_by_rgsw(
// &mut rlwe,
// &rgsw.data,
// &mut scratch,
// &decomposer,
// &nttq_op,
// &modq_op,
// );
// measure noise
let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) % q as u128) as u64;
let m0m1 = negacyclic_mul(&m0, &m1, mul_mod, q);
let noise = measure_noise(&rlwe, &m0m1, &nttq_op, &modq_op, sk.values());
println!("Noise: {noise}");
}
}
// Test B part with limbd -1 when variance of m is 1
#[test]
fn rgsw_saver() {
let logq = 60;
let ring_size = 1 << 11;
let q = generate_prime(logq, (ring_size as u64) << 1, 1 << logq).unwrap();
let logb = 12;
let d0 = 4;
let sk = RlweSecret::random((ring_size >> 1) as usize, ring_size as usize);
let mut rng = DefaultSecureRng::new();
let gadget_vector = gadget_vector(logq, logb, d0);
let decomposer = DefaultDecomposer::new(q, logb, d0);
for i in 0..100 {
let modq_op = ModularOpsU64::new(q);
let nttq_op = NttBackendU64::new(q, ring_size);
// Encrypt RGSW(m0)
let mut m0 = vec![0u64; ring_size as usize];
m0[thread_rng().gen_range(0..ring_size)] = 1;
let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw0 =
SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size, d0, rgsw_seed, q);
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
secret_key_encrypt_rgsw(
&mut seeded_rgsw0.data,
&m0,
&gadget_vector,
sk.values(),
&modq_op,
&nttq_op,
&mut p_rng,
&mut rng,
);
// Encrypt RGSW(m1)
let mut m1 = vec![0u64; ring_size as usize];
m1[thread_rng().gen_range(0..ring_size)] = 1;
let mut rgsw_seed = [0u8; 32];
rng.fill_bytes(&mut rgsw_seed);
let mut seeded_rgsw1 =
SeededRgswCiphertext::<Vec<Vec<u64>>, _>::empty(ring_size, d0, rgsw_seed, q);
let mut p_rng = DefaultSecureRng::new_seeded(rgsw_seed);
secret_key_encrypt_rgsw(
&mut seeded_rgsw1.data,
&m1,
&gadget_vector,
sk.values(),
&modq_op,
&nttq_op,
&mut p_rng,
&mut rng,
);
// TODO(Jay): Why cant you create RgswCIphertext from SeededRgswCiphertext?
let mut rgsw0 = {
let mut evl_tmp =
RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
&seeded_rgsw0,
);
evl_tmp
.data
.iter_mut()
.for_each(|ri| nttq_op.backward(ri.as_mut()));
evl_tmp.data
};
let rgsw1 = RgswCiphertextEvaluationDomain::<_, DefaultSecureRng, NttBackendU64>::from(
&seeded_rgsw1,
);
let mut scratch_matrix_d_plus_rgsw_by_ring = vec![vec![0u64; ring_size]; d0 + (d0 * 4)];
// RGSW(m0m1) = RGSW(m0)xRGSW(m1)
rgsw_by_rgsw_inplace(
&mut rgsw0,
&rgsw1.data,
&decomposer,
&mut scratch_matrix_d_plus_rgsw_by_ring,
&nttq_op,
&modq_op,
);
// send RGSW(m0m1) to Evaluation domain
let mut rgsw01 = rgsw0;
rgsw01
.iter_mut()
.for_each(|v| nttq_op.forward(v.as_mut_slice()));
// RLWE(m2)
let mut m2 = vec![0u64; ring_size as usize];
RandomUniformDist::random_fill(&mut rng, &q, m2.as_mut_slice());
let mut rlwe_seed = [0u8; 32];
rng.fill_bytes(&mut rlwe_seed);
let mut seeded_rlwe =
SeededRlweCiphertext::<Vec<u64>, _>::empty(ring_size, rlwe_seed, q);
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed);
secret_key_encrypt_rlwe(
&m2,
&mut seeded_rlwe.data,
sk.values(),
&modq_op,
&nttq_op,
&mut p_rng,
&mut rng,
);
let mut rlwe = RlweCiphertext::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_rlwe);
// RLWE(m0m1m2) = RLWE(m2) x RGSW(m0m1)
let mut scratch_matrix_dplus2_ring = vec![vec![0u64; ring_size]; d0 + 2];
less1_rlwe_by_rgsw(
&mut rlwe,
&rgsw01,
&mut scratch_matrix_dplus2_ring,
&decomposer,
&nttq_op,
&modq_op,
1,
2,
);
let mul_mod = |v0: &u64, v1: &u64| ((*v0 as u128 * *v1 as u128) % q as u128) as u64;
let m0m1 = negacyclic_mul(&m0, &m1, mul_mod, q);
let m0m1m2 = negacyclic_mul(&m2, &m0m1, mul_mod, q);
let noise = measure_noise(&rlwe.data, &m0m1m2, &nttq_op, &modq_op, sk.values());
println!("Noise: {noise}");
}
}
}

+ 94
- 0
src/rgsw.rs

@ -598,6 +598,100 @@ pub(crate) fn galois_auto<
.copy_from_slice(tmp_rlwe_out[1].as_ref()); .copy_from_slice(tmp_rlwe_out[1].as_ref());
} }
/// Returns RLWE(m0m1) = RLWE(m0) x RGSW(m1). Mutates rlwe_in inplace to equal
/// RLWE(m0m1)
///
/// - rlwe_in: is RLWE(m0) with polynomials in coefficient domain
/// - rgsw_in: is RGSW(m1) with polynomials in evaluation domain
/// - scratch_matrix_d_ring: is a matrix of dimension (d_rgsw, ring_size) used
/// as scratch space to store decomposed Ring elements temporarily
pub(crate) fn less1_rlwe_by_rgsw<
Mmut: MatrixMut,
MT: Matrix<MatElement = Mmut::MatElement> + MatrixMut<MatElement = Mmut::MatElement> + IsTrivial,
D: Decomposer<Element = Mmut::MatElement>,
ModOp: VectorOps<Element = Mmut::MatElement>,
NttOp: Ntt<Element = Mmut::MatElement>,
>(
rlwe_in: &mut MT,
rgsw_in: &Mmut,
scratch_matrix_dplus2_ring: &mut Mmut,
decomposer: &D,
ntt_op: &NttOp,
mod_op: &ModOp,
skip0: usize,
skip1: usize,
) where
Mmut::MatElement: Copy + Zero,
<Mmut as Matrix>::R: RowMut,
<MT as Matrix>::R: RowMut,
{
let d_rgsw = decomposer.d();
assert!(scratch_matrix_dplus2_ring.dimension() == (d_rgsw + 2, rlwe_in.dimension().1));
assert!(rgsw_in.dimension() == (d_rgsw * 4, rlwe_in.dimension().1));
// decomposed RLWE x RGSW
let (rlwe_dash_nsm, rlwe_dash_m) = rgsw_in.split_at_row(d_rgsw * 2);
let (scratch_matrix_d_ring, scratch_rlwe_out) =
scratch_matrix_dplus2_ring.split_at_row_mut(d_rgsw);
scratch_rlwe_out[0].as_mut().fill(Mmut::MatElement::zero());
scratch_rlwe_out[1].as_mut().fill(Mmut::MatElement::zero());
// RLWE_in = a_in, b_in; RLWE_out = a_out, b_out
if !rlwe_in.is_trivial() {
// a_in = 0 when RLWE_in is trivial RLWE ciphertext
// decomp<a_in>
decompose_r(rlwe_in.get_row_slice(0), scratch_matrix_d_ring, decomposer);
scratch_matrix_d_ring
.iter_mut()
.for_each(|r| ntt_op.forward(r.as_mut()));
// a_out += decomp<a_in> \cdot RLWE_A'(-sm)
routine(
scratch_rlwe_out[0].as_mut(),
scratch_matrix_d_ring[skip0..].as_ref(),
&rlwe_dash_nsm[skip0..d_rgsw],
mod_op,
);
// b_out += decomp<a_in> \cdot RLWE_B'(-sm)
routine(
scratch_rlwe_out[1].as_mut(),
scratch_matrix_d_ring[skip0..].as_ref(),
&rlwe_dash_nsm[d_rgsw + skip0..],
mod_op,
);
}
// decomp<b_in>
decompose_r(rlwe_in.get_row_slice(1), scratch_matrix_d_ring, decomposer);
scratch_matrix_d_ring
.iter_mut()
.for_each(|r| ntt_op.forward(r.as_mut()));
// a_out += decomp<b_in> \cdot RLWE_A'(m)
routine(
scratch_rlwe_out[0].as_mut(),
scratch_matrix_d_ring[skip1..].as_ref(),
&rlwe_dash_m[skip1..d_rgsw],
mod_op,
);
// b_out += decomp<b_in> \cdot RLWE_B'(m)
routine(
scratch_rlwe_out[1].as_mut(),
scratch_matrix_d_ring[skip1..].as_ref(),
&rlwe_dash_m[d_rgsw + skip1..],
mod_op,
);
// transform rlwe_out to coefficient domain
scratch_rlwe_out
.iter_mut()
.for_each(|r| ntt_op.backward(r.as_mut()));
rlwe_in
.get_row_mut(0)
.copy_from_slice(scratch_rlwe_out[0].as_mut());
rlwe_in
.get_row_mut(1)
.copy_from_slice(scratch_rlwe_out[1].as_mut());
rlwe_in.set_not_trivial();
}
/// Returns RLWE(m0m1) = RLWE(m0) x RGSW(m1). Mutates rlwe_in inplace to equal /// Returns RLWE(m0m1) = RLWE(m0) x RGSW(m1). Mutates rlwe_in inplace to equal
/// RLWE(m0m1) /// RLWE(m0m1)
/// ///

Loading…
Cancel
Save