Browse Source

change ksk to seeded ksk

par-agg-key-shares
Janmajaya Mall 11 months ago
parent
commit
99f8e71583
1 changed files with 120 additions and 52 deletions
  1. +120
    -52
      src/lwe.rs

+ 120
- 52
src/lwe.rs

@ -1,6 +1,8 @@
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::btree_map::Values,
fmt::{Debug, Display}, fmt::{Debug, Display},
marker::PhantomData,
}; };
use itertools::{izip, Itertools}; use itertools::{izip, Itertools};
@ -11,15 +13,65 @@ use crate::{
decomposer::Decomposer, decomposer::Decomposer,
lwe, lwe,
num::UnsignedInteger, num::UnsignedInteger,
random::{DefaultSecureRng, RandomGaussianDist, RandomUniformDist, DEFAULT_RNG},
random::{DefaultSecureRng, NewWithSeed, RandomGaussianDist, RandomUniformDist, DEFAULT_RNG},
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom, WithLocal}, utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom, WithLocal},
Matrix, MatrixEntity, MatrixMut, Row, RowMut, Secret,
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret,
}; };
trait LweKeySwitchParameters {
fn n_in(&self) -> usize;
fn n_out(&self) -> usize;
fn d_ks(&self) -> usize;
struct SeededLweKeySwitchingKey<Ro, S>
where
Ro: Row,
{
data: Ro,
seed: S,
to_lwe_n: usize,
modulus: Ro::Element,
}
impl<Ro: RowEntity, S> SeededLweKeySwitchingKey<Ro, S> {
pub(crate) fn empty(
from_lwe_n: usize,
to_lwe_n: usize,
d: usize,
seed: S,
modulus: Ro::Element,
) -> Self {
let data = Ro::zeros(from_lwe_n * d);
SeededLweKeySwitchingKey {
data,
to_lwe_n,
seed,
modulus,
}
}
}
struct LweKeySwitchingKey<M, R> {
data: M,
_phantom: PhantomData<R>,
}
impl<
M: MatrixMut + MatrixEntity,
R: NewWithSeed + RandomUniformDist<[M::MatElement], Parameters = M::MatElement>,
> From<&SeededLweKeySwitchingKey<M::R, R::Seed>> for LweKeySwitchingKey<M, R>
where
M::R: RowMut,
R::Seed: Clone,
M::MatElement: Copy,
{
fn from(value: &SeededLweKeySwitchingKey<M::R, R::Seed>) -> Self {
let mut p_rng = R::new_with_seed(value.seed.clone());
let mut data = M::zeros(value.data.as_ref().len(), value.to_lwe_n + 1);
izip!(value.data.as_ref().iter(), data.iter_rows_mut()).for_each(|(bi, lwe_i)| {
RandomUniformDist::random_fill(&mut p_rng, &value.modulus, &mut lwe_i.as_mut()[1..]);
lwe_i.as_mut()[0] = *bi;
});
LweKeySwitchingKey {
data,
_phantom: PhantomData,
}
}
} }
trait LweCiphertext<M: Matrix> {} trait LweCiphertext<M: Matrix> {}
@ -76,59 +128,61 @@ pub(crate) fn lwe_key_switch<
} }
pub fn lwe_ksk_keygen< pub fn lwe_ksk_keygen<
Mmut: MatrixMut,
Ro: Row + RowMut + RowEntity,
S, S,
Op: VectorOps<Element = Mmut::MatElement> + ArithmeticOps<Element = Mmut::MatElement>,
R: RandomGaussianDist<Mmut::MatElement, Parameters = Mmut::MatElement>
+ RandomUniformDist<[Mmut::MatElement], Parameters = Mmut::MatElement>,
Op: VectorOps<Element = Ro::Element> + ArithmeticOps<Element = Ro::Element>,
R: RandomGaussianDist<Ro::Element, Parameters = Ro::Element>
+ RandomUniformDist<[Ro::Element], Parameters = Ro::Element>
+ NewWithSeed,
>( >(
from_lwe_sk: &[S], from_lwe_sk: &[S],
to_lwe_sk: &[S], to_lwe_sk: &[S],
ksk_out: &mut Mmut,
gadget: &[Mmut::MatElement],
ksk_out: &mut Ro,
gadget: &[Ro::Element],
seed: R::Seed,
operator: &Op, operator: &Op,
rng: &mut R, rng: &mut R,
) where ) where
<Mmut as Matrix>::R: RowMut,
Mmut::R: TryConvertFrom<[S], Parameters = Mmut::MatElement>,
Mmut::MatElement: Zero + Debug,
Ro: TryConvertFrom<[S], Parameters = Ro::Element>,
Ro::Element: Zero + Debug,
{ {
assert!(ksk_out.dimension() == (from_lwe_sk.len() * gadget.len(), to_lwe_sk.len() + 1,));
assert!(ksk_out.as_ref().len() == (from_lwe_sk.len() * gadget.len()));
let d = gadget.len(); let d = gadget.len();
let modulus = VectorOps::modulus(operator); let modulus = VectorOps::modulus(operator);
let mut neg_sk_in_m = Mmut::R::try_convert_from(from_lwe_sk, &modulus);
let mut neg_sk_in_m = Ro::try_convert_from(from_lwe_sk, &modulus);
operator.elwise_neg_mut(neg_sk_in_m.as_mut()); operator.elwise_neg_mut(neg_sk_in_m.as_mut());
let sk_out_m = Mmut::R::try_convert_from(to_lwe_sk, &modulus);
izip!(
neg_sk_in_m.as_ref(),
ksk_out.iter_rows_mut().chunks(d).into_iter()
)
.for_each(|(neg_sk_in_si, d_ks_lwes)| {
izip!(gadget.iter(), d_ks_lwes.into_iter()).for_each(|(f, lwe)| {
// sample `a`
RandomUniformDist::random_fill(rng, &modulus, &mut lwe.as_mut()[1..]);
// a * z
let mut az = Mmut::MatElement::zero();
izip!(lwe.as_ref()[1..].iter(), sk_out_m.as_ref()).for_each(|(ai, si)| {
let ai_si = operator.mul(ai, si);
az = operator.add(&az, &ai_si);
});
// a*z + (-s_i)*\beta^j + e
let mut b = operator.add(&az, &operator.mul(f, neg_sk_in_si));
let mut e = Mmut::MatElement::zero();
RandomGaussianDist::random_fill(rng, &modulus, &mut e);
b = operator.add(&b, &e);
lwe.as_mut()[0] = b;
// dbg!(&lwe.as_mut(), &f);
})
});
let sk_out_m = Ro::try_convert_from(to_lwe_sk, &modulus);
let mut scratch = Ro::zeros(to_lwe_sk.len());
let mut p_rng = R::new_with_seed(seed);
izip!(neg_sk_in_m.as_ref(), ksk_out.as_mut().chunks_mut(d)).for_each(
|(neg_sk_in_si, d_lwes_partb)| {
izip!(gadget.iter(), d_lwes_partb.into_iter()).for_each(|(f, lwe_b)| {
// sample `a`
RandomUniformDist::random_fill(&mut p_rng, &modulus, scratch.as_mut());
// a * z
let mut az = Ro::Element::zero();
izip!(scratch.as_ref().iter(), sk_out_m.as_ref()).for_each(|(ai, si)| {
let ai_si = operator.mul(ai, si);
az = operator.add(&az, &ai_si);
});
// a*z + (-s_i)*\beta^j + e
let mut b = operator.add(&az, &operator.mul(f, neg_sk_in_si));
let mut e = Ro::Element::zero();
RandomGaussianDist::random_fill(rng, &modulus, &mut e);
b = operator.add(&b, &e);
*lwe_b = b;
// dbg!(&lwe.as_mut(), &f);
})
},
);
} }
/// Encrypts encoded message m as LWE ciphertext /// Encrypts encoded message m as LWE ciphertext
@ -231,9 +285,12 @@ mod tests {
Secret, Secret,
}; };
use super::{decrypt_lwe, encrypt_lwe, lwe_ksk_keygen, LweSecret};
use super::{
decrypt_lwe, encrypt_lwe, lwe_ksk_keygen, LweKeySwitchingKey, LweSecret,
SeededLweKeySwitchingKey,
};
const K: usize = 500;
const K: usize = 50;
#[test] #[test]
fn encrypt_decrypt_works() { fn encrypt_decrypt_works() {
@ -274,7 +331,7 @@ mod tests {
let lwe_in_n = 2048; let lwe_in_n = 2048;
let lwe_out_n = 493; let lwe_out_n = 493;
let d_ks = 3; let d_ks = 3;
let logb = 5;
let logb = 4;
let lwe_sk_in = LweSecret::random(lwe_in_n >> 1, lwe_in_n); let lwe_sk_in = LweSecret::random(lwe_in_n >> 1, lwe_in_n);
let lwe_sk_out = LweSecret::random(lwe_out_n >> 1, lwe_out_n); let lwe_sk_out = LweSecret::random(lwe_out_n >> 1, lwe_out_n);
@ -284,17 +341,22 @@ mod tests {
// genrate ksk // genrate ksk
for _ in 0..K { for _ in 0..K {
let mut ksk = vec![vec![0u64; lwe_out_n + 1]; d_ks * lwe_in_n];
let mut ksk_seed = [0u8; 32];
rng.fill_bytes(&mut ksk_seed);
let mut seeded_ksk =
SeededLweKeySwitchingKey::empty(lwe_in_n, lwe_out_n, d_ks, ksk_seed, q);
let gadget = gadget_vector(logq, logb, d_ks); let gadget = gadget_vector(logq, logb, d_ks);
lwe_ksk_keygen( lwe_ksk_keygen(
&lwe_sk_in.values(), &lwe_sk_in.values(),
&lwe_sk_out.values(), &lwe_sk_out.values(),
&mut ksk,
&mut seeded_ksk.data,
&gadget, &gadget,
seeded_ksk.seed,
&modq_op, &modq_op,
&mut rng, &mut rng,
); );
// println!("{:?}", ksk); // println!("{:?}", ksk);
let ksk = LweKeySwitchingKey::<Vec<Vec<u64>>, DefaultSecureRng>::from(&seeded_ksk);
for m in 0..(1 << logp) { for m in 0..(1 << logp) {
// encrypt using lwe_sk_in // encrypt using lwe_sk_in
@ -311,7 +373,13 @@ mod tests {
// key switch from lwe_sk_in to lwe_sk_out // key switch from lwe_sk_in to lwe_sk_out
let decomposer = DefaultDecomposer::new(1u64 << logq, logb, d_ks); let decomposer = DefaultDecomposer::new(1u64 << logq, logb, d_ks);
let mut lwe_out_ct = vec![0u64; lwe_out_n + 1]; let mut lwe_out_ct = vec![0u64; lwe_out_n + 1];
lwe_key_switch(&mut lwe_out_ct, &lwe_in_ct, &ksk, &modq_op, &decomposer);
lwe_key_switch(
&mut lwe_out_ct,
&lwe_in_ct,
&ksk.data,
&modq_op,
&decomposer,
);
// decrypt lwe_out_ct using lwe_sk_out // decrypt lwe_out_ct using lwe_sk_out
let encoded_m_back = decrypt_lwe(&lwe_out_ct, &lwe_sk_out.values(), &modq_op); let encoded_m_back = decrypt_lwe(&lwe_out_ct, &lwe_sk_out.values(), &modq_op);

Loading…
Cancel
Save