Browse Source

clean rgsw/keygen

par-agg-key-shares
Janmajaya Mall 9 months ago
parent
commit
acc51ce402
6 changed files with 102 additions and 75 deletions
  1. +4
    -4
      src/bool/evaluator.rs
  2. +2
    -2
      src/bool/ni_mp_api.rs
  3. +5
    -16
      src/ntt.rs
  4. +79
    -42
      src/rgsw/keygen.rs
  5. +7
    -6
      src/rgsw/mod.rs
  6. +5
    -5
      src/utils.rs

+ 4
- 4
src/bool/evaluator.rs

@ -25,8 +25,8 @@ use crate::{
RandomFillUniformInModulus, RandomGaussianElementInModulus, RandomFillUniformInModulus, RandomGaussianElementInModulus,
}, },
rgsw::{ rgsw::{
decrypt_rlwe, galois_auto, galois_key_gen, generate_auto_map, public_key_encrypt_rgsw,
rgsw_by_rgsw_inplace, secret_key_encrypt_rgsw,
decrypt_rlwe, galois_auto, generate_auto_map, public_key_encrypt_rgsw,
rgsw_by_rgsw_inplace, secret_key_encrypt_rgsw, seeded_auto_key_gen,
}, },
utils::{ utils::{
encode_x_pow_si_with_emebedding_factor, fill_random_ternary_secret_with_hamming_weight, encode_x_pow_si_with_emebedding_factor, fill_random_ternary_secret_with_hamming_weight,
@ -864,7 +864,7 @@ where
(g.pow(i as u32) % br_q) as isize (g.pow(i as u32) % br_q) as isize
}; };
let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n); let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n);
galois_key_gen(
seeded_auto_key_gen(
&mut gk, &mut gk,
&sk_rlwe, &sk_rlwe,
g_pow, g_pow,
@ -2010,7 +2010,7 @@ where
self.pbs_info.auto_decomposer.decomposition_count(), self.pbs_info.auto_decomposer.decomposition_count(),
ring_size, ring_size,
); );
galois_key_gen(
seeded_auto_key_gen(
&mut ksk_out, &mut ksk_out,
sk_rlwe, sk_rlwe,
g_pow, g_pow,

+ 2
- 2
src/bool/ni_mp_api.rs

@ -178,7 +178,7 @@ mod impl_enc_dec {
bool::{evaluator::BoolEncoding, keys::NonInteractiveMultiPartyClientKey}, bool::{evaluator::BoolEncoding, keys::NonInteractiveMultiPartyClientKey},
pbs::{sample_extract, PbsInfo, WithShoupRepr}, pbs::{sample_extract, PbsInfo, WithShoupRepr},
random::{NewWithSeed, RandomFillUniformInModulus}, random::{NewWithSeed, RandomFillUniformInModulus},
rgsw::{key_switch, secret_key_encrypt_rlwe},
rgsw::{key_switch, seeded_secret_key_encrypt_rlwe},
utils::TryConvertFrom1, utils::TryConvertFrom1,
Encryptor, KeySwitchWithId, Matrix, MatrixEntity, MatrixMut, RowEntity, RowMut, Encryptor, KeySwitchWithId, Matrix, MatrixEntity, MatrixMut, RowEntity, RowMut,
}; };
@ -296,7 +296,7 @@ mod impl_enc_dec {
let mut rlwe_out = let mut rlwe_out =
<<Mat as Matrix>::R as RowEntity>::zeros(parameters.rlwe_n().0); <<Mat as Matrix>::R as RowEntity>::zeros(parameters.rlwe_n().0);
secret_key_encrypt_rlwe(
seeded_secret_key_encrypt_rlwe(
&message, &message,
&mut rlwe_out, &mut rlwe_out,
&sk_u, &sk_u,

+ 5
- 16
src/ntt.rs

@ -50,7 +50,7 @@ pub fn forward_butterly_0_to_4q(
pub fn forward_butterly_0_to_2q( pub fn forward_butterly_0_to_2q(
mut x: u64, mut x: u64,
mut y: u64,
y: u64,
w: u64, w: u64,
w_shoup: u64, w_shoup: u64,
q: u64, q: u64,
@ -310,7 +310,7 @@ pub(crate) fn find_primitive_root(q: u64, n: u64, rng: &mut R) -> Op
pub struct NttBackendU64 { pub struct NttBackendU64 {
q: u64, q: u64,
q_twice: u64, q_twice: u64,
n: u64,
_n: u64,
n_inv: u64, n_inv: u64,
n_inv_shoup: u64, n_inv_shoup: u64,
psi_powers_bo: Box<[u64]>, psi_powers_bo: Box<[u64]>,
@ -374,7 +374,7 @@ impl NttBackendU64 {
NttBackendU64 { NttBackendU64 {
q, q,
q_twice: 2 * q, q_twice: 2 * q,
n: n as u64,
_n: n as u64,
n_inv, n_inv,
n_inv_shoup: ShoupMul::representation(n_inv, q), n_inv_shoup: ShoupMul::representation(n_inv, q),
psi_powers_bo: psi_powers_bo.into_boxed_slice(), psi_powers_bo: psi_powers_bo.into_boxed_slice(),
@ -393,17 +393,6 @@ impl> NttInit for NttBackendU64 {
} }
} }
impl NttBackendU64 {
fn reduce_from_lazy(&self, a: &mut [u64]) {
let q = self.q;
a.iter_mut().for_each(|a0| {
if *a0 >= q {
*a0 = *a0 - q;
}
});
}
}
impl Ntt for NttBackendU64 { impl Ntt for NttBackendU64 {
type Element = u64; type Element = u64;
@ -458,9 +447,9 @@ mod tests {
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use rand_distr::Uniform; use rand_distr::Uniform;
use super::{NttBackendU64, NttInit};
use super::NttBackendU64;
use crate::{ use crate::{
backend::{ArithmeticOps, ModInit, ModularOpsU64, VectorOps},
backend::{ModInit, ModularOpsU64, VectorOps},
ntt::Ntt, ntt::Ntt,
utils::{generate_prime, negacyclic_mul}, utils::{generate_prime, negacyclic_mul},
}; };

+ 79
- 42
src/rgsw/keygen.rs

@ -1,25 +1,16 @@
use std::{
clone,
fmt::Debug,
iter,
marker::PhantomData,
ops::{Div, Neg, Sub},
};
use std::{fmt::Debug, ops::Sub};
use itertools::{izip, Itertools};
use itertools::izip;
use num_traits::{PrimInt, Signed, ToPrimitive, Zero}; use num_traits::{PrimInt, Signed, ToPrimitive, Zero};
use crate::{ use crate::{
backend::{ArithmeticOps, GetModulus, Modulus, VectorOps}, backend::{ArithmeticOps, GetModulus, Modulus, VectorOps},
decomposer::{self, Decomposer, RlweDecomposer},
ntt::{self, Ntt, NttInit},
ntt::Ntt,
random::{ random::{
DefaultSecureRng, NewWithSeed, RandomElementInModulus, RandomFill,
RandomFillGaussianInModulus, RandomFillUniformInModulus,
RandomElementInModulus, RandomFill, RandomFillGaussianInModulus, RandomFillUniformInModulus,
}, },
rgsw::decompose_r,
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom1, WithLocal},
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut, Secret, ShoupMatrixFMA,
utils::{fill_random_ternary_secret_with_hamming_weight, TryConvertFrom1},
Matrix, MatrixEntity, MatrixMut, Row, RowEntity, RowMut,
}; };
pub(crate) fn generate_auto_map(ring_size: usize, k: isize) -> (Vec<usize>, Vec<bool>) { pub(crate) fn generate_auto_map(ring_size: usize, k: isize) -> (Vec<usize>, Vec<bool>) {
@ -49,13 +40,31 @@ pub(crate) fn generate_auto_map(ring_size: usize, k: isize) -> (Vec, Vec<
(auto_map_index, auto_sign_index) (auto_map_index, auto_sign_index)
} }
/// Encrypts message m as a RGSW ciphertext.
/// Returns RGSW(m)
///
/// RGSW = [RLWE'(-sm) || RLWE(m)] = [RLWE'_A(-sm), RLWE'_B(-sm), RLWE'_A(m),
/// RLWE'_B(m)]
///
/// RGSW(m1) ciphertext is used for RLWE(m0) x RGSW(m1) multiplication.
/// Let RLWE(m) = [a, b] where b = as + e + m0.
/// For RLWExRGSW we calculate:
/// (\sum signed_decompose(a)[i] x RLWE(-s \beta^i' m1))
/// + (\sum signed_decompose(b)[i'] x RLWE(\beta^i' m1))
/// = RLWE(m0m1)
/// We denote decomposer count for signed_decompose(a)[i] with d_a and
/// corresponding gadget vector with `gadget_a`. We denote decomposer count for
/// signed_decompose(b)[i] with d_b and corresponding gadget vector with
/// `gadget_b`
/// ///
/// - m_eval: is `m` is evaluation domain
/// - out_rgsw: RGSW(m) is stored as single matrix of dimension (d_rgsw * 3,
/// ring_size). The matrix has the following structure [RLWE'_A(-sm) ||
/// RLWE'_B(-sm) || RLWE'_B(m)]^T and RLWE'_A(m) is generated via seed (where
/// p_rng is assumed to be seeded with seed)
/// In secret key RGSW encrypton RLWE'_A(m) can be seeded. Hence, we seed it
/// using the `p_rng` passed and the retured RGSW ciphertext has d_a * 2 + d_b
/// rows
///
/// - s: is the secret key
/// - m: message to encrypt
/// - gadget_a: Gadget vector for RLWE'(-sm)
/// - gadget_b: Gadget vector for RLWE'(m)
/// - p_rng: Seeded psuedo random generator used to sample RLWE'_A(m).
pub(crate) fn secret_key_encrypt_rgsw< pub(crate) fn secret_key_encrypt_rgsw<
Mmut: MatrixMut + MatrixEntity, Mmut: MatrixMut + MatrixEntity,
S, S,
@ -150,6 +159,13 @@ pub(crate) fn secret_key_encrypt_rgsw<
}); });
} }
/// Returns RGSW(m) encrypted with public key
///
/// Follows the same routine as `secret_key_encrypt_rgsw` but with the
/// difference that each RLWE encryption uses public key instead of secret key.
///
/// Since public key encryption cannot be seeded `RLWE'_A(m)` is included in the
/// ciphertext. Hence the returned RGSW ciphertext has d_a * 2 + d_b * 2 rows
pub(crate) fn public_key_encrypt_rgsw< pub(crate) fn public_key_encrypt_rgsw<
Mmut: MatrixMut + MatrixEntity, Mmut: MatrixMut + MatrixEntity,
M: Matrix<MatElement = Mmut::MatElement>, M: Matrix<MatElement = Mmut::MatElement>,
@ -269,20 +285,25 @@ pub(crate) fn public_key_encrypt_rgsw<
}); });
} }
/// Generates RLWE Key switching key to key switch ciphertext RLWE_{from_s}(m)
/// Returns key switching key to key switch ciphertext RLWE_{from_s}(m)
/// to RLWE_{to_s}(m). /// to RLWE_{to_s}(m).
/// ///
/// Key switching equals
/// \sum decompose(c_1)_i * RLWE_{to_s}(\beta^i -from_s)
/// Hence, key switchin key equals RLWE'(-from_s) = RLWE(-from_s), RLWE(beta^1
/// -from_s), ..., RLWE(beta^{d-1} -from_s).
/// Let key switching decomposer have `d` decompostion count with gadget vector:
/// [1, \beta, ..., \beta^d-1]
/// ///
/// - ksk_out: Output Key switching key. Key switching key stores only part B
/// polynomials of ksk RLWE ciphertexts (i.e. RLWE'_B(-from_s)) in coefficient
/// domain
/// - neg_from_s: Negative of secret polynomial to key switch from
/// Key switching key consists of `d` RLWE ciphertexts:
/// RLWE'_{to_s}(-from_s) = [RLWE_{to_s}(\beta^i -from_s)]
///
/// In RLWE(m) s.t. b = as + e + m where s is the secret key, `a` can be seeded.
/// And we seed all RLWE ciphertexts in key switchin key.
///
/// - neg_from_s: Negative of secret polynomial to key switch from (i.e.
/// -from_s)
/// - to_s: secret polynomial to key switch to. /// - to_s: secret polynomial to key switch to.
pub(crate) fn rlwe_ksk_gen<
/// - gadget_vector: Gadget vector of decomposer used in key switch
/// - p_rng: Seeded pseudo random generate used to generate `a` polynomials of
/// key switching key RLWE ciphertexts
fn seeded_rlwe_ksk_gen<
Mmut: MatrixMut + MatrixEntity, Mmut: MatrixMut + MatrixEntity,
ModOp: ArithmeticOps<Element = Mmut::MatElement> ModOp: ArithmeticOps<Element = Mmut::MatElement>
+ VectorOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>
@ -341,7 +362,18 @@ pub(crate) fn rlwe_ksk_gen<
}); });
} }
pub(crate) fn galois_key_gen<
/// Returns auto key to send RLWE(m(X)) -> RLWE(m(X^k))
///
/// Auto key is key switchin key that key-switches RLWE_{s(X^k)}(m(X^k)) to
/// RLWE_{s(X)}(m(X^k)).
///
/// - s: secret polynomial s(X)
/// - auto_k: k used in for autmorphism X -> X^k
/// - gadget_vector: Gadget vector corresponding to decomposer used in key
/// switch
/// - p_rng: pseudo random generator used to generate `a` polynomials of key
/// switching key RLWE ciphertexts
pub(crate) fn seeded_auto_key_gen<
Mmut: MatrixMut + MatrixEntity, Mmut: MatrixMut + MatrixEntity,
ModOp: ArithmeticOps<Element = Mmut::MatElement> ModOp: ArithmeticOps<Element = Mmut::MatElement>
+ VectorOps<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>
@ -385,7 +417,7 @@ pub(crate) fn galois_key_gen<
); );
// Ksk from -s(X^k) to s(X) // Ksk from -s(X^k) to s(X)
rlwe_ksk_gen(
seeded_rlwe_ksk_gen(
ksk_out, ksk_out,
neg_s_auto, neg_s_auto,
s, s,
@ -397,12 +429,14 @@ pub(crate) fn galois_key_gen<
); );
} }
/// Encrypt polynomial m(X) as RLWE ciphertext.
/// Returns seeded RLWE(m(X))
///
/// RLWE(m(X)) = [a(X), b(X) = a(X)s(X) + e(X) + m(X)]
/// ///
/// - rlwe_out: returned RLWE ciphertext RLWE(m) in coefficient domain. RLWE
/// ciphertext is a matirx with first row consiting polynomial `a` and the
/// second rows consting polynomial `b`
pub(crate) fn secret_key_encrypt_rlwe<
/// a(X) of RLWE encyrptions using secret key s(X) can be seeded. We use seeded
/// pseudo random generator `p_rng` to sample a(X) and return seeded RLWE
/// ciphertext (i.e. only b(X))
pub(crate) fn seeded_secret_key_encrypt_rlwe<
Ro: Row + RowMut + RowEntity, Ro: Row + RowMut + RowEntity,
ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>, ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
NttOp: Ntt<Element = Ro::Element>, NttOp: Ntt<Element = Ro::Element>,
@ -446,6 +480,9 @@ pub(crate) fn secret_key_encrypt_rlwe<
mod_op.elwise_add_mut(b_rlwe_out.as_mut(), sa.as_ref()); mod_op.elwise_add_mut(b_rlwe_out.as_mut(), sa.as_ref());
} }
/// Returns RLWE(m(X)) encrypted using public key.
///
/// Unlike secret key encryption, public key encryption cannot be seeded
pub(crate) fn public_key_encrypt_rlwe< pub(crate) fn public_key_encrypt_rlwe<
M: Matrix, M: Matrix,
Mmut: MatrixMut<MatElement = M::MatElement>, Mmut: MatrixMut<MatElement = M::MatElement>,
@ -507,8 +544,8 @@ pub(crate) fn public_key_encrypt_rlwe<
mod_op.elwise_add_mut(rlwe_out.get_row_mut(1), m); mod_op.elwise_add_mut(rlwe_out.get_row_mut(1), m);
} }
/// Generates RLWE public key
pub(crate) fn gen_rlwe_public_key<
/// Returns RLWE public key generated using RLWE secret key
pub(crate) fn rlwe_public_key<
Ro: RowMut + RowEntity, Ro: RowMut + RowEntity,
S, S,
ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>, ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,
@ -549,9 +586,9 @@ pub(crate) fn gen_rlwe_public_key<
mod_op.elwise_add_mut(part_b_out.as_mut(), sa.as_ref()); mod_op.elwise_add_mut(part_b_out.as_mut(), sa.as_ref());
} }
/// Decrypts degree 1 RLWE ciphertext RLWE(m) and returns m
/// Decrypts ciphertext RLWE(m) and returns noisy m
/// ///
/// - rlwe_ct: input degree 1 ciphertext RLWE(m).
/// We assume RLWE(m) = [a, b] is a degree 1 ciphertext s.t. b - sa = e + m
pub(crate) fn decrypt_rlwe< pub(crate) fn decrypt_rlwe<
R: RowMut, R: RowMut,
M: Matrix<MatElement = R::Element>, M: Matrix<MatElement = R::Element>,

