arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
clean rgsw/keygen
Janmajaya Mall janmajayamall@protonmail.com
Fri, 28 Jun 2024 18:43:58 +0530
commit

acc51ce4022d91542e3efee2f1c67ad0e4030e37

parent

8e6cde2d89b82607214c29463916bb7627dedaf7

6 files changed, 102 insertions(+), 75 deletions(-)

jump to
M src/bool/evaluator.rs → src/bool/evaluator.rs

@@ -25,8 +25,8 @@ DefaultSecureRng, NewWithSeed, RandomFill, RandomFillGaussianInModulus,

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 @@ } else {

(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 @@ let mut ksk_out = M::zeros(

self.pbs_info.auto_decomposer.decomposition_count(), ring_size, ); - galois_key_gen( + seeded_auto_key_gen( &mut ksk_out, sk_rlwe, g_pow,
M src/bool/ni_mp_api.rs → src/bool/ni_mp_api.rs

@@ -178,7 +178,7 @@ use crate::{

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 @@ // encrypt message

let mut rlwe_out = <<Mat as Matrix>::R as RowEntity>::zeros(parameters.rlwe_n().0); - secret_key_encrypt_rlwe( + seeded_secret_key_encrypt_rlwe( &message, &mut rlwe_out, &sk_u,
M src/ntt.rs → src/ntt.rs

@@ -50,7 +50,7 @@ }

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 @@ #[derive(Debug)]

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 @@

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 @@ NttBackendU64::_new(q.q().unwrap(), n)

} } -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 @@ use itertools::Itertools;

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}, };
M src/rgsw/keygen.rs → 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<usize>, Vec<bool>) {

@@ -49,13 +40,31 @@ .unzip();

(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` +/// +/// 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 /// -/// - 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) +/// - 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 @@ mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());

}); } +/// 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<MatElement = Mmut::MatElement>,

@@ -269,20 +285,25 @@ mod_op.elwise_add_mut(bi.as_mut(), u_eval.as_ref());

}); } -/// 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<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>

@@ -341,7 +362,18 @@ mod_op.elwise_add_mut(bi.as_mut(), ai.as_ref());

}); } -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<Element = Mmut::MatElement> + VectorOps<Element = Mmut::MatElement>

@@ -385,7 +417,7 @@ },

); // 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 @@ rng,

); } -/// Encrypt polynomial m(X) as RLWE ciphertext. +/// Returns seeded RLWE(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< +/// RLWE(m(X)) = [a(X), b(X) = a(X)s(X) + e(X) + m(X)] +/// +/// 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<Element = Ro::Element> + GetModulus<Element = Ro::Element>, NttOp: Ntt<Element = Ro::Element>,

@@ -446,6 +480,9 @@ mod_op.elwise_add_mut(b_rlwe_out.as_mut(), m.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< M: Matrix, Mmut: MatrixMut<MatElement = M::MatElement>,

@@ -507,8 +544,8 @@ // b*u + e1 + 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, S, ModOp: VectorOps<Element = Ro::Element> + GetModulus<Element = Ro::Element>,

@@ -549,9 +586,9 @@ RandomFillGaussianInModulus::random_fill(rng, &q, part_b_out.as_mut());

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<MatElement = R::Element>,
M src/rgsw/mod.rs → src/rgsw/mod.rs

@@ -524,8 +524,9 @@ };

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 @@ rng.fill_bytes(&mut rlwe_seed);

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 @@ rng.fill_bytes(&mut pk_seed);

let mut pk_prng = DefaultSecureRng::new_seeded(pk_seed); let mut seeded_pk = SeededRlwePublicKey::<Vec<u64>, _>::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 @@ let mut seed_rlwe = [0u8; 32];

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 @@ let mut seeded_auto_key =

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,
M src/utils.rs → 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<F, R>(func: F) -> R

@@ -163,11 +163,11 @@

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: PrimInt, F: Fn(&T, &T) -> T>( +pub(crate) fn negacyclic_mul<T: PrimInt, F: Fn(&T, &T) -> T>( a: &[T], b: &[T], mul: F,