|
@@ -4,6 +4,8 @@ use crate::{
|
|
|
use rand::{Rng, SeedableRng};
|
|
|
use rand_chacha::ChaCha20Rng;
|
|
|
use std::{iter::once, mem::size_of};
|
|
|
+use std::sync::Mutex;
|
|
|
+use thread_local::ThreadLocal;
|
|
|
|
|
|
fn new_vec_raw<'a>(
|
|
|
params: &'a Params,
|
|
@@ -203,15 +205,15 @@ impl<'a> Query<'a> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub struct Client<'a, T: Rng> {
|
|
|
+pub struct Client<'a, T: Rng + Send> {
|
|
|
params: &'a Params,
|
|
|
sk_gsw: PolyMatrixRaw<'a>,
|
|
|
sk_reg: PolyMatrixRaw<'a>,
|
|
|
sk_gsw_full: PolyMatrixRaw<'a>,
|
|
|
sk_reg_full: PolyMatrixRaw<'a>,
|
|
|
- dg: DiscreteGaussian<'a, T>,
|
|
|
- public_rng: ChaCha20Rng,
|
|
|
- public_seed: <ChaCha20Rng as SeedableRng>::Seed,
|
|
|
+ dg: DiscreteGaussian<T>,
|
|
|
+ public_rng: ThreadLocal<Mutex<ChaCha20Rng>>,
|
|
|
+ public_seed: ThreadLocal<<ChaCha20Rng as SeedableRng>::Seed>,
|
|
|
}
|
|
|
|
|
|
fn matrix_with_identity<'a>(p: &PolyMatrixRaw<'a>) -> PolyMatrixRaw<'a> {
|
|
@@ -242,18 +244,17 @@ fn params_with_moduli(params: &Params, moduli: &Vec<u64>) -> Params {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-impl<'a, T: Rng> Client<'a, T> {
|
|
|
- pub fn init(params: &'a Params, rng: &'a mut T) -> Self {
|
|
|
+impl<'a, T: Rng + Send> Client<'a, T> {
|
|
|
+ pub fn init(params: &'a Params, rnggen: fn() -> T) -> Self {
|
|
|
let sk_gsw_dims = params.get_sk_gsw();
|
|
|
let sk_reg_dims = params.get_sk_reg();
|
|
|
let sk_gsw = PolyMatrixRaw::zero(params, sk_gsw_dims.0, sk_gsw_dims.1);
|
|
|
let sk_reg = PolyMatrixRaw::zero(params, sk_reg_dims.0, sk_reg_dims.1);
|
|
|
let sk_gsw_full = matrix_with_identity(&sk_gsw);
|
|
|
let sk_reg_full = matrix_with_identity(&sk_reg);
|
|
|
- let mut public_seed = [0u8; 32];
|
|
|
- rng.fill_bytes(&mut public_seed);
|
|
|
- let public_rng = ChaCha20Rng::from_seed(public_seed);
|
|
|
- let dg = DiscreteGaussian::init(params, rng);
|
|
|
+ let public_seed = ThreadLocal::new();
|
|
|
+ let dg = DiscreteGaussian::init(params, rnggen);
|
|
|
+ let public_rng = ThreadLocal::new();
|
|
|
Self {
|
|
|
params,
|
|
|
sk_gsw,
|
|
@@ -271,24 +272,23 @@ impl<'a, T: Rng> Client<'a, T> {
|
|
|
&self.sk_reg
|
|
|
}
|
|
|
|
|
|
- pub fn get_rng(&mut self) -> &mut T {
|
|
|
- &mut self.dg.rng
|
|
|
+ pub fn get_public_seed(&self) -> <ChaCha20Rng as SeedableRng>::Seed {
|
|
|
+ *self.public_seed.get_or( || {
|
|
|
+ let mut seed = [0u8; 32];
|
|
|
+ self.dg.get_rng().fill_bytes(&mut seed);
|
|
|
+ seed
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
- pub fn get_public_rng(&mut self) -> &mut ChaCha20Rng {
|
|
|
- &mut self.public_rng
|
|
|
- }
|
|
|
-
|
|
|
- pub fn get_public_seed(&mut self) -> <ChaCha20Rng as SeedableRng>::Seed {
|
|
|
- self.public_seed
|
|
|
- }
|
|
|
-
|
|
|
- fn get_fresh_gsw_public_key(&mut self, m: usize) -> PolyMatrixRaw<'a> {
|
|
|
+ fn get_fresh_gsw_public_key(&self, m: usize) -> PolyMatrixRaw<'a> {
|
|
|
let params = self.params;
|
|
|
let n = params.n;
|
|
|
|
|
|
- let a = PolyMatrixRaw::random_rng(params, 1, m, self.get_rng());
|
|
|
- let e = PolyMatrixRaw::noise(params, n, m, &mut self.dg);
|
|
|
+ let a = {
|
|
|
+ let rng = &mut *self.dg.get_rng();
|
|
|
+ PolyMatrixRaw::random_rng(params, 1, m, rng)
|
|
|
+ };
|
|
|
+ let e = PolyMatrixRaw::noise(params, n, m, &self.dg);
|
|
|
let a_inv = -&a;
|
|
|
let b_p = &self.sk_gsw.ntt() * &a.ntt();
|
|
|
let b = &e.ntt() + &b_p;
|
|
@@ -296,10 +296,16 @@ impl<'a, T: Rng> Client<'a, T> {
|
|
|
p
|
|
|
}
|
|
|
|
|
|
- fn get_regev_sample(&mut self) -> PolyMatrixNTT<'a> {
|
|
|
+ fn get_regev_sample(&self) -> PolyMatrixNTT<'a> {
|
|
|
let params = self.params;
|
|
|
- let a = PolyMatrixRaw::random_rng(params, 1, 1, self.get_public_rng());
|
|
|
- let e = PolyMatrixRaw::noise(params, 1, 1, &mut self.dg);
|
|
|
+ let a = {
|
|
|
+ let public_rng = &mut *self.public_rng.get_or(|| {
|
|
|
+ Mutex::new(ChaCha20Rng::from_seed(self.get_public_seed()))
|
|
|
+ })
|
|
|
+ .lock().unwrap();
|
|
|
+ PolyMatrixRaw::random_rng(params, 1, 1, public_rng)
|
|
|
+ };
|
|
|
+ let e = PolyMatrixRaw::noise(params, 1, 1, &self.dg);
|
|
|
let b_p = &self.sk_reg.ntt() * &a.ntt();
|
|
|
let b = &e.ntt() + &b_p;
|
|
|
let mut p = PolyMatrixNTT::zero(params, 2, 1);
|
|
@@ -308,7 +314,7 @@ impl<'a, T: Rng> Client<'a, T> {
|
|
|
p
|
|
|
}
|
|
|
|
|
|
- fn get_fresh_reg_public_key(&mut self, m: usize) -> PolyMatrixNTT<'a> {
|
|
|
+ fn get_fresh_reg_public_key(&self, m: usize) -> PolyMatrixNTT<'a> {
|
|
|
let params = self.params;
|
|
|
|
|
|
let mut p = PolyMatrixNTT::zero(params, 2, m);
|
|
@@ -319,29 +325,29 @@ impl<'a, T: Rng> Client<'a, T> {
|
|
|
p
|
|
|
}
|
|
|
|
|
|
- fn encrypt_matrix_gsw(&mut self, ag: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
+ fn encrypt_matrix_gsw(&self, ag: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
let mx = ag.cols;
|
|
|
let p = self.get_fresh_gsw_public_key(mx);
|
|
|
let res = &(p.ntt()) + &(ag.pad_top(1));
|
|
|
res
|
|
|
}
|
|
|
|
|
|
- pub fn encrypt_matrix_reg(&mut self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
+ pub fn encrypt_matrix_reg(&self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
let m = a.cols;
|
|
|
let p = self.get_fresh_reg_public_key(m);
|
|
|
&p + &a.pad_top(1)
|
|
|
}
|
|
|
|
|
|
- pub fn decrypt_matrix_reg(&mut self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
+ pub fn decrypt_matrix_reg(&self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
&self.sk_reg_full.ntt() * a
|
|
|
}
|
|
|
|
|
|
- pub fn decrypt_matrix_gsw(&mut self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
+ pub fn decrypt_matrix_gsw(&self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
|
|
|
&self.sk_gsw_full.ntt() * a
|
|
|
}
|
|
|
|
|
|
fn generate_expansion_params(
|
|
|
- &mut self,
|
|
|
+ &self,
|
|
|
num_exp: usize,
|
|
|
m_exp: usize,
|
|
|
) -> Vec<PolyMatrixNTT<'a>> {
|
|
@@ -414,7 +420,7 @@ impl<'a, T: Rng> Client<'a, T> {
|
|
|
pp
|
|
|
}
|
|
|
|
|
|
- pub fn generate_query(&mut self, idx_target: usize) -> Query<'a> {
|
|
|
+ pub fn generate_query(&self, idx_target: usize) -> Query<'a> {
|
|
|
let params = self.params;
|
|
|
let further_dims = params.db_dim_2;
|
|
|
let idx_dim0 = idx_target / (1 << further_dims);
|
|
@@ -582,7 +588,8 @@ impl<'a, T: Rng> Client<'a, T> {
|
|
|
|
|
|
#[cfg(test)]
|
|
|
mod test {
|
|
|
- use rand::thread_rng;
|
|
|
+ use rand::SeedableRng;
|
|
|
+ use rand_chacha::ChaCha20Rng;
|
|
|
|
|
|
use super::*;
|
|
|
|
|
@@ -598,8 +605,7 @@ mod test {
|
|
|
#[test]
|
|
|
fn init_is_correct() {
|
|
|
let params = get_params();
|
|
|
- let mut rng = thread_rng();
|
|
|
- let client = Client::init(¶ms, &mut rng);
|
|
|
+ let client = Client::init(¶ms, ChaCha20Rng::from_entropy);
|
|
|
|
|
|
assert_eq!(*client.params, params);
|
|
|
}
|
|
@@ -607,8 +613,8 @@ mod test {
|
|
|
#[test]
|
|
|
fn keygen_is_correct() {
|
|
|
let params = get_params();
|
|
|
- let mut seeded_rng = get_static_seeded_rng();
|
|
|
- let mut client = Client::init(¶ms, &mut seeded_rng);
|
|
|
+ let mut client = Client::init(¶ms, get_static_seeded_rng);
|
|
|
+ client.get_public_seed();
|
|
|
|
|
|
let pub_params = client.generate_keys();
|
|
|
|
|
@@ -639,8 +645,7 @@ mod test {
|
|
|
}
|
|
|
|
|
|
fn public_parameters_serialization_is_correct_for_params(params: Params) {
|
|
|
- let mut seeded_rng = get_static_seeded_rng();
|
|
|
- let mut client = Client::init(¶ms, &mut seeded_rng);
|
|
|
+ let mut client = Client::init(¶ms, get_static_seeded_rng);
|
|
|
let pub_params = client.generate_keys();
|
|
|
|
|
|
let serialized1 = pub_params.serialize();
|
|
@@ -704,8 +709,7 @@ mod test {
|
|
|
}
|
|
|
|
|
|
fn query_serialization_is_correct_for_params(params: Params) {
|
|
|
- let mut seeded_rng = get_static_seeded_rng();
|
|
|
- let mut client = Client::init(¶ms, &mut seeded_rng);
|
|
|
+ let mut client = Client::init(¶ms, get_static_seeded_rng);
|
|
|
_ = client.generate_keys();
|
|
|
let query = client.generate_query(1);
|
|
|
|