diff --git a/src/bool/evaluator.rs b/src/bool/evaluator.rs index 053d149..d2b9aee 100644 --- a/src/bool/evaluator.rs +++ b/src/bool/evaluator.rs @@ -25,8 +25,8 @@ use crate::{ RandomFillUniformInModulus, RandomGaussianElementInModulus, }, 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::{ 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 }; let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n); - galois_key_gen( + seeded_auto_key_gen( &mut gk, &sk_rlwe, g_pow, @@ -2010,7 +2010,7 @@ where self.pbs_info.auto_decomposer.decomposition_count(), ring_size, ); - galois_key_gen( + seeded_auto_key_gen( &mut ksk_out, sk_rlwe, g_pow, diff --git a/src/bool/ni_mp_api.rs b/src/bool/ni_mp_api.rs index ee5b7c5..b5d7353 100644 --- a/src/bool/ni_mp_api.rs +++ b/src/bool/ni_mp_api.rs @@ -178,7 +178,7 @@ mod impl_enc_dec { bool::{evaluator::BoolEncoding, keys::NonInteractiveMultiPartyClientKey}, pbs::{sample_extract, PbsInfo, WithShoupRepr}, random::{NewWithSeed, RandomFillUniformInModulus}, - rgsw::{key_switch, secret_key_encrypt_rlwe}, + rgsw::{key_switch, seeded_secret_key_encrypt_rlwe}, utils::TryConvertFrom1, Encryptor, KeySwitchWithId, Matrix, MatrixEntity, MatrixMut, RowEntity, RowMut, }; @@ -296,7 +296,7 @@ mod impl_enc_dec { let mut rlwe_out = <::R as RowEntity>::zeros(parameters.rlwe_n().0); - secret_key_encrypt_rlwe( + seeded_secret_key_encrypt_rlwe( &message, &mut rlwe_out, &sk_u, diff --git a/src/ntt.rs b/src/ntt.rs index c180800..743aa32 100644 --- a/src/ntt.rs +++ b/src/ntt.rs @@ -50,7 +50,7 @@ pub fn forward_butterly_0_to_4q( pub fn forward_butterly_0_to_2q( mut x: u64, - mut y: u64, + y: u64, w: u64, w_shoup: u64, q: u64, @@ -310,7 +310,7 @@ pub(crate) fn find_primitive_root(q: u64, n: u64, rng: &mut R) -> Op pub struct NttBackendU64 { q: u64, q_twice: u64, - n: u64, + _n: u64, n_inv: u64, n_inv_shoup: u64, psi_powers_bo: Box<[u64]>, @@ -374,7 +374,7 @@ impl NttBackendU64 { NttBackendU64 { q, q_twice: 2 * q, - n: n as u64, + _n: n as u64, n_inv, n_inv_shoup: ShoupMul::representation(n_inv, q), 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 { type Element = u64; @@ -458,9 +447,9 @@ mod tests { use rand::{thread_rng, Rng}; use rand_distr::Uniform; - use super::{NttBackendU64, NttInit}; + use super::NttBackendU64; use crate::{ - backend::{ArithmeticOps, ModInit, ModularOpsU64, VectorOps}, + backend::{ModInit, ModularOpsU64, VectorOps}, ntt::Ntt, utils::{generate_prime, negacyclic_mul}, }; diff --git a/src/rgsw/keygen.rs b/src/rgsw/keygen.rs index 72bff08..094acb1 100644 --- a/src/rgsw/keygen.rs +++ b/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 crate::{ backend::{ArithmeticOps, GetModulus, Modulus, VectorOps}, - decomposer::{self, Decomposer, RlweDecomposer}, - ntt::{self, Ntt, NttInit}, + ntt::Ntt, 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, Vec) { @@ -49,13 +40,31 @@ pub(crate) fn generate_auto_map(ring_size: usize, k: isize) -> (Vec, Vec< (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< Mmut: MatrixMut + MatrixEntity, 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< Mmut: MatrixMut + MatrixEntity, M: Matrix, @@ -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). /// -/// 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. -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, ModOp: ArithmeticOps + VectorOps @@ -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, ModOp: ArithmeticOps + VectorOps @@ -385,7 +417,7 @@ pub(crate) fn galois_key_gen< ); // Ksk from -s(X^k) to s(X) - rlwe_ksk_gen( + seeded_rlwe_ksk_gen( ksk_out, neg_s_auto, 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, ModOp: VectorOps + GetModulus, NttOp: Ntt, @@ -446,6 +480,9 @@ pub(crate) fn secret_key_encrypt_rlwe< 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< M: Matrix, Mmut: MatrixMut, @@ -507,8 +544,8 @@ pub(crate) fn public_key_encrypt_rlwe< 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, S, ModOp: VectorOps + GetModulus, @@ -549,9 +586,9 @@ pub(crate) fn gen_rlwe_public_key< 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< R: RowMut, M: Matrix, diff --git a/src/rgsw/mod.rs b/src/rgsw/mod.rs index f121aa1..d9e4545 100644 --- a/src/rgsw/mod.rs +++ b/src/rgsw/mod.rs @@ -524,8 +524,9 @@ pub(crate) mod tests { use super::{ 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}, AutoKeyEvaluationDomain, RgswCiphertext, RgswCiphertextEvaluationDomain, RlweCiphertext, @@ -549,7 +550,7 @@ pub(crate) mod tests { let mut seeded_rlwe_ct = SeededRlweCiphertext::<_, [u8; 32], _>::empty(ring_size as usize, rlwe_seed, q.clone()); let mut p_rng = DefaultSecureRng::new_seeded(rlwe_seed); - secret_key_encrypt_rlwe( + seeded_secret_key_encrypt_rlwe( &m, &mut seeded_rlwe_ct.data, s, @@ -782,7 +783,7 @@ pub(crate) mod tests { let mut pk_prng = DefaultSecureRng::new_seeded(pk_seed); let mut seeded_pk = SeededRlwePublicKey::, _>::empty(ring_size as usize, pk_seed, q); - gen_rlwe_public_key( + rlwe_public_key( &mut seeded_pk.data, s.values(), &ntt_op, @@ -934,7 +935,7 @@ pub(crate) mod tests { rng.fill_bytes(&mut seed_rlwe); let mut seeded_rlwe_m = SeededRlweCiphertext::empty(ring_size as usize, seed_rlwe, q); let mut p_rng = DefaultSecureRng::new_seeded(seed_rlwe); - secret_key_encrypt_rlwe( + seeded_secret_key_encrypt_rlwe( &encoded_m, &mut seeded_rlwe_m.data, s.values(), @@ -955,7 +956,7 @@ pub(crate) mod tests { SeededAutoKey::empty(ring_size as usize, &decomposer, seed_auto, q); let mut p_rng = DefaultSecureRng::new_seeded(seed_auto); let gadget_vector = decomposer.gadget_vector(); - galois_key_gen( + seeded_auto_key_gen( &mut seeded_auto_key.data, s.values(), auto_k, diff --git a/src/utils.rs b/src/utils.rs index 27cfd24..a8f8f04 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,12 +1,12 @@ -use std::{fmt::Debug, usize, vec}; +use std::{usize, vec}; use itertools::{izip, Itertools}; -use num_traits::{FromPrimitive, One, PrimInt, Signed}; +use num_traits::{One, PrimInt, Signed}; use crate::{ backend::Modulus, random::{RandomElementInModulus, RandomFill}, - Matrix, Row, RowEntity, RowMut, + Matrix, RowEntity, RowMut, }; pub trait WithLocal { fn with_local(func: F) -> R @@ -163,11 +163,11 @@ pub fn mod_exponent(a: u64, mut b: u64, q: u64) -> u64 { 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) } -pub fn negacyclic_mul T>( +pub(crate) fn negacyclic_mul T>( a: &[T], b: &[T], mul: F,