mirror of
https://github.com/arnaucube/phantom-zone.git
synced 2026-01-07 22:51:29 +01:00
test noise growth a bit more
This commit is contained in:
@@ -10,6 +10,7 @@ mod bool;
|
||||
mod decomposer;
|
||||
mod lwe;
|
||||
mod multi_party;
|
||||
mod noise;
|
||||
mod ntt;
|
||||
mod num;
|
||||
mod random;
|
||||
|
||||
245
src/noise.rs
Normal file
245
src/noise.rs
Normal file
@@ -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
src/rgsw.rs
94
src/rgsw.rs
@@ -598,6 +598,100 @@ pub(crate) fn galois_auto<
|
||||
.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
|
||||
/// RLWE(m0m1)
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user