+ 7
- 6
src/rgsw/mod.rs

@ -524,8 +524,9 @@ pub(crate) mod tests {
use super::{ use super::{
keygen::{ keygen::{
decrypt_rlwe, galois_key_gen, gen_rlwe_public_key, generate_auto_map, measure_noise,
public_key_encrypt_rgsw, secret_key_encrypt_rgsw, secret_key_encrypt_rlwe,
decrypt_rlwe, generate_auto_map, measure_noise, public_key_encrypt_rgsw,
rlwe_public_key, secret_key_encrypt_rgsw, seeded_auto_key_gen,
seeded_secret_key_encrypt_rlwe,
}, },
runtime::{galois_auto, rgsw_by_rgsw_inplace, rlwe_by_rgsw}, runtime::{galois_auto, rgsw_by_rgsw_inplace, rlwe_by_rgsw},
AutoKeyEvaluationDomain, RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, AutoKeyEvaluationDomain, RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext,
@ -549,7 +550,7 @@ pub(crate) mod tests {
let mut seeded_rlwe_ct = let mut seeded_rlwe_ct =
SeededRlweCiphertext::<_, [u8; 32], _>::empty(ring_size as usize, rlwe_seed, q.clone()); SeededRlweCiphertext::<_, [u8; 32], _>::empty(ring_size as usize, rlwe_seed, q.clone());
let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed); let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed);
secret_key_encrypt_rlwe(
seeded_secret_key_encrypt_rlwe(
&m, &m,
&mut seeded_rlwe_ct.data, &mut seeded_rlwe_ct.data,
s, s,
@ -782,7 +783,7 @@ pub(crate) mod tests {
let mut pk_prng = DefaultSecureRng::new_seeded(pk_seed); let mut pk_prng = DefaultSecureRng::new_seeded(pk_seed);
let mut seeded_pk = let mut seeded_pk =
SeededRlwePublicKey::<Vec<u64>, _>::empty(ring_size as usize, pk_seed, q); SeededRlwePublicKey::<Vec<u64>, _>::empty(ring_size as usize, pk_seed, q);
gen_rlwe_public_key(
rlwe_public_key(
&mut seeded_pk.data, &mut seeded_pk.data,
s.values(), s.values(),
&ntt_op, &ntt_op,
@ -934,7 +935,7 @@ pub(crate) mod tests {
rng.fill_bytes(&mut seed_rlwe); rng.fill_bytes(&mut seed_rlwe);
let mut seeded_rlwe_m = SeededRlweCiphertext::empty(ring_size as usize, seed_rlwe, q); let mut seeded_rlwe_m = SeededRlweCiphertext::empty(ring_size as usize, seed_rlwe, q);
let mut p_rng = DefaultSecureRng::new_seeded(seed_rlwe); let mut p_rng = DefaultSecureRng::new_seeded(seed_rlwe);
secret_key_encrypt_rlwe(
seeded_secret_key_encrypt_rlwe(
&encoded_m, &encoded_m,
&mut seeded_rlwe_m.data, &mut seeded_rlwe_m.data,
s.values(), s.values(),
@ -955,7 +956,7 @@ pub(crate) mod tests {
SeededAutoKey::empty(ring_size as usize, &decomposer, seed_auto, q); SeededAutoKey::empty(ring_size as usize, &decomposer, seed_auto, q);
let mut p_rng = DefaultSecureRng::new_seeded(seed_auto); let mut p_rng = DefaultSecureRng::new_seeded(seed_auto);
let gadget_vector = decomposer.gadget_vector(); let gadget_vector = decomposer.gadget_vector();
galois_key_gen(
seeded_auto_key_gen(
&mut seeded_auto_key.data, &mut seeded_auto_key.data,
s.values(), s.values(),
auto_k, auto_k,

+ 5
- 5
src/utils.rs

@ -1,12 +1,12 @@
use std::{fmt::Debug, usize, vec};
use std::{usize, vec};
use itertools::{izip, Itertools}; use itertools::{izip, Itertools};
use num_traits::{FromPrimitive, One, PrimInt, Signed};
use num_traits::{One, PrimInt, Signed};
use crate::{ use crate::{
backend::Modulus, backend::Modulus,
random::{RandomElementInModulus, RandomFill}, random::{RandomElementInModulus, RandomFill},
Matrix, Row, RowEntity, RowMut,
Matrix, RowEntity, RowMut,
}; };
pub trait WithLocal { pub trait WithLocal {
fn with_local<F, R>(func: F) -> R fn with_local<F, R>(func: F) -> R
@ -163,11 +163,11 @@ pub fn mod_exponent(a: u64, mut b: u64, q: u64) -> u64 {
out out
} }
pub fn mod_inverse(a: u64, q: u64) -> u64 {
pub(crate) fn mod_inverse(a: u64, q: u64) -> u64 {
mod_exponent(a, q - 2, q) mod_exponent(a, q - 2, q)
} }
pub fn negacyclic_mul<T: PrimInt, F: Fn(&T, &T) -> T>(
pub(crate) fn negacyclic_mul<T: PrimInt, F: Fn(&T, &T) -> T>(
a: &[T], a: &[T],
b: &[T], b: &[T],
mul: F, mul: F,

Loading…
Cancel
Save