Browse Source

add non-interactive

par-agg-key-shares
Janmajaya Mall 10 months ago
parent
commit
41fab75713
1 changed files with 287 additions and 256 deletions
  1. +287
    -256
      src/noise.rs

+ 287
- 256
src/noise.rs

@ -1,261 +1,292 @@
#[cfg(test)]
mod tests {
use itertools::{izip, Itertools};
use num_traits::zero;
use rand::{thread_rng, Rng};
// use crate::{
// backend::{ArithmeticOps, ModInit, ModularOpsU64},
// decomposer::{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 decomposer = DefaultDecomposer::new(q, logb, d0);
// let gadget_vector = decomposer.gadget_vector();
// 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,
// &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];
// 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 decomposer = DefaultDecomposer::new(q, logb, d0);
// let gadget_vector = decomposer.gadget_vector();
// 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,
// &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,
// &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,
// &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}");
// }
// }
use crate::{
bool::keys::ClientKey,
ntt,
random::{
DefaultSecureRng, RandomFill, RandomFillGaussianInModulus, RandomFillUniformInModulus,
},
utils::{
fill_random_ternary_secret_with_hamming_weight, generate_prime, Stats, TryConvertFrom1,
},
ArithmeticOps, Decomposer, DefaultDecomposer, ModInit, ModularOpsU64, Ntt, NttBackendU64,
NttInit, VectorOps,
};
#[test]
fn non_interactive_multi_party() {
let logq = 56;
let ring_size = 1usize << 11;
let q = generate_prime(logq, 2 * ring_size as u64, 1 << logq).unwrap();
let logb = 1;
let d = 56;
let decomposer = DefaultDecomposer::new(q, logb, d);
let gadget_vec = decomposer.gadget_vector();
let mut rng = DefaultSecureRng::new();
let modop = ModularOpsU64::new(q);
let nttop = NttBackendU64::new(&q, ring_size);
let no_of_parties = 16;
let client_secrets = (0..no_of_parties)
.into_iter()
.map(|_| {
let mut sk = vec![0i64; ring_size];
fill_random_ternary_secret_with_hamming_weight(&mut sk, ring_size >> 1, &mut rng);
sk
})
.collect_vec();
let mut s_ideal = vec![0i64; ring_size];
client_secrets.iter().for_each(|s| {
izip!(s_ideal.iter_mut(), s.iter()).for_each(|(add_to, v)| {
*add_to = *add_to + *v;
});
});
let sk_poly_ideal = Vec::<u64>::try_convert_from(s_ideal.as_slice(), &q);
let mut sk_poly_ideal_eval = sk_poly_ideal.clone();
nttop.forward(&mut sk_poly_ideal_eval);
let mut ksk_seed = [0u8; 32];
rng.fill_bytes(&mut ksk_seed);
// zero encryptions for each party for ksk(u)
let client_zero_encs = {
client_secrets
.iter()
.map(|sk| {
let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q);
let mut sk_poly_eval = sk_poly.clone();
nttop.forward(sk_poly_eval.as_mut_slice());
let mut zero_encs =
vec![vec![0u64; ring_size]; decomposer.decomposition_count()];
let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed);
zero_encs.iter_mut().for_each(|out| {
RandomFillUniformInModulus::random_fill(
&mut ksk_prng,
&q,
out.as_mut_slice(),
);
nttop.forward(out.as_mut_slice());
modop.elwise_mul_mut(out.as_mut_slice(), &sk_poly_eval);
nttop.backward(out.as_mut_slice());
let mut error = vec![0u64; ring_size];
RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error);
modop.elwise_add_mut(out.as_mut_slice(), &error);
});
zero_encs
})
.collect_vec()
};
// main values
let main_a = {
let mut a = vec![0u64; ring_size];
RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut a);
a
};
let main_m = {
let mut main_m = vec![0u64; ring_size];
RandomFillUniformInModulus::random_fill(&mut rng, &q, &mut main_m);
main_m
};
let mut main_u = vec![0i64; ring_size];
fill_random_ternary_secret_with_hamming_weight(&mut main_u, ring_size >> 1, &mut rng);
let u_main_poly = Vec::<u64>::try_convert_from(main_u.as_slice(), &q);
let mut u_main_poly_eval = u_main_poly.clone();
nttop.forward(u_main_poly_eval.as_mut_slice());
// party 0
let (mut party0_ksk_u, mut rlwe_main_m_parta) = {
// party 0's secret
let sk = client_secrets[0].clone();
let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q);
let mut sk_poly_eval = sk_poly.clone();
nttop.forward(sk_poly_eval.as_mut_slice());
// `main_a*u + main_m` with ephemeral key u
let mut rlwe_main_m = main_a.clone();
nttop.forward(&mut rlwe_main_m);
modop.elwise_mul_mut(&mut rlwe_main_m, &u_main_poly_eval);
nttop.backward(&mut rlwe_main_m);
let mut error = vec![0u64; ring_size];
RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error);
modop.elwise_add_mut(&mut rlwe_main_m, &error);
modop.elwise_add_mut(&mut rlwe_main_m, &main_m);
// Generate KSK(u)
let mut ksk_prng = DefaultSecureRng::new_seeded(ksk_seed);
let mut ksk_u = vec![vec![0u64; ring_size]; 2 * decomposer.decomposition_count()];
let (ksk_u_a, ksk_u_b) = ksk_u.split_at_mut(decomposer.decomposition_count());
izip!(ksk_u_b.iter_mut(), ksk_u_a.iter_mut(), gadget_vec.iter()).for_each(
|(row_b, row_a, beta_i)| {
// sample a
RandomFillUniformInModulus::random_fill(&mut ksk_prng, &q, row_a.as_mut());
// s_i * a
let mut s_i_a = row_a.clone();
nttop.forward(&mut s_i_a);
modop.elwise_mul_mut(&mut s_i_a, &sk_poly_eval);
nttop.backward(&mut s_i_a);
// \beta * u
let mut beta_u = u_main_poly.clone();
modop.elwise_scalar_mul_mut(beta_u.as_mut_slice(), beta_i);
// e
RandomFillGaussianInModulus::random_fill(&mut rng, &q, row_b.as_mut_slice());
// e + \beta * u
modop.elwise_add_mut(row_b.as_mut_slice(), &beta_u);
// b = e + \beta * u + a * s_i
modop.elwise_add_mut(row_b.as_mut_slice(), &s_i_a);
},
);
// send ksk u from s_0 to s_{ideal}
ksk_u_b.iter_mut().enumerate().for_each(|(index, out_b)| {
// note: skip zero encryption of party 0
client_zero_encs.iter().skip(1).for_each(|encs| {
modop.elwise_add_mut(out_b, &encs[index]);
});
});
// // put ksk in fourier domain
// ksk_u
// .iter_mut()
// .for_each(|r| nttop.forward(r.as_mut_slice()));
(ksk_u, rlwe_main_m)
};
// Check ksk_u is correct
// {
// let (ksk_a, ksk_b) =
// party0_ksk_u.split_at_mut(decomposer.decomposition_count());
// izip!(
// ksk_a.iter(),
// ksk_b.iter(),
// decomposer.gadget_vector().iter()
// )
// .for_each(|(row_a, row_b, beta_i)| {
// // a * s
// let mut sa = row_a.clone();
// nttop.forward(&mut sa);
// modop.elwise_mul_mut(&mut sa, &sk_poly_ideal_eval);
// nttop.backward(&mut sa);
// // b - a*s
// let mut out = sa;
// modop.elwise_neg_mut(&mut out);
// modop.elwise_add_mut(&mut out, row_b);
// // beta * u
// let mut expected = u_main_poly.clone();
// modop.elwise_scalar_mul_mut(&mut expected, beta_i);
// assert_eq!(expected, out);
// });
// }
// RLWE(0) = main_a * s + e = \sum main_a*s_i + e_i
let rlwe_to_switch = {
let mut sum = vec![0u64; ring_size];
client_secrets.iter().for_each(|sk| {
let sk_poly = Vec::<u64>::try_convert_from(sk.as_slice(), &q);
let mut sk_poly_eval = sk_poly.clone();
nttop.forward(sk_poly_eval.as_mut_slice());
// a * s
let mut rlwe = main_a.clone();
nttop.forward(&mut rlwe);
modop.elwise_mul_mut(rlwe.as_mut_slice(), &sk_poly_eval);
nttop.backward(&mut rlwe);
// a * s + e
let mut error = vec![0u64; ring_size];
RandomFillGaussianInModulus::random_fill(&mut rng, &q, &mut error);
modop.elwise_add_mut(&mut rlwe, &error);
modop.elwise_add_mut(&mut sum, &rlwe);
});
sum
};
// {
// let mut tmp = main_a.clone();
// nttop.forward(&mut tmp);
// modop.elwise_mul_mut(&mut tmp, &sk_poly_ideal_eval);
// nttop.backward(&mut tmp);
// assert_eq!(&rlwe_to_switch, &tmp);
// }
// Key switch \sum decomp<RLWE(0)> * KSK(i)
let mut decomp_rlwe = vec![vec![0u64; ring_size]; decomposer.decomposition_count()];
rlwe_to_switch.iter().enumerate().for_each(|(ri, el)| {
decomposer
.decompose_iter(el)
.enumerate()
.for_each(|(j, d_el)| {
decomp_rlwe[j][ri] = d_el;
});
});
// put ksk_u and decomp<RLWE(main_a*s_ideal + e)> in fourier domain
decomp_rlwe
.iter_mut()
.for_each(|r| nttop.forward(r.as_mut_slice()));
party0_ksk_u
.iter_mut()
.for_each(|r| nttop.forward(r.as_mut_slice()));
let (ksk_u_a, ksk_u_b) = party0_ksk_u.split_at(decomposer.decomposition_count());
let mut rlwe_main_m_partb_eval = vec![vec![0u64; ring_size]; 2];
izip!(decomp_rlwe.iter(), ksk_u_a.iter(), ksk_u_b.iter()).for_each(|(o, a, b)| {
// A part
// rlwe[0] += o*a
izip!(rlwe_main_m_partb_eval[0].iter_mut(), o.iter(), a.iter()).for_each(
|(r, o, a)| {
*r = modop.add(r, &modop.mul(o, a));
},
);
// B part
// rlwe[1] += o*b
izip!(rlwe_main_m_partb_eval[1].iter_mut(), o.iter(), b.iter()).for_each(
|(r, o, b)| {
*r = modop.add(r, &modop.mul(o, b));
},
);
});
// construct RLWE_{s_{ideal}}(-sm)
nttop.forward(rlwe_main_m_parta.as_mut_slice());
modop.elwise_add_mut(&mut rlwe_main_m_partb_eval[0], &rlwe_main_m_parta);
let rlwe_main_m_eval = rlwe_main_m_partb_eval;
// decrypt RLWE_{s_{ideal}}(m) and check
let mut neg_s_m_main_out = rlwe_main_m_eval[0].clone();
modop.elwise_mul_mut(&mut neg_s_m_main_out, &sk_poly_ideal_eval);
modop.elwise_neg_mut(&mut neg_s_m_main_out);
modop.elwise_add_mut(&mut neg_s_m_main_out, &rlwe_main_m_eval[1]);
nttop.backward(&mut neg_s_m_main_out);
let mut neg_s_main_m = main_m.clone();
nttop.forward(&mut neg_s_main_m);
modop.elwise_mul_mut(&mut neg_s_main_m, &sk_poly_ideal_eval);
modop.elwise_neg_mut(&mut neg_s_main_m);
nttop.backward(&mut neg_s_main_m);
let mut diff = neg_s_m_main_out.clone();
modop.elwise_sub_mut(&mut diff, &neg_s_main_m);
let mut stat = Stats::new();
stat.add_more(&Vec::<i64>::try_convert_from(&diff, &q));
println!("Log2 Std: {}", stat.std_dev().abs().log2());
}
}

Loading…
Cancel
Save