phantom-zone/src/bool/evaluator.rs
src/bool/evaluator.rsRaw
1use std::{
2 collections::HashMap,
3 fmt::{Debug, Display},
4 marker::PhantomData,
5 usize,
6};
7
8use itertools::{izip, Itertools};
9use num_traits::{FromPrimitive, One, PrimInt, ToPrimitive, WrappingAdd, WrappingSub, Zero};
10use rand_distr::uniform::SampleUniform;
11
12use crate::{
13 backend::{ArithmeticOps, GetModulus, ModInit, Modulus, ShoupMatrixFMA, VectorOps},
14 bool::parameters::ParameterVariant,
15 decomposer::{Decomposer, DefaultDecomposer, NumInfo, RlweDecomposer},
16 lwe::{decrypt_lwe, encrypt_lwe, seeded_lwe_ksk_keygen},
17 multi_party::{
18 non_interactive_ksk_gen, non_interactive_ksk_zero_encryptions_for_other_party_i,
19 public_key_share,
20 },
21 ntt::{self, Ntt, NttBackendU64, NttInit},
22 pbs::{pbs, sample_extract, PbsInfo, PbsKey, WithShoupRepr},
23 random::{
24 DefaultSecureRng, NewWithSeed, RandomFill, RandomFillGaussianInModulus,
25 RandomFillUniformInModulus, RandomGaussianElementInModulus,
26 },
27 rgsw::{
28 decrypt_rlwe, generate_auto_map, public_key_encrypt_rgsw, rgsw_by_rgsw_inplace,
29 rgsw_x_rgsw_scratch_rows, rlwe_auto, secret_key_encrypt_rgsw, seeded_auto_key_gen,
30 RgswCiphertext, RgswCiphertextMutRef, RgswCiphertextRef, RuntimeScratchMutRef,
31 },
32 utils::{
33 encode_x_pow_si_with_emebedding_factor, fill_random_ternary_secret_with_hamming_weight,
34 generate_prime, mod_exponent, puncture_p_rng, Global, TryConvertFrom1, WithLocal,
35 },
36 Encoder, Matrix, MatrixEntity, MatrixMut, RowEntity, RowMut,
37};
38
39use super::{
40 keys::{
41 ClientKey, CommonReferenceSeededCollectivePublicKeyShare,
42 CommonReferenceSeededMultiPartyServerKeyShare,
43 CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare,
44 InteractiveMultiPartyClientKey, NonInteractiveMultiPartyClientKey,
45 SeededMultiPartyServerKey, SeededNonInteractiveMultiPartyServerKey,
46 SeededSinglePartyServerKey, SinglePartyClientKey,
47 },
48 parameters::{BoolParameters, CiphertextModulus, DecompositionCount, DoubleDecomposerParams},
49};
50
51/// Common reference seed used for Interactive multi-party,
52///
53/// Seeds for public key shares and differents parts of server key shares are
54/// derived from common reference seed with different puncture rountines.
55///
56/// ## Punctures
57///
58/// Initial Seed:
59/// Puncture 1 -> Public key share seed
60/// Puncture 2 -> Main server key share seed
61/// Puncture 1 -> Auto keys cipertexts seed
62/// Puncture 2 -> LWE ksk seed
63#[derive(Clone, PartialEq)]
64pub struct MultiPartyCrs<S> {
65 pub(super) seed: S,
66}
67
68impl MultiPartyCrs<[u8; 32]> {
69 pub(super) fn random() -> Self {
70 DefaultSecureRng::with_local_mut(|rng| {
71 let mut seed = [0u8; 32];
72 rng.fill_bytes(&mut seed);
73 Self { seed }
74 })
75 }
76}
77impl<S: Default + Copy> MultiPartyCrs<S> {
78 /// Seed to generate public key share
79 fn public_key_share_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
80 let mut prng = Rng::new_with_seed(self.seed);
81 puncture_p_rng(&mut prng, 1)
82 }
83
84 /// Main server key share seed
85 fn key_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
86 let mut prng = Rng::new_with_seed(self.seed);
87 puncture_p_rng(&mut prng, 2)
88 }
89
90 pub(super) fn auto_keys_cts_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
91 let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
92 puncture_p_rng(&mut key_prng, 1)
93 }
94
95 pub(super) fn lwe_ksk_cts_seed_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
96 let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
97 puncture_p_rng(&mut key_prng, 2)
98 }
99}
100
101/// Common reference seed used for non-interactive multi-party.
102///
103/// Initial Seed
104/// Puncture 1 -> Key Seed
105/// Puncture 1 -> Rgsw ciphertext seed
106/// Puncture l+1 -> Seed for zero encs and non-interactive
107/// multi-party RGSW ciphertexts of
108/// l^th LWE index.
109/// Puncture 2 -> auto keys seed
110/// Puncture 3 -> Lwe key switching key seed
111/// Puncture 2 -> user specific seed for u_j to s ksk
112/// Punture j+1 -> user j's seed
113#[derive(Clone)]
114pub struct NonInteractiveMultiPartyCrs<S> {
115 pub(super) seed: S,
116}
117
118impl NonInteractiveMultiPartyCrs<[u8; 32]> {
119 pub(super) fn random() -> Self {
120 DefaultSecureRng::with_local_mut(|rng| {
121 let mut seed = [0u8; 32];
122 rng.fill_bytes(&mut seed);
123 Self { seed }
124 })
125 }
126}
127
128impl<S: Default + Copy> NonInteractiveMultiPartyCrs<S> {
129 fn key_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
130 let mut p_rng = R::new_with_seed(self.seed);
131 puncture_p_rng(&mut p_rng, 1)
132 }
133
134 pub(crate) fn ni_rgsw_cts_main_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
135 let mut p_rng = R::new_with_seed(self.key_seed::<R>());
136 puncture_p_rng(&mut p_rng, 1)
137 }
138
139 pub(crate) fn ni_rgsw_ct_seed_for_index<R: NewWithSeed<Seed = S> + RandomFill<S>>(
140 &self,
141 lwe_index: usize,
142 ) -> S {
143 let mut p_rng = R::new_with_seed(self.ni_rgsw_cts_main_seed::<R>());
144 puncture_p_rng(&mut p_rng, lwe_index + 1)
145 }
146
147 pub(crate) fn auto_keys_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
148 let mut p_rng = R::new_with_seed(self.key_seed::<R>());
149 puncture_p_rng(&mut p_rng, 2)
150 }
151
152 pub(crate) fn lwe_ksk_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
153 let mut p_rng = R::new_with_seed(self.key_seed::<R>());
154 puncture_p_rng(&mut p_rng, 3)
155 }
156
157 fn ui_to_s_ks_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
158 let mut p_rng = R::new_with_seed(self.seed);
159 puncture_p_rng(&mut p_rng, 2)
160 }
161
162 pub(crate) fn ui_to_s_ks_seed_for_user_i<R: NewWithSeed<Seed = S> + RandomFill<S>>(
163 &self,
164 user_i: usize,
165 ) -> S {
166 let ks_seed = self.ui_to_s_ks_seed::<R>();
167 let mut p_rng = R::new_with_seed(ks_seed);
168
169 puncture_p_rng(&mut p_rng, user_i + 1)
170 }
171}
172
173pub(crate) trait BooleanGates {
174 type Ciphertext: RowEntity;
175 type Key;
176
177 fn and_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
178 fn nand_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
179 fn or_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
180 fn nor_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
181 fn xor_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
182 fn xnor_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
183 fn not_inplace(&mut self, c: &mut Self::Ciphertext);
184
185 fn and(
186 &mut self,
187 c0: &Self::Ciphertext,
188 c1: &Self::Ciphertext,
189 key: &Self::Key,
190 ) -> Self::Ciphertext;
191 fn nand(
192 &mut self,
193 c0: &Self::Ciphertext,
194 c1: &Self::Ciphertext,
195 key: &Self::Key,
196 ) -> Self::Ciphertext;
197 fn or(
198 &mut self,
199 c0: &Self::Ciphertext,
200 c1: &Self::Ciphertext,
201 key: &Self::Key,
202 ) -> Self::Ciphertext;
203 fn nor(
204 &mut self,
205 c0: &Self::Ciphertext,
206 c1: &Self::Ciphertext,
207 key: &Self::Key,
208 ) -> Self::Ciphertext;
209 fn xor(
210 &mut self,
211 c0: &Self::Ciphertext,
212 c1: &Self::Ciphertext,
213 key: &Self::Key,
214 ) -> Self::Ciphertext;
215 fn xnor(
216 &mut self,
217 c0: &Self::Ciphertext,
218 c1: &Self::Ciphertext,
219 key: &Self::Key,
220 ) -> Self::Ciphertext;
221 fn not(&mut self, c: &Self::Ciphertext) -> Self::Ciphertext;
222}
223
224struct ScratchMemory<M>
225where
226 M: Matrix,
227{
228 lwe_vector: M::R,
229 decomposition_matrix: M,
230}
231
232impl<M: MatrixEntity> ScratchMemory<M>
233where
234 M::R: RowEntity,
235{
236 fn new(parameters: &BoolParameters<M::MatElement>) -> Self {
237 // Vector to store LWE ciphertext with LWE dimesnion n
238 let lwe_vector = M::R::zeros(parameters.lwe_n().0 + 1);
239
240 // Matrix to store decomposed polynomials
241 // Max decompistion count + space for temporary RLWE
242 let d = std::cmp::max(
243 parameters.auto_decomposition_count().0,
244 std::cmp::max(
245 parameters.rlwe_rgsw_decomposition_count().0 .0,
246 parameters.rlwe_rgsw_decomposition_count().1 .0,
247 ),
248 ) + 2;
249 let decomposition_matrix = M::zeros(d, parameters.rlwe_n().0);
250
251 Self {
252 lwe_vector,
253 decomposition_matrix,
254 }
255 }
256}
257
258pub(super) trait BoolEncoding {
259 type Element;
260 fn true_el(&self) -> Self::Element;
261 fn false_el(&self) -> Self::Element;
262 fn qby4(&self) -> Self::Element;
263 fn decode(&self, m: Self::Element) -> bool;
264}
265
266impl<T> BoolEncoding for CiphertextModulus<T>
267where
268 CiphertextModulus<T>: Modulus<Element = T>,
269 T: PrimInt,
270{
271 type Element = T;
272
273 fn qby4(&self) -> Self::Element {
274 if self.is_native() {
275 T::one() << (CiphertextModulus::<T>::_bits() - 2)
276 } else {
277 self.q().unwrap() >> 2
278 }
279 }
280 /// Q/8
281 fn true_el(&self) -> Self::Element {
282 if self.is_native() {
283 T::one() << (CiphertextModulus::<T>::_bits() - 3)
284 } else {
285 self.q().unwrap() >> 3
286 }
287 }
288 /// -Q/8
289 fn false_el(&self) -> Self::Element {
290 self.largest_unsigned_value() - self.true_el() + T::one()
291 }
292 fn decode(&self, m: Self::Element) -> bool {
293 let qby8 = self.true_el();
294 let m = (((m + qby8).to_f64().unwrap() * 4.0f64) / self.q_as_f64().unwrap()).round()
295 as usize
296 % 4usize;
297
298 if m == 0 {
299 return false;
300 } else if m == 1 {
301 return true;
302 } else {
303 panic!("Incorrect bool decryption. Got m={m} but expected m to be 0 or 1")
304 }
305 }
306}
307
308impl<B> Encoder<bool, B::Element> for B
309where
310 B: BoolEncoding,
311{
312 fn encode(&self, v: bool) -> B::Element {
313 if v {
314 self.true_el()
315 } else {
316 self.false_el()
317 }
318 }
319}
320
321pub(super) struct BoolPbsInfo<M: Matrix, Ntt, RlweModOp, LweModOp> {
322 auto_decomposer: DefaultDecomposer<M::MatElement>,
323 rlwe_rgsw_decomposer: (
324 DefaultDecomposer<M::MatElement>,
325 DefaultDecomposer<M::MatElement>,
326 ),
327 lwe_decomposer: DefaultDecomposer<M::MatElement>,
328 g_k_dlog_map: Vec<usize>,
329 rlwe_nttop: Ntt,
330 rlwe_modop: RlweModOp,
331 lwe_modop: LweModOp,
332 embedding_factor: usize,
333 rlwe_qby4: M::MatElement,
334 rlwe_auto_maps: Vec<(Vec<usize>, Vec<bool>)>,
335 parameters: BoolParameters<M::MatElement>,
336}
337
338impl<M: Matrix, NttOp, RlweModOp, LweModOp> PbsInfo for BoolPbsInfo<M, NttOp, RlweModOp, LweModOp>
339where
340 M::MatElement: PrimInt
341 + WrappingSub
342 + NumInfo
343 + FromPrimitive
344 + From<bool>
345 + Display
346 + WrappingAdd
347 + Debug,
348 RlweModOp: ArithmeticOps<Element = M::MatElement> + ShoupMatrixFMA<M::R>,
349 LweModOp: ArithmeticOps<Element = M::MatElement> + VectorOps<Element = M::MatElement>,
350 NttOp: Ntt<Element = M::MatElement>,
351{
352 type M = M;
353 type Modulus = CiphertextModulus<M::MatElement>;
354 type D = DefaultDecomposer<M::MatElement>;
355 type RlweModOp = RlweModOp;
356 type LweModOp = LweModOp;
357 type NttOp = NttOp;
358 fn rlwe_auto_map(&self, k: usize) -> &(Vec<usize>, Vec<bool>) {
359 &self.rlwe_auto_maps[k]
360 }
361 fn br_q(&self) -> usize {
362 *self.parameters.br_q()
363 }
364 fn lwe_decomposer(&self) -> &Self::D {
365 &self.lwe_decomposer
366 }
367 fn rlwe_rgsw_decomposer(&self) -> &(Self::D, Self::D) {
368 &self.rlwe_rgsw_decomposer
369 }
370 fn auto_decomposer(&self) -> &Self::D {
371 &self.auto_decomposer
372 }
373 fn embedding_factor(&self) -> usize {
374 self.embedding_factor
375 }
376 fn g(&self) -> isize {
377 self.parameters.g() as isize
378 }
379 fn w(&self) -> usize {
380 self.parameters.w()
381 }
382 fn g_k_dlog_map(&self) -> &[usize] {
383 &self.g_k_dlog_map
384 }
385 fn lwe_n(&self) -> usize {
386 self.parameters.lwe_n().0
387 }
388 fn lwe_q(&self) -> &Self::Modulus {
389 self.parameters.lwe_q()
390 }
391 fn rlwe_n(&self) -> usize {
392 self.parameters.rlwe_n().0
393 }
394 fn rlwe_q(&self) -> &Self::Modulus {
395 self.parameters.rlwe_q()
396 }
397 fn modop_lweq(&self) -> &Self::LweModOp {
398 &self.lwe_modop
399 }
400 fn modop_rlweq(&self) -> &Self::RlweModOp {
401 &self.rlwe_modop
402 }
403 fn nttop_rlweq(&self) -> &Self::NttOp {
404 &self.rlwe_nttop
405 }
406}
407
408pub(crate) struct BoolEvaluator<M, Ntt, RlweModOp, LweModOp, SKey>
409where
410 M: Matrix,
411{
412 pbs_info: BoolPbsInfo<M, Ntt, RlweModOp, LweModOp>,
413 scratch_memory: ScratchMemory<M>,
414 nand_test_vec: M::R,
415 and_test_vec: M::R,
416 or_test_vec: M::R,
417 nor_test_vec: M::R,
418 xor_test_vec: M::R,
419 xnor_test_vec: M::R,
420 /// Non-interactive u_i -> s key switch decomposer
421 ni_ui_to_s_ks_decomposer: Option<DefaultDecomposer<M::MatElement>>,
422 _phantom: PhantomData<SKey>,
423}
424
425impl<M: Matrix, NttOp, RlweModOp, LweModOp, Skey>
426 BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
427{
428 pub(crate) fn parameters(&self) -> &BoolParameters<M::MatElement> {
429 &self.pbs_info.parameters
430 }
431
432 pub(super) fn pbs_info(&self) -> &BoolPbsInfo<M, NttOp, RlweModOp, LweModOp> {
433 &self.pbs_info
434 }
435
436 pub(super) fn ni_ui_to_s_ks_decomposer(&self) -> &Option<DefaultDecomposer<M::MatElement>> {
437 &self.ni_ui_to_s_ks_decomposer
438 }
439}
440
441fn trim_rgsw_ct_matrix_from_rgrg_to_rlrg<
442 M: MatrixMut + MatrixEntity,
443 D: DoubleDecomposerParams<Count = DecompositionCount>,
444>(
445 rgsw_ct_in: M,
446 rgrg_params: D,
447 rlrg_params: D,
448) -> M
449where
450 M::R: RowMut,
451 M::MatElement: Copy,
452{
453 let (rgswrgsw_d_a, rgswrgsw_d_b) = (
454 rgrg_params.decomposition_count_a(),
455 rgrg_params.decomposition_count_b(),
456 );
457 let (rlrg_d_a, rlrg_d_b) = (
458 rlrg_params.decomposition_count_a(),
459 rlrg_params.decomposition_count_b(),
460 );
461 let rgsw_ct_rows_in = rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 * 2;
462 let rgsw_ct_rows_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
463 assert!(rgsw_ct_in.dimension().0 == rgsw_ct_rows_in);
464 assert!(rgswrgsw_d_a.0 >= rlrg_d_a.0, "RGSWxRGSW part A decomposition count {} must be >= RLWExRGSW part A decomposition count {}", rgswrgsw_d_a.0 , rlrg_d_a.0);
465 assert!(rgswrgsw_d_b.0 >= rlrg_d_b.0, "RGSWxRGSW part B decomposition count {} must be >= RLWExRGSW part B decomposition count {}", rgswrgsw_d_b.0 , rlrg_d_b.0);
466
467 let mut reduced_ct_i_out = M::zeros(rgsw_ct_rows_out, rgsw_ct_in.dimension().1);
468
469 // RLWE'(-sm) part A
470 izip!(
471 reduced_ct_i_out.iter_rows_mut().take(rlrg_d_a.0),
472 rgsw_ct_in
473 .iter_rows()
474 .skip(rgswrgsw_d_a.0 - rlrg_d_a.0)
475 .take(rlrg_d_a.0)
476 )
477 .for_each(|(to_ri, from_ri)| {
478 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
479 });
480
481 // RLWE'(-sm) part B
482 izip!(
483 reduced_ct_i_out
484 .iter_rows_mut()
485 .skip(rlrg_d_a.0)
486 .take(rlrg_d_a.0),
487 rgsw_ct_in
488 .iter_rows()
489 .skip(rgswrgsw_d_a.0 + (rgswrgsw_d_a.0 - rlrg_d_a.0))
490 .take(rlrg_d_a.0)
491 )
492 .for_each(|(to_ri, from_ri)| {
493 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
494 });
495
496 // RLWE'(m) Part A
497 izip!(
498 reduced_ct_i_out
499 .iter_rows_mut()
500 .skip(rlrg_d_a.0 * 2)
501 .take(rlrg_d_b.0),
502 rgsw_ct_in
503 .iter_rows()
504 .skip(rgswrgsw_d_a.0 * 2 + (rgswrgsw_d_b.0 - rlrg_d_b.0))
505 .take(rlrg_d_b.0)
506 )
507 .for_each(|(to_ri, from_ri)| {
508 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
509 });
510
511 // RLWE'(m) Part B
512 izip!(
513 reduced_ct_i_out
514 .iter_rows_mut()
515 .skip(rlrg_d_a.0 * 2 + rlrg_d_b.0)
516 .take(rlrg_d_b.0),
517 rgsw_ct_in
518 .iter_rows()
519 .skip(rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 + (rgswrgsw_d_b.0 - rlrg_d_b.0))
520 .take(rlrg_d_b.0)
521 )
522 .for_each(|(to_ri, from_ri)| {
523 to_ri.as_mut().copy_from_slice(from_ri.as_ref());
524 });
525
526 reduced_ct_i_out
527}
528
529fn produce_rgsw_ciphertext_from_ni_rgsw<
530 M: MatrixMut + MatrixEntity,
531 D: RlweDecomposer,
532 ModOp: VectorOps<Element = M::MatElement>,
533 NttOp: Ntt<Element = M::MatElement>,
534>(
535 ni_rgsw_ct: &M,
536 aggregated_decomposed_ni_rgsw_zero_encs: &[M],
537 decomposed_neg_ais: &[M],
538 decomposer: &D,
539 parameters: &BoolParameters<M::MatElement>,
540 uj_to_s_ksk: (&M, &M),
541 rlwe_modop: &ModOp,
542 nttop: &NttOp,
543 out_eval: bool,
544) -> M
545where
546 <M as Matrix>::R: RowMut + Clone,
547{
548 let max_decomposer =
549 if decomposer.a().decomposition_count() > decomposer.b().decomposition_count() {
550 decomposer.a()
551 } else {
552 decomposer.b()
553 };
554
555 assert!(
556 ni_rgsw_ct.dimension() == (max_decomposer.decomposition_count(), parameters.rlwe_n().0)
557 );
558 assert!(aggregated_decomposed_ni_rgsw_zero_encs.len() == decomposer.a().decomposition_count(),);
559 assert!(decomposed_neg_ais.len() == decomposer.b().decomposition_count());
560
561 let mut rgsw_i = M::zeros(
562 decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count() * 2,
563 parameters.rlwe_n().0,
564 );
565 let (rlwe_dash_nsm, rlwe_dash_m) =
566 rgsw_i.split_at_row_mut(decomposer.a().decomposition_count() * 2);
567
568 // RLWE'_{s}(-sm)
569 // Key switch `s * a_{i, l} + e` using ksk(u_j -> s) to produce RLWE(s *
570 // u_{j=user_id} * a_{i, l}).
571 //
572 // Then set RLWE_{s}(-s B^i m) = (0, u_{j=user_id} * a_{i, l} + e + B^i m) +
573 // RLWE(s * u_{j=user_id} * a_{i, l})
574 {
575 let (rlwe_dash_nsm_parta, rlwe_dash_nsm_partb) =
576 rlwe_dash_nsm.split_at_mut(decomposer.a().decomposition_count());
577 izip!(
578 rlwe_dash_nsm_parta.iter_mut(),
579 rlwe_dash_nsm_partb.iter_mut(),
580 ni_rgsw_ct
581 .iter_rows()
582 .skip(max_decomposer.decomposition_count() - decomposer.a().decomposition_count()),
583 aggregated_decomposed_ni_rgsw_zero_encs.iter()
584 )
585 .for_each(|(rlwe_a, rlwe_b, ni_rlwe_ct, decomp_zero_enc)| {
586 // KS(s * a_{i, l} + e) = RLWE(s * u_j *
587 // a_{i, l}) using user j's Ksk
588 izip!(
589 decomp_zero_enc.iter_rows(),
590 uj_to_s_ksk.0.iter_rows(),
591 uj_to_s_ksk.1.iter_rows()
592 )
593 .for_each(|(c, pb, pa)| {
594 rlwe_modop.elwise_fma_mut(rlwe_b.as_mut(), pb.as_ref(), c.as_ref());
595 rlwe_modop.elwise_fma_mut(rlwe_a.as_mut(), pa.as_ref(), c.as_ref());
596 });
597
598 // RLWE(-s beta^i m) = (0, u_j * a_{j, l} +
599 // e + beta^i m) + RLWE(s * u_j * a_{i, l})
600 if out_eval {
601 let mut ni_rlwe_ct = ni_rlwe_ct.clone();
602 nttop.forward(ni_rlwe_ct.as_mut());
603 rlwe_modop.elwise_add_mut(rlwe_a.as_mut(), ni_rlwe_ct.as_ref());
604 } else {
605 nttop.backward(rlwe_a.as_mut());
606 nttop.backward(rlwe_b.as_mut());
607 rlwe_modop.elwise_add_mut(rlwe_a.as_mut(), ni_rlwe_ct.as_ref());
608 }
609 });
610 }
611
612 // RLWE'_{s}(m)
613 {
614 let (rlwe_dash_m_parta, rlwe_dash_partb) =
615 rlwe_dash_m.split_at_mut(decomposer.b().decomposition_count());
616 izip!(
617 rlwe_dash_m_parta.iter_mut(),
618 rlwe_dash_partb.iter_mut(),
619 ni_rgsw_ct
620 .iter_rows()
621 .skip(max_decomposer.decomposition_count() - decomposer.b().decomposition_count()),
622 decomposed_neg_ais.iter()
623 )
624 .for_each(|(rlwe_a, rlwe_b, ni_rlwe_ct, decomp_neg_ai)| {
625 // KS(-a_{i, l}) = RLWE(u_i * -a_{i,l}) using user j's Ksk
626 izip!(
627 decomp_neg_ai.iter_rows(),
628 uj_to_s_ksk.0.iter_rows(),
629 uj_to_s_ksk.1.iter_rows()
630 )
631 .for_each(|(c, pb, pa)| {
632 rlwe_modop.elwise_fma_mut(rlwe_b.as_mut(), pb.as_ref(), c.as_ref());
633 rlwe_modop.elwise_fma_mut(rlwe_a.as_mut(), pa.as_ref(), c.as_ref());
634 });
635
636 // RLWE_{s}(beta^i m) = (u_j * a_{i, l} + e + beta^i m, 0) -
637 // RLWE(-a_{i, l} u_j)
638 if out_eval {
639 let mut ni_rlwe_ct = ni_rlwe_ct.clone();
640 nttop.forward(ni_rlwe_ct.as_mut());
641 rlwe_modop.elwise_add_mut(rlwe_b.as_mut(), ni_rlwe_ct.as_ref());
642 } else {
643 nttop.backward(rlwe_a.as_mut());
644 nttop.backward(rlwe_b.as_mut());
645 rlwe_modop.elwise_add_mut(rlwe_b.as_mut(), ni_rlwe_ct.as_ref());
646 }
647 });
648 }
649
650 rgsw_i
651}
652
653/// Assigns user with user_id segement of LWE secret indices for which they
654/// generate RGSW(X^{s[i]}) as the leader (i.e. for RLWExRGSW). If returned
655/// tuple is (start, end), user's segment is [start, end)
656pub(super) fn interactive_mult_party_user_id_lwe_segment(
657 user_id: usize,
658 total_users: usize,
659 lwe_n: usize,
660) -> (usize, usize) {
661 let per_user = (lwe_n as f64 / total_users as f64)
662 .ceil()
663 .to_usize()
664 .unwrap();
665 (
666 per_user * user_id,
667 std::cmp::min(per_user * (user_id + 1), lwe_n),
668 )
669}
670
671impl<M: Matrix, NttOp, RlweModOp, LweModOp, SKey> BoolEvaluator<M, NttOp, RlweModOp, LweModOp, SKey>
672where
673 M: MatrixEntity + MatrixMut,
674 M::MatElement: PrimInt
675 + Debug
676 + Display
677 + NumInfo
678 + FromPrimitive
679 + WrappingSub
680 + WrappingAdd
681 + SampleUniform
682 + From<bool>,
683 NttOp: Ntt<Element = M::MatElement>,
684 RlweModOp: ArithmeticOps<Element = M::MatElement>
685 + VectorOps<Element = M::MatElement>
686 + GetModulus<Element = M::MatElement, M = CiphertextModulus<M::MatElement>>
687 + ShoupMatrixFMA<M::R>,
688 LweModOp: ArithmeticOps<Element = M::MatElement>
689 + VectorOps<Element = M::MatElement>
690 + GetModulus<Element = M::MatElement, M = CiphertextModulus<M::MatElement>>,
691 M::R: TryConvertFrom1<[i32], CiphertextModulus<M::MatElement>> + RowEntity + Debug,
692 <M as Matrix>::R: RowMut,
693{
694 pub(super) fn new(parameters: BoolParameters<M::MatElement>) -> Self
695 where
696 RlweModOp: ModInit<M = CiphertextModulus<M::MatElement>>,
697 LweModOp: ModInit<M = CiphertextModulus<M::MatElement>>,
698 NttOp: NttInit<CiphertextModulus<M::MatElement>>,
699 {
700 //TODO(Jay): Run sanity checks for modulus values in parameters
701
702 // generates dlog map s.t. (+/-)g^{k} % q = a, for all a \in Z*_{q} and k \in
703 // [0, q/4). We store the dlog `k` at index `a`. This makes it easier to
704 // simply look up `k` at runtime as vec[a]. If a = g^{k} then dlog is
705 // stored as k. If a = -g^{k} then dlog is stored as k = q/4. This is done to
706 // differentiate sign.
707 let g = parameters.g();
708 let q = *parameters.br_q();
709 let mut g_k_dlog_map = vec![0usize; q];
710 for i in 0..q / 4 {
711 let v = mod_exponent(g as u64, i as u64, q as u64) as usize;
712 // g^i
713 g_k_dlog_map[v] = i;
714 // -(g^i)
715 g_k_dlog_map[q - v] = i + (q / 4);
716 }
717
718 let embedding_factor = (2 * parameters.rlwe_n().0) / q;
719
720 let rlwe_nttop = NttOp::new(parameters.rlwe_q(), parameters.rlwe_n().0);
721 let rlwe_modop = RlweModOp::new(*parameters.rlwe_q());
722 let lwe_modop = LweModOp::new(*parameters.lwe_q());
723
724 let q = *parameters.br_q();
725 let qby2 = q >> 1;
726 let qby8 = q >> 3;
727 // Q/8 (Q: rlwe_q)
728 let true_m_el = parameters.rlwe_q().true_el();
729 // -Q/8
730 let false_m_el = parameters.rlwe_q().false_el();
731 let (auto_map_index, auto_map_sign) = generate_auto_map(qby2, -(g as isize));
732
733 let init_test_vec = |partition_el: usize,
734 before_partition_el: M::MatElement,
735 after_partition_el: M::MatElement| {
736 let mut test_vec = M::R::zeros(qby2);
737 for i in 0..qby2 {
738 if i < partition_el {
739 test_vec.as_mut()[i] = before_partition_el;
740 } else {
741 test_vec.as_mut()[i] = after_partition_el;
742 }
743 }
744
745 // v(X) -> v(X^{-g})
746 let mut test_vec_autog = M::R::zeros(qby2);
747 izip!(
748 test_vec.as_ref().iter(),
749 auto_map_index.iter(),
750 auto_map_sign.iter()
751 )
752 .for_each(|(v, to_index, to_sign)| {
753 if !to_sign {
754 // negate
755 test_vec_autog.as_mut()[*to_index] = rlwe_modop.neg(v);
756 } else {
757 test_vec_autog.as_mut()[*to_index] = *v;
758 }
759 });
760
761 return test_vec_autog;
762 };
763
764 let nand_test_vec = init_test_vec(3 * qby8, true_m_el, false_m_el);
765 let and_test_vec = init_test_vec(3 * qby8, false_m_el, true_m_el);
766 let or_test_vec = init_test_vec(qby8, false_m_el, true_m_el);
767 let nor_test_vec = init_test_vec(qby8, true_m_el, false_m_el);
768 let xor_test_vec = init_test_vec(qby8, false_m_el, true_m_el);
769 let xnor_test_vec = init_test_vec(qby8, true_m_el, false_m_el);
770
771 // auto map indices and sign
772 // Auto maps are stored as [-g, g^{1}, g^{2}, ..., g^{w}]
773 let mut rlwe_auto_maps = vec![];
774 let ring_size = parameters.rlwe_n().0;
775 let g = parameters.g();
776 let br_q = parameters.br_q();
777 let auto_element_dlogs = parameters.auto_element_dlogs();
778 assert!(auto_element_dlogs[0] == 0);
779 for i in auto_element_dlogs.into_iter() {
780 let el = if i == 0 {
781 -(g as isize)
782 } else {
783 (g.pow(i as u32) % br_q) as isize
784 };
785 rlwe_auto_maps.push(generate_auto_map(ring_size, el))
786 }
787
788 let rlwe_qby4 = parameters.rlwe_q().qby4();
789
790 let scratch_memory = ScratchMemory::new(¶meters);
791
792 let ni_ui_to_s_ks_decomposer = if parameters.variant()
793 == &ParameterVariant::NonInteractiveMultiParty
794 {
795 Some(parameters
796 .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>())
797 } else {
798 None
799 };
800
801 let pbs_info = BoolPbsInfo {
802 auto_decomposer: parameters.auto_decomposer(),
803 lwe_decomposer: parameters.lwe_decomposer(),
804 rlwe_rgsw_decomposer: parameters.rlwe_rgsw_decomposer(),
805 g_k_dlog_map,
806 embedding_factor,
807 lwe_modop,
808 rlwe_modop,
809 rlwe_nttop,
810 rlwe_qby4,
811 rlwe_auto_maps,
812 parameters: parameters,
813 };
814
815 BoolEvaluator {
816 pbs_info,
817 scratch_memory,
818 nand_test_vec,
819 and_test_vec,
820 or_test_vec,
821 nor_test_vec,
822 xnor_test_vec,
823 xor_test_vec,
824 ni_ui_to_s_ks_decomposer,
825 _phantom: PhantomData,
826 }
827 }
828
829 pub(crate) fn client_key(
830 &self,
831 ) -> ClientKey<<DefaultSecureRng as NewWithSeed>::Seed, M::MatElement> {
832 ClientKey::new(self.parameters().clone())
833 }
834
835 pub(super) fn single_party_server_key<K: SinglePartyClientKey<Element = i32>>(
836 &self,
837 client_key: &K,
838 ) -> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, [u8; 32]> {
839 assert_eq!(self.parameters().variant(), &ParameterVariant::SingleParty);
840
841 DefaultSecureRng::with_local_mut(|rng| {
842 let mut main_seed = [0u8; 32];
843 rng.fill_bytes(&mut main_seed);
844
845 let mut main_prng = DefaultSecureRng::new_seeded(main_seed);
846
847 let rlwe_n = self.pbs_info.parameters.rlwe_n().0;
848 let sk_rlwe = client_key.sk_rlwe();
849 let sk_lwe = client_key.sk_lwe();
850
851 // generate auto keys
852 let mut auto_keys = HashMap::new();
853 let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
854 let g = self.pbs_info.parameters.g();
855 let br_q = self.pbs_info.parameters.br_q();
856 let auto_els = self.pbs_info.parameters.auto_element_dlogs();
857 for i in auto_els.into_iter() {
858 let g_pow = if i == 0 {
859 -(g as isize)
860 } else {
861 (g.pow(i as u32) % br_q) as isize
862 };
863 let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n);
864 seeded_auto_key_gen(
865 &mut gk,
866 &sk_rlwe,
867 g_pow,
868 &auto_gadget,
869 &self.pbs_info.rlwe_modop,
870 &self.pbs_info.rlwe_nttop,
871 &mut main_prng,
872 rng,
873 );
874 auto_keys.insert(i, gk);
875 }
876
877 // generate rgsw ciphertexts RGSW(si) where si is i^th LWE secret element
878 let ring_size = self.pbs_info.parameters.rlwe_n().0;
879 let rlwe_q = self.pbs_info.parameters.rlwe_q();
880 let (rlrg_d_a, rlrg_d_b) = (
881 self.pbs_info.rlwe_rgsw_decomposer.0.decomposition_count(),
882 self.pbs_info.rlwe_rgsw_decomposer.1.decomposition_count(),
883 );
884 let rlrg_gadget_a = self.pbs_info.rlwe_rgsw_decomposer.0.gadget_vector();
885 let rlrg_gadget_b = self.pbs_info.rlwe_rgsw_decomposer.1.gadget_vector();
886 let rgsw_cts = sk_lwe
887 .iter()
888 .map(|si| {
889 // X^{si}; assume |emebedding_factor * si| < N
890 let mut m = M::R::zeros(ring_size);
891 let si = (self.pbs_info.embedding_factor as i32) * si;
892 // dbg!(si);
893 if si < 0 {
894 // X^{-i} = X^{2N - i} = -X^{N-i}
895 m.as_mut()[ring_size - (si.abs() as usize)] = rlwe_q.neg_one();
896 } else {
897 // X^{i}
898 m.as_mut()[si.abs() as usize] = M::MatElement::one();
899 }
900
901 let mut rgsw_si = M::zeros(rlrg_d_a * 2 + rlrg_d_b, ring_size);
902 secret_key_encrypt_rgsw(
903 &mut rgsw_si,
904 m.as_ref(),
905 &rlrg_gadget_a,
906 &rlrg_gadget_b,
907 &sk_rlwe,
908 &self.pbs_info.rlwe_modop,
909 &self.pbs_info.rlwe_nttop,
910 &mut main_prng,
911 rng,
912 );
913
914 rgsw_si
915 })
916 .collect_vec();
917
918 // LWE KSK from RLWE secret s -> LWE secret z
919 let d_lwe_gadget = self.pbs_info.lwe_decomposer.gadget_vector();
920 let lwe_ksk = seeded_lwe_ksk_keygen(
921 &sk_rlwe,
922 &sk_lwe,
923 &d_lwe_gadget,
924 &self.pbs_info.lwe_modop,
925 &mut main_prng,
926 rng,
927 );
928
929 SeededSinglePartyServerKey::from_raw(
930 auto_keys,
931 rgsw_cts,
932 lwe_ksk,
933 self.pbs_info.parameters.clone(),
934 main_seed,
935 )
936 })
937 }
938
939 pub(super) fn multi_party_server_key_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
940 &self,
941 user_id: usize,
942 total_users: usize,
943 cr_seed: &MultiPartyCrs<[u8; 32]>,
944 collective_pk: &M,
945 client_key: &K,
946 ) -> CommonReferenceSeededMultiPartyServerKeyShare<
947 M,
948 BoolParameters<M::MatElement>,
949 MultiPartyCrs<[u8; 32]>,
950 > {
951 assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
952 assert!(user_id < total_users);
953
954 let sk_rlwe = client_key.sk_rlwe();
955 let sk_lwe = client_key.sk_lwe();
956
957 let g = self.pbs_info.parameters.g();
958 let ring_size = self.pbs_info.parameters.rlwe_n().0;
959 let rlwe_q = self.pbs_info.parameters.rlwe_q();
960 let lwe_q = self.pbs_info.parameters.lwe_q();
961
962 let rlweq_modop = &self.pbs_info.rlwe_modop;
963 let rlweq_nttop = &self.pbs_info.rlwe_nttop;
964
965 // sanity check
966 assert!(sk_rlwe.len() == ring_size);
967 assert!(sk_lwe.len() == self.pbs_info.parameters.lwe_n().0);
968
969 // auto keys
970 let auto_keys = self._common_rountine_multi_party_auto_keys_share_gen(
971 cr_seed.auto_keys_cts_seed::<DefaultSecureRng>(),
972 &sk_rlwe,
973 );
974
975 // rgsw ciphertexts of lwe secret elements
976 let (self_leader_rgsws, not_self_leader_rgsws) = DefaultSecureRng::with_local_mut(|rng| {
977 let mut self_leader_rgsw = vec![];
978 let mut not_self_leader_rgsws = vec![];
979
980 let (segment_start, segment_end) = interactive_mult_party_user_id_lwe_segment(
981 user_id,
982 total_users,
983 self.pbs_info().lwe_n(),
984 );
985
986 // self LWE secret indices
987 {
988 // LWE secret indices for which user is the leader they need to send RGSW(m) for
989 // RLWE x RGSW multiplication
990 let rlrg_decomposer = self.pbs_info().rlwe_rgsw_decomposer();
991 let (rlrg_d_a, rlrg_d_b) = (
992 rlrg_decomposer.a().decomposition_count(),
993 rlrg_decomposer.b().decomposition_count(),
994 );
995 let (gadget_a, gadget_b) = (
996 rlrg_decomposer.a().gadget_vector(),
997 rlrg_decomposer.b().gadget_vector(),
998 );
999 for s_index in segment_start..segment_end {
1000 let mut out_rgsw = M::zeros(rlrg_d_a * 2 + rlrg_d_b * 2, ring_size);
1001 public_key_encrypt_rgsw(
1002 &mut out_rgsw,
1003 &encode_x_pow_si_with_emebedding_factor::<
1004 M::R,
1005 CiphertextModulus<M::MatElement>,
1006 >(
1007 sk_lwe[s_index],
1008 self.pbs_info().embedding_factor(),
1009 ring_size,
1010 self.pbs_info().rlwe_q(),
1011 )
1012 .as_ref(),
1013 collective_pk,
1014 &gadget_a,
1015 &gadget_b,
1016 rlweq_modop,
1017 rlweq_nttop,
1018 rng,
1019 );
1020 self_leader_rgsw.push(out_rgsw);
1021 }
1022 }
1023
1024 // not self LWE secret indices
1025 {
1026 // LWE secret indices for which user isn't the leader, they need to send RGSW(m)
1027 // for RGSW x RGSW multiplcation
1028 let rgsw_rgsw_decomposer = self
1029 .pbs_info
1030 .parameters
1031 .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1032 let (rgrg_d_a, rgrg_d_b) = (
1033 rgsw_rgsw_decomposer.a().decomposition_count(),
1034 rgsw_rgsw_decomposer.b().decomposition_count(),
1035 );
1036 let (rgrg_gadget_a, rgrg_gadget_b) = (
1037 rgsw_rgsw_decomposer.a().gadget_vector(),
1038 rgsw_rgsw_decomposer.b().gadget_vector(),
1039 );
1040
1041 for s_index in (0..segment_start).chain(segment_end..self.parameters().lwe_n().0) {
1042 let mut out_rgsw = M::zeros(rgrg_d_a * 2 + rgrg_d_b * 2, ring_size);
1043 public_key_encrypt_rgsw(
1044 &mut out_rgsw,
1045 &encode_x_pow_si_with_emebedding_factor::<
1046 M::R,
1047 CiphertextModulus<M::MatElement>,
1048 >(
1049 sk_lwe[s_index],
1050 self.pbs_info().embedding_factor(),
1051 ring_size,
1052 self.pbs_info().rlwe_q(),
1053 )
1054 .as_ref(),
1055 collective_pk,
1056 &rgrg_gadget_a,
1057 &rgrg_gadget_b,
1058 rlweq_modop,
1059 rlweq_nttop,
1060 rng,
1061 );
1062
1063 not_self_leader_rgsws.push(out_rgsw);
1064 }
1065 }
1066
1067 (self_leader_rgsw, not_self_leader_rgsws)
1068 });
1069
1070 // LWE Ksk
1071 let lwe_ksk = self._common_rountine_multi_party_lwe_ksk_share_gen(
1072 cr_seed.lwe_ksk_cts_seed_seed::<DefaultSecureRng>(),
1073 &sk_rlwe,
1074 &sk_lwe,
1075 );
1076
1077 CommonReferenceSeededMultiPartyServerKeyShare::new(
1078 self_leader_rgsws,
1079 not_self_leader_rgsws,
1080 auto_keys,
1081 lwe_ksk,
1082 cr_seed.clone(),
1083 self.pbs_info.parameters.clone(),
1084 user_id,
1085 )
1086 }
1087
1088 pub(super) fn aggregate_multi_party_server_key_shares<S>(
1089 &self,
1090 shares: &[CommonReferenceSeededMultiPartyServerKeyShare<
1091 M,
1092 BoolParameters<M::MatElement>,
1093 MultiPartyCrs<S>,
1094 >],
1095 ) -> SeededMultiPartyServerKey<M, MultiPartyCrs<S>, BoolParameters<M::MatElement>>
1096 where
1097 S: PartialEq + Clone,
1098 M: Clone,
1099 {
1100 assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
1101 assert!(shares.len() > 0);
1102
1103 let total_users = shares.len();
1104
1105 let parameters = shares[0].parameters().clone();
1106 let cr_seed = shares[0].cr_seed();
1107
1108 let rlwe_n = parameters.rlwe_n().0;
1109 let g = parameters.g() as isize;
1110 let rlwe_q = parameters.rlwe_q();
1111 let lwe_q = parameters.lwe_q();
1112
1113 // sanity checks
1114 shares.iter().skip(1).for_each(|s| {
1115 assert!(s.parameters() == ¶meters);
1116 assert!(s.cr_seed() == cr_seed);
1117 });
1118
1119 let rlweq_modop = &self.pbs_info.rlwe_modop;
1120 let rlweq_nttop = &self.pbs_info.rlwe_nttop;
1121
1122 // auto keys
1123 let mut auto_keys = HashMap::new();
1124 let auto_elements_dlog = parameters.auto_element_dlogs();
1125 for i in auto_elements_dlog.into_iter() {
1126 let mut key = M::zeros(parameters.auto_decomposition_count().0, rlwe_n);
1127
1128 shares.iter().for_each(|s| {
1129 let auto_key_share_i = s.auto_keys().get(&i).expect("Auto key {i} missing");
1130 assert!(
1131 auto_key_share_i.dimension()
1132 == (parameters.auto_decomposition_count().0, rlwe_n)
1133 );
1134 izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
1135 |(partb_out, partb_share)| {
1136 rlweq_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
1137 },
1138 );
1139 });
1140
1141 auto_keys.insert(i, key);
1142 }
1143
1144 // rgsw ciphertext (most expensive part!)
1145 let rgsw_cts = {
1146 let rgsw_x_rgsw_decomposer =
1147 parameters.rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1148 let rlwe_x_rgsw_decomposer = self.pbs_info().rlwe_rgsw_decomposer();
1149 let rgsw_x_rgsw_dimension = (
1150 rgsw_x_rgsw_decomposer.a().decomposition_count() * 2
1151 + rgsw_x_rgsw_decomposer.b().decomposition_count() * 2,
1152 rlwe_n,
1153 );
1154 let rlwe_x_rgsw_dimension = (
1155 rlwe_x_rgsw_decomposer.a().decomposition_count() * 2
1156 + rlwe_x_rgsw_decomposer.b().decomposition_count() * 2,
1157 rlwe_n,
1158 );
1159
1160 let mut rgsw_x_rgsw_scratch = M::zeros(
1161 rgsw_x_rgsw_scratch_rows(rlwe_x_rgsw_decomposer, &rgsw_x_rgsw_decomposer),
1162 rlwe_n,
1163 );
1164
1165 let shares_in_correct_order = (0..total_users)
1166 .map(|i| shares.iter().find(|s| s.user_id() == i).unwrap())
1167 .collect_vec();
1168
1169 let lwe_n = self.parameters().lwe_n().0;
1170 let (users_segments, users_segments_sizes): (Vec<(usize, usize)>, Vec<usize>) = (0
1171 ..total_users)
1172 .map(|(user_id)| {
1173 let (start_index, end_index) =
1174 interactive_mult_party_user_id_lwe_segment(user_id, total_users, lwe_n);
1175 ((start_index, end_index), end_index - start_index)
1176 })
1177 .unzip();
1178
1179 let mut rgsw_cts = Vec::with_capacity(lwe_n);
1180 users_segments
1181 .iter()
1182 .enumerate()
1183 .for_each(|(user_id, user_segment)| {
1184 let share = shares_in_correct_order[user_id];
1185 for secret_index in user_segment.0..user_segment.1 {
1186 let mut rgsw_i =
1187 share.self_leader_rgsws()[secret_index - user_segment.0].clone();
1188 // assert already exists in RGSW x RGSW rountine
1189 assert!(rgsw_i.dimension() == rlwe_x_rgsw_dimension);
1190
1191 // multiply leader's RGSW ct at `secret_index` with RGSW cts of other users
1192 // for lwe index `secret_index`
1193 (0..total_users)
1194 .filter(|i| i != &user_id)
1195 .for_each(|other_user_id| {
1196 let mut offset = 0;
1197 if other_user_id < user_id {
1198 offset = users_segments_sizes[other_user_id];
1199 }
1200
1201 let mut other_rgsw_i = shares_in_correct_order[other_user_id]
1202 .not_self_leader_rgsws()
1203 [secret_index.checked_sub(offset).unwrap()]
1204 .clone();
1205 // assert already exists in RGSW x RGSW rountine
1206 assert!(other_rgsw_i.dimension() == rgsw_x_rgsw_dimension);
1207
1208 // send to evaluation domain for RGSwxRGSW mul
1209 other_rgsw_i
1210 .iter_rows_mut()
1211 .for_each(|r| rlweq_nttop.forward(r.as_mut()));
1212
1213 rgsw_by_rgsw_inplace(
1214 &mut RgswCiphertextMutRef::new(
1215 rgsw_i.as_mut(),
1216 rlwe_x_rgsw_decomposer.a().decomposition_count(),
1217 rlwe_x_rgsw_decomposer.b().decomposition_count(),
1218 ),
1219 &RgswCiphertextRef::new(
1220 other_rgsw_i.as_ref(),
1221 rgsw_x_rgsw_decomposer.a().decomposition_count(),
1222 rgsw_x_rgsw_decomposer.b().decomposition_count(),
1223 ),
1224 rlwe_x_rgsw_decomposer,
1225 &rgsw_x_rgsw_decomposer,
1226 &mut RuntimeScratchMutRef::new(rgsw_x_rgsw_scratch.as_mut()),
1227 rlweq_nttop,
1228 rlweq_modop,
1229 );
1230 });
1231
1232 rgsw_cts.push(rgsw_i);
1233 }
1234 });
1235
1236 rgsw_cts
1237 };
1238
1239 // LWE ksks
1240 let mut lwe_ksk = M::R::zeros(rlwe_n * parameters.lwe_decomposition_count().0);
1241 let lweq_modop = &self.pbs_info.lwe_modop;
1242 shares.iter().for_each(|si| {
1243 assert!(si.lwe_ksk().as_ref().len() == rlwe_n * parameters.lwe_decomposition_count().0);
1244 lweq_modop.elwise_add_mut(lwe_ksk.as_mut(), si.lwe_ksk().as_ref())
1245 });
1246
1247 SeededMultiPartyServerKey::new(rgsw_cts, auto_keys, lwe_ksk, cr_seed.clone(), parameters)
1248 }
1249
1250 pub(super) fn aggregate_non_interactive_multi_party_key_share(
1251 &self,
1252 cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
1253 total_users: usize,
1254 key_shares: &[CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
1255 M,
1256 NonInteractiveMultiPartyCrs<[u8; 32]>,
1257 >],
1258 ) -> SeededNonInteractiveMultiPartyServerKey<
1259 M,
1260 NonInteractiveMultiPartyCrs<[u8; 32]>,
1261 BoolParameters<M::MatElement>,
1262 >
1263 where
1264 M: Clone + Debug,
1265 <M as Matrix>::R: RowMut + Clone,
1266 {
1267 assert_eq!(
1268 self.parameters().variant(),
1269 &ParameterVariant::NonInteractiveMultiParty
1270 );
1271
1272 let total_users = key_shares.len();
1273 let key_shares = (0..total_users)
1274 .map(|user_id| {
1275 // find share of user_id
1276 key_shares
1277 .iter()
1278 .find(|share| share.user_index() == user_id)
1279 .expect(&format!("Key Share for user_id={user_id} missing"))
1280 })
1281 .collect_vec();
1282
1283 let rlwe_modop = &self.pbs_info().rlwe_modop;
1284 let nttop = &self.pbs_info().rlwe_nttop;
1285 let ring_size = self.parameters().rlwe_n().0;
1286 let rlwe_q = self.parameters().rlwe_q();
1287 let lwe_modop = self.pbs_info().modop_lweq();
1288
1289 // Generate Key switching key from u_j to s, where u_j user j's RLWE secret and
1290 // s is the ideal RLWE secret.
1291 //
1292 // User j gives [s_j * a_{i, j} + e + \beta^i u_j] where a_{i, j} is user j
1293 // specific publicly know polynomial sampled from user j's pseudo random seed
1294 // defined in the protocol.
1295 //
1296 // User k, k != j, gives [s_k * a_{i, j} + e].
1297 //
1298 // We set Ksk(u_j -> s) = [s_j * a_{i, j} + e + \beta^i u_j + \sum_{k \in P, k
1299 // != j} s_k * a_{i, j} + e]
1300 let ni_uj_to_s_decomposer = self
1301 .parameters()
1302 .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>();
1303 let mut uj_to_s_ksks = key_shares
1304 .iter()
1305 .map(|share| {
1306 let mut useri_ui_to_s_ksk = share.ui_to_s_ksk().clone();
1307 assert!(
1308 useri_ui_to_s_ksk.dimension()
1309 == (ni_uj_to_s_decomposer.decomposition_count(), ring_size)
1310 );
1311 key_shares
1312 .iter()
1313 .filter(|x| x.user_index() != share.user_index())
1314 .for_each(|other_share| {
1315 let op2 = other_share.ui_to_s_ksk_zero_encs_for_user_i(share.user_index());
1316 assert!(
1317 op2.dimension()
1318 == (ni_uj_to_s_decomposer.decomposition_count(), ring_size)
1319 );
1320 izip!(useri_ui_to_s_ksk.iter_rows_mut(), op2.iter_rows()).for_each(
1321 |(add_to, add_from)| {
1322 rlwe_modop.elwise_add_mut(add_to.as_mut(), add_from.as_ref())
1323 },
1324 );
1325 });
1326 useri_ui_to_s_ksk
1327 })
1328 .collect_vec();
1329
1330 let rgsw_cts = {
1331 // Send u_j -> s ksk in evaluation domain and sample corresponding a's using
1332 // user j's ksk seed to prepare for upcoming key switches
1333 uj_to_s_ksks.iter_mut().for_each(|ksk_i| {
1334 ksk_i
1335 .iter_rows_mut()
1336 .for_each(|r| nttop.forward(r.as_mut()))
1337 });
1338 let uj_to_s_ksks_part_a_eval = key_shares
1339 .iter()
1340 .map(|share| {
1341 let mut ksk_prng = DefaultSecureRng::new_seeded(
1342 cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(share.user_index()),
1343 );
1344 let mut ais = M::zeros(ni_uj_to_s_decomposer.decomposition_count(), ring_size);
1345
1346 ais.iter_rows_mut().for_each(|r_ai| {
1347 RandomFillUniformInModulus::random_fill(
1348 &mut ksk_prng,
1349 rlwe_q,
1350 r_ai.as_mut(),
1351 );
1352
1353 nttop.forward(r_ai.as_mut())
1354 });
1355 ais
1356 })
1357 .collect_vec();
1358
1359 let rgsw_x_rgsw_decomposer = self
1360 .parameters()
1361 .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1362 let rlwe_x_rgsw_decomposer = self
1363 .parameters()
1364 .rlwe_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1365
1366 let d_max = if rgsw_x_rgsw_decomposer.a().decomposition_count()
1367 > rgsw_x_rgsw_decomposer.b().decomposition_count()
1368 {
1369 rgsw_x_rgsw_decomposer.a().decomposition_count()
1370 } else {
1371 rgsw_x_rgsw_decomposer.b().decomposition_count()
1372 };
1373
1374 let mut scratch_rgsw_x_rgsw = M::zeros(
1375 rgsw_x_rgsw_scratch_rows(&rlwe_x_rgsw_decomposer, &rgsw_x_rgsw_decomposer),
1376 self.parameters().rlwe_n().0,
1377 );
1378
1379 // Recall that given u_j * a_{i, l} + e + \beta^i X^{s_j[l]} from user j
1380 //
1381 // We generate:
1382 //
1383 // - RLWE(-s \beta^i X^{s_j[l]}) = KS_{u_j -> s}(a_{i, l} * s + e) + (0 , u_j *
1384 // a_{i, l} + e + \beta^i X^{s_j[l]}), where KS_{u_j -> s}(a_{i, l} * s + e) =
1385 // RLWE_s(a_{i, l} * u_j)
1386 // - RLWE(\beta^i X^{s_j[l]}) = KS_{u_j -> s}(-a_{i,l}) + (u_j * a_{i, l} + e +
1387 // \beta^i X^{s_j[l]}, 0), where KS_{u_j -> s}(-a_{i,l}) = RLWE_s(-a_{i,l} *
1388 // u_j)
1389 //
1390 // a_{i, l} * s + e = \sum_{j \in P} a_{i, l} * s_{j} + e
1391 let user_segments = (0..total_users)
1392 .map(|user_id| {
1393 interactive_mult_party_user_id_lwe_segment(
1394 user_id,
1395 total_users,
1396 self.parameters().lwe_n().0,
1397 )
1398 })
1399 .collect_vec();
1400 // Note: Each user is assigned a contigous LWE segement and the LWE dimension is
1401 // split approximately uniformly across all users. Hence, concatenation of all
1402 // user specific lwe segments will give LWE dimension.
1403 let rgsw_cts = user_segments
1404 .into_iter()
1405 .enumerate()
1406 .flat_map(|(user_id, lwe_segment)| {
1407 (lwe_segment.0..lwe_segment.1)
1408 .into_iter()
1409 .map(|lwe_index| {
1410 // We sample d_b `-a_i`s to key switch and generate RLWE'(m). But before
1411 // we sampling we need to puncture a_prng d_max - d_b times to align
1412 // a_i's. After sampling we decompose `-a_i`s and send them to
1413 // evaluation domain for upcoming key switches.
1414 let mut a_prng = DefaultSecureRng::new_seeded(
1415 cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1416 );
1417
1418 let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1419 (0..d_max - rgsw_x_rgsw_decomposer.b().decomposition_count()).for_each(
1420 |_| {
1421 RandomFillUniformInModulus::random_fill(
1422 &mut a_prng,
1423 rlwe_q,
1424 scratch.as_mut(),
1425 );
1426 },
1427 );
1428
1429 let decomp_neg_ais = (0..rgsw_x_rgsw_decomposer
1430 .b()
1431 .decomposition_count())
1432 .map(|_| {
1433 RandomFillUniformInModulus::random_fill(
1434 &mut a_prng,
1435 rlwe_q,
1436 scratch.as_mut(),
1437 );
1438 rlwe_modop.elwise_neg_mut(scratch.as_mut());
1439
1440 let mut decomp_neg_ai = M::zeros(
1441 ni_uj_to_s_decomposer.decomposition_count(),
1442 self.parameters().rlwe_n().0,
1443 );
1444 scratch.as_ref().iter().enumerate().for_each(|(index, el)| {
1445 ni_uj_to_s_decomposer
1446 .decompose_iter(el)
1447 .enumerate()
1448 .for_each(|(row_j, d_el)| {
1449 (decomp_neg_ai.as_mut()[row_j]).as_mut()[index] =
1450 d_el;
1451 });
1452 });
1453
1454 decomp_neg_ai
1455 .iter_rows_mut()
1456 .for_each(|ri| nttop.forward(ri.as_mut()));
1457
1458 decomp_neg_ai
1459 })
1460 .collect_vec();
1461
1462 // Aggregate zero encryptions to produce a_{i, l} * s + e =
1463 // \sum_{k in P} a_{i, l} * s_{k} + e where s is the ideal RLWE
1464 // secret. Aggregated a_{i, l} * s + e are key switched using
1465 // Ksk(u_j -> s) to produce RLWE_{s}(a_{i, l} * s) which are
1466 // then use to produce RLWE'(-sX^{s_{lwe}[l]}).
1467 // Hence, after aggregation we decompose a_{i, l} * s + e to
1468 // prepare for key switching
1469 let ni_rgsw_zero_encs = (0..rgsw_x_rgsw_decomposer
1470 .a()
1471 .decomposition_count())
1472 .map(|i| {
1473 let mut sum = M::R::zeros(self.parameters().rlwe_n().0);
1474 key_shares.iter().for_each(|k| {
1475 let to_add_ref = k
1476 .ni_rgsw_zero_enc_for_lwe_index(lwe_index)
1477 .get_row_slice(i);
1478 assert!(to_add_ref.len() == self.parameters().rlwe_n().0);
1479 rlwe_modop.elwise_add_mut(sum.as_mut(), to_add_ref);
1480 });
1481
1482 // decompose
1483 let mut decomp_sum = M::zeros(
1484 ni_uj_to_s_decomposer.decomposition_count(),
1485 self.parameters().rlwe_n().0,
1486 );
1487 sum.as_ref().iter().enumerate().for_each(|(index, el)| {
1488 ni_uj_to_s_decomposer
1489 .decompose_iter(el)
1490 .enumerate()
1491 .for_each(|(row_j, d_el)| {
1492 (decomp_sum.as_mut()[row_j]).as_mut()[index] = d_el;
1493 });
1494 });
1495
1496 decomp_sum
1497 .iter_rows_mut()
1498 .for_each(|r| nttop.forward(r.as_mut()));
1499
1500 decomp_sum
1501 })
1502 .collect_vec();
1503
1504 // Produce RGSW(X^{s_{j=user_id, lwe}[l]}) for the
1505 // leader, ie user's id = user_id.
1506 // Recall leader's RGSW ciphertext must be constructed
1507 // for RLWE x RGSW multiplication, and is then used
1508 // to accumulate, using RGSW x RGSW multiplication,
1509 // X^{s_{j != user_id, lwe}[l]} from other users.
1510 let mut rgsw_i = produce_rgsw_ciphertext_from_ni_rgsw(
1511 key_shares[user_id]
1512 .ni_rgsw_cts_for_self_leader_lwe_index(lwe_index),
1513 &ni_rgsw_zero_encs[rgsw_x_rgsw_decomposer
1514 .a()
1515 .decomposition_count()
1516 - rlwe_x_rgsw_decomposer.a().decomposition_count()..],
1517 &decomp_neg_ais[rgsw_x_rgsw_decomposer.b().decomposition_count()
1518 - rlwe_x_rgsw_decomposer.b().decomposition_count()..],
1519 &rlwe_x_rgsw_decomposer,
1520 self.parameters(),
1521 (&uj_to_s_ksks[user_id], &uj_to_s_ksks_part_a_eval[user_id]),
1522 rlwe_modop,
1523 nttop,
1524 false,
1525 );
1526
1527 // RGSW for lwe_index of users that are not leader.
1528 //
1529 // Recall that for users that are not leader for the
1530 // lwe_index we require to produce RGSW ciphertext for
1531 // RGSW x RGSW product
1532 (0..total_users)
1533 .filter(|i| *i != user_id)
1534 .for_each(|other_user_id| {
1535 let mut other_rgsw_i = produce_rgsw_ciphertext_from_ni_rgsw(
1536 key_shares[other_user_id]
1537 .ni_rgsw_cts_for_self_not_leader_lwe_index(lwe_index),
1538 &ni_rgsw_zero_encs,
1539 &decomp_neg_ais,
1540 &rgsw_x_rgsw_decomposer,
1541 self.parameters(),
1542 (
1543 &uj_to_s_ksks[other_user_id],
1544 &uj_to_s_ksks_part_a_eval[other_user_id],
1545 ),
1546 rlwe_modop,
1547 nttop,
1548 true,
1549 );
1550
1551 rgsw_by_rgsw_inplace(
1552 &mut RgswCiphertextMutRef::new(
1553 rgsw_i.as_mut(),
1554 rlwe_x_rgsw_decomposer.a().decomposition_count(),
1555 rlwe_x_rgsw_decomposer.b().decomposition_count(),
1556 ),
1557 &RgswCiphertextRef::new(
1558 other_rgsw_i.as_ref(),
1559 rgsw_x_rgsw_decomposer.a().decomposition_count(),
1560 rgsw_x_rgsw_decomposer.b().decomposition_count(),
1561 ),
1562 &rlwe_x_rgsw_decomposer,
1563 &rgsw_x_rgsw_decomposer,
1564 &mut RuntimeScratchMutRef::new(
1565 scratch_rgsw_x_rgsw.as_mut(),
1566 ),
1567 nttop,
1568 rlwe_modop,
1569 )
1570 });
1571
1572 rgsw_i
1573 })
1574 .collect_vec()
1575 })
1576 .collect_vec();
1577
1578 // put u_j to s ksk in coefficient domain
1579 uj_to_s_ksks.iter_mut().for_each(|ksk_i| {
1580 ksk_i
1581 .iter_rows_mut()
1582 .for_each(|r| nttop.backward(r.as_mut()))
1583 });
1584
1585 rgsw_cts
1586 };
1587
1588 // auto keys
1589 let auto_keys = {
1590 let mut auto_keys = HashMap::new();
1591 let auto_elements_dlog = self.parameters().auto_element_dlogs();
1592 for i in auto_elements_dlog.into_iter() {
1593 let mut key = M::zeros(self.parameters().auto_decomposition_count().0, ring_size);
1594
1595 key_shares.iter().for_each(|s| {
1596 let auto_key_share_i =
1597 s.auto_keys_share().get(&i).expect("Auto key {i} missing");
1598 assert!(
1599 auto_key_share_i.dimension()
1600 == (self.parameters().auto_decomposition_count().0, ring_size)
1601 );
1602 izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
1603 |(partb_out, partb_share)| {
1604 rlwe_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
1605 },
1606 );
1607 });
1608
1609 auto_keys.insert(i, key);
1610 }
1611 auto_keys
1612 };
1613
1614 // LWE ksk
1615 let lwe_ksk = {
1616 let mut lwe_ksk =
1617 M::R::zeros(self.parameters().lwe_decomposition_count().0 * ring_size);
1618 key_shares.iter().for_each(|s| {
1619 assert!(
1620 s.lwe_ksk_share().as_ref().len()
1621 == self.parameters().lwe_decomposition_count().0 * ring_size
1622 );
1623 lwe_modop.elwise_add_mut(lwe_ksk.as_mut(), s.lwe_ksk_share().as_ref());
1624 });
1625 lwe_ksk
1626 };
1627
1628 SeededNonInteractiveMultiPartyServerKey::new(
1629 uj_to_s_ksks,
1630 rgsw_cts,
1631 auto_keys,
1632 lwe_ksk,
1633 cr_seed.clone(),
1634 self.parameters().clone(),
1635 )
1636 }
1637
1638 pub(super) fn non_interactive_multi_party_key_share<
1639 K: NonInteractiveMultiPartyClientKey<Element = i32>,
1640 >(
1641 &self,
1642 cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
1643 self_index: usize,
1644 total_users: usize,
1645 client_key: &K,
1646 ) -> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
1647 M,
1648 NonInteractiveMultiPartyCrs<[u8; 32]>,
1649 > {
1650 assert_eq!(
1651 self.parameters().variant(),
1652 &ParameterVariant::NonInteractiveMultiParty
1653 );
1654
1655 // TODO: check whether parameters support `total_users`
1656 let nttop = self.pbs_info().nttop_rlweq();
1657 let rlwe_modop = self.pbs_info().modop_rlweq();
1658 let ring_size = self.pbs_info().rlwe_n();
1659 let rlwe_q = self.parameters().rlwe_q();
1660
1661 let sk_rlwe = client_key.sk_rlwe();
1662 let sk_u_rlwe = client_key.sk_u_rlwe();
1663 let sk_lwe = client_key.sk_lwe();
1664
1665 let (ui_to_s_ksk, ksk_zero_encs_for_others) = DefaultSecureRng::with_local_mut(|rng| {
1666 // ui_to_s_ksk
1667 let non_interactive_decomposer = self
1668 .parameters()
1669 .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>(
1670 );
1671 let non_interactive_gadget_vec = non_interactive_decomposer.gadget_vector();
1672 let ui_to_s_ksk = {
1673 let mut p_rng = DefaultSecureRng::new_seeded(
1674 cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(self_index),
1675 );
1676
1677 non_interactive_ksk_gen::<M, _, _, _, _, _>(
1678 &sk_rlwe,
1679 &sk_u_rlwe,
1680 &non_interactive_gadget_vec,
1681 &mut p_rng,
1682 rng,
1683 nttop,
1684 rlwe_modop,
1685 )
1686 };
1687
1688 // zero encryptions for others uj_to_s ksk
1689 let all_users_except_self = (0..total_users).filter(|x| *x != self_index);
1690 let zero_encs_for_others = all_users_except_self
1691 .map(|other_user_index| {
1692 let mut p_rng = DefaultSecureRng::new_seeded(
1693 cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(other_user_index),
1694 );
1695 let zero_encs =
1696 non_interactive_ksk_zero_encryptions_for_other_party_i::<M, _, _, _, _, _>(
1697 &sk_rlwe,
1698 &non_interactive_gadget_vec,
1699 &mut p_rng,
1700 rng,
1701 nttop,
1702 rlwe_modop,
1703 );
1704 zero_encs
1705 })
1706 .collect_vec();
1707
1708 (ui_to_s_ksk, zero_encs_for_others)
1709 });
1710
1711 // Non-interactive RGSW cts
1712 let (ni_rgsw_zero_encs, self_leader_ni_rgsw_cts, not_self_leader_rgsw_cts) = {
1713 let rgsw_x_rgsw_decomposer = self
1714 .parameters()
1715 .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1716 let rlwe_x_rgsw_decomposer = self
1717 .parameters()
1718 .rlwe_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1719
1720 // We assume that d_{a/b} for RGSW x RGSW are always < d'_{a/b} for RLWE x RGSW
1721 assert!(
1722 rlwe_x_rgsw_decomposer.a().decomposition_count()
1723 < rgsw_x_rgsw_decomposer.a().decomposition_count()
1724 );
1725 assert!(
1726 rlwe_x_rgsw_decomposer.b().decomposition_count()
1727 < rgsw_x_rgsw_decomposer.b().decomposition_count()
1728 );
1729
1730 let sj_poly_eval = {
1731 let mut s = M::R::try_convert_from(&sk_rlwe, rlwe_q);
1732 nttop.forward(s.as_mut());
1733 s
1734 };
1735
1736 let d_rgsw_a = rgsw_x_rgsw_decomposer.a().decomposition_count();
1737 let d_rgsw_b = rgsw_x_rgsw_decomposer.b().decomposition_count();
1738 let d_max = std::cmp::max(d_rgsw_a, d_rgsw_b);
1739
1740 // Zero encyptions for each LWE index. We generate d_a zero encryptions for each
1741 // LWE index using a_{i, l} with i \in {d_max - d_a , d_max) and l = lwe_index
1742 let zero_encs = {
1743 (0..self.parameters().lwe_n().0)
1744 .map(|lwe_index| {
1745 let mut p_rng = DefaultSecureRng::new_seeded(
1746 cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1747 );
1748
1749 let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1750
1751 // puncture seeded prng d_max - d_a times
1752 (0..(d_max - d_rgsw_a)).into_iter().for_each(|_| {
1753 RandomFillUniformInModulus::random_fill(
1754 &mut p_rng,
1755 rlwe_q,
1756 scratch.as_mut(),
1757 );
1758 });
1759
1760 let mut zero_enc = M::zeros(d_rgsw_a, self.parameters().rlwe_n().0);
1761 zero_enc.iter_rows_mut().for_each(|out| {
1762 // sample a_i
1763 RandomFillUniformInModulus::random_fill(
1764 &mut p_rng,
1765 rlwe_q,
1766 out.as_mut(),
1767 );
1768
1769 // a_i * s_j
1770 nttop.forward(out.as_mut());
1771 rlwe_modop.elwise_mul_mut(out.as_mut(), sj_poly_eval.as_ref());
1772 nttop.backward(out.as_mut());
1773
1774 // a_j * s_j + e
1775 DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1776 RandomFillGaussianInModulus::random_fill(
1777 rng,
1778 rlwe_q,
1779 scratch.as_mut(),
1780 );
1781 });
1782
1783 rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1784 });
1785
1786 zero_enc
1787 })
1788 .collect_vec()
1789 };
1790
1791 let uj_poly_eval = {
1792 let mut u = M::R::try_convert_from(&sk_u_rlwe, rlwe_q);
1793 nttop.forward(u.as_mut());
1794 u
1795 };
1796
1797 // Generate non-interactive RGSW ciphertexts a_{i, l} u_j + e + \beta X^{s_j[l]}
1798 // for i \in (0, d_max]
1799 let (self_start_index, self_end_index) = interactive_mult_party_user_id_lwe_segment(
1800 self_index,
1801 total_users,
1802 self.parameters().lwe_n().0,
1803 );
1804
1805 // For LWE indices [self_start_index, self_end_index) user generates
1806 // non-interactive RGSW cts for RLWE x RGSW product. We refer to
1807 // such indices as where user is the leader. For the rest of
1808 // the indices user generates non-interactive RGWS cts for RGSW x
1809 // RGSW multiplication. We refer to such indices as where user is
1810 // not the leader.
1811 let self_leader_ni_rgsw_cts = {
1812 let max_rlwe_x_rgsw_decomposer = if rlwe_x_rgsw_decomposer.a().decomposition_count()
1813 > rlwe_x_rgsw_decomposer.b().decomposition_count()
1814 {
1815 rlwe_x_rgsw_decomposer.a()
1816 } else {
1817 rlwe_x_rgsw_decomposer.b()
1818 };
1819
1820 let gadget_vec = max_rlwe_x_rgsw_decomposer.gadget_vector();
1821
1822 (self_start_index..self_end_index)
1823 .map(|lwe_index| {
1824 let mut p_rng = DefaultSecureRng::new_seeded(
1825 cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1826 );
1827
1828 // puncture p_rng d_max - d'_max time to align with `a_{i, l}`s used to
1829 // produce RGSW cts for RGSW x RGSW
1830 let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1831 (0..(d_max - max_rlwe_x_rgsw_decomposer.decomposition_count()))
1832 .into_iter()
1833 .for_each(|_| {
1834 RandomFillUniformInModulus::random_fill(
1835 &mut p_rng,
1836 rlwe_q,
1837 scratch.as_mut(),
1838 );
1839 });
1840
1841 let mut ni_rgsw_cts = M::zeros(
1842 max_rlwe_x_rgsw_decomposer.decomposition_count(),
1843 self.parameters().rlwe_n().0,
1844 );
1845
1846 // X^{s_{j, lwe}[l]}
1847 let m_poly = encode_x_pow_si_with_emebedding_factor::<M::R, _>(
1848 sk_lwe[lwe_index],
1849 self.pbs_info().embedding_factor(),
1850 self.parameters().rlwe_n().0,
1851 rlwe_q,
1852 );
1853
1854 izip!(ni_rgsw_cts.iter_rows_mut(), gadget_vec.iter()).for_each(
1855 |(out, beta)| {
1856 // sample a_i
1857 RandomFillUniformInModulus::random_fill(
1858 &mut p_rng,
1859 rlwe_q,
1860 out.as_mut(),
1861 );
1862
1863 // u_j * a_i
1864 nttop.forward(out.as_mut());
1865 rlwe_modop.elwise_mul_mut(out.as_mut(), uj_poly_eval.as_ref());
1866 nttop.backward(out.as_mut());
1867
1868 // u_j + a_i + e
1869 DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1870 RandomFillGaussianInModulus::random_fill(
1871 rng,
1872 rlwe_q,
1873 scratch.as_mut(),
1874 );
1875 });
1876 rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1877
1878 // u_j + a_i + e + beta m
1879 rlwe_modop.elwise_scalar_mul(
1880 scratch.as_mut(),
1881 m_poly.as_ref(),
1882 beta,
1883 );
1884 rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1885 },
1886 );
1887
1888 ni_rgsw_cts
1889 })
1890 .collect_vec()
1891 };
1892
1893 let not_self_leader_rgsw_cts = {
1894 let max_rgsw_x_rgsw_decomposer = if rgsw_x_rgsw_decomposer.a().decomposition_count()
1895 > rgsw_x_rgsw_decomposer.b().decomposition_count()
1896 {
1897 rgsw_x_rgsw_decomposer.a()
1898 } else {
1899 rgsw_x_rgsw_decomposer.b()
1900 };
1901 let gadget_vec = max_rgsw_x_rgsw_decomposer.gadget_vector();
1902
1903 ((0..self_start_index).chain(self_end_index..self.parameters().lwe_n().0))
1904 .map(|lwe_index| {
1905 let mut p_rng = DefaultSecureRng::new_seeded(
1906 cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1907 );
1908 let mut ni_rgsw_cts = M::zeros(
1909 max_rgsw_x_rgsw_decomposer.decomposition_count(),
1910 self.parameters().rlwe_n().0,
1911 );
1912 let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1913
1914 // X^{s_{j, lwe}[l]}
1915 let m_poly = encode_x_pow_si_with_emebedding_factor::<M::R, _>(
1916 sk_lwe[lwe_index],
1917 self.pbs_info().embedding_factor(),
1918 self.parameters().rlwe_n().0,
1919 rlwe_q,
1920 );
1921
1922 izip!(ni_rgsw_cts.iter_rows_mut(), gadget_vec.iter()).for_each(
1923 |(out, beta)| {
1924 // sample a_i
1925 RandomFillUniformInModulus::random_fill(
1926 &mut p_rng,
1927 rlwe_q,
1928 out.as_mut(),
1929 );
1930
1931 // u_j * a_i
1932 nttop.forward(out.as_mut());
1933 rlwe_modop.elwise_mul_mut(out.as_mut(), uj_poly_eval.as_ref());
1934 nttop.backward(out.as_mut());
1935
1936 // u_j + a_i + e
1937 DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1938 RandomFillGaussianInModulus::random_fill(
1939 rng,
1940 rlwe_q,
1941 scratch.as_mut(),
1942 );
1943 });
1944 rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1945
1946 // u_j * a_i + e + beta m
1947 rlwe_modop.elwise_scalar_mul(
1948 scratch.as_mut(),
1949 m_poly.as_ref(),
1950 beta,
1951 );
1952 rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1953 },
1954 );
1955
1956 ni_rgsw_cts
1957 })
1958 .collect_vec()
1959 };
1960
1961 (zero_encs, self_leader_ni_rgsw_cts, not_self_leader_rgsw_cts)
1962 };
1963
1964 // Auto key share
1965 let auto_keys_share = {
1966 let auto_seed = cr_seed.auto_keys_cts_seed::<DefaultSecureRng>();
1967 self._common_rountine_multi_party_auto_keys_share_gen(auto_seed, &sk_rlwe)
1968 };
1969
1970 // Lwe Ksk share
1971 let lwe_ksk_share = {
1972 let lwe_ksk_seed = cr_seed.lwe_ksk_cts_seed::<DefaultSecureRng>();
1973 self._common_rountine_multi_party_lwe_ksk_share_gen(lwe_ksk_seed, &sk_rlwe, &sk_lwe)
1974 };
1975
1976 CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare::new(
1977 self_leader_ni_rgsw_cts,
1978 not_self_leader_rgsw_cts,
1979 ni_rgsw_zero_encs,
1980 ui_to_s_ksk,
1981 ksk_zero_encs_for_others,
1982 auto_keys_share,
1983 lwe_ksk_share,
1984 self_index,
1985 total_users,
1986 self.parameters().lwe_n().0,
1987 cr_seed.clone(),
1988 )
1989 }
1990
1991 fn _common_rountine_multi_party_auto_keys_share_gen(
1992 &self,
1993 auto_seed: <DefaultSecureRng as NewWithSeed>::Seed,
1994 sk_rlwe: &[i32],
1995 ) -> HashMap<usize, M> {
1996 let g = self.pbs_info.parameters.g();
1997 let ring_size = self.pbs_info.parameters.rlwe_n().0;
1998 let br_q = self.pbs_info.parameters.br_q();
1999 let rlweq_modop = &self.pbs_info.rlwe_modop;
2000 let rlweq_nttop = &self.pbs_info.rlwe_nttop;
2001
2002 DefaultSecureRng::with_local_mut(|rng| {
2003 let mut p_rng = DefaultSecureRng::new_seeded(auto_seed);
2004
2005 let mut auto_keys = HashMap::new();
2006 let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
2007 let auto_element_dlogs = self.pbs_info.parameters.auto_element_dlogs();
2008
2009 for i in auto_element_dlogs.into_iter() {
2010 let g_pow = if i == 0 {
2011 -(g as isize)
2012 } else {
2013 (g.pow(i as u32) % br_q) as isize
2014 };
2015
2016 let mut ksk_out = M::zeros(
2017 self.pbs_info.auto_decomposer.decomposition_count(),
2018 ring_size,
2019 );
2020 seeded_auto_key_gen(
2021 &mut ksk_out,
2022 sk_rlwe,
2023 g_pow,
2024 &auto_gadget,
2025 rlweq_modop,
2026 rlweq_nttop,
2027 &mut p_rng,
2028 rng,
2029 );
2030 auto_keys.insert(i, ksk_out);
2031 }
2032
2033 auto_keys
2034 })
2035 }
2036
2037 fn _common_rountine_multi_party_lwe_ksk_share_gen(
2038 &self,
2039 lwe_ksk_seed: <DefaultSecureRng as NewWithSeed>::Seed,
2040 sk_rlwe: &[i32],
2041 sk_lwe: &[i32],
2042 ) -> M::R {
2043 DefaultSecureRng::with_local_mut(|rng| {
2044 let mut p_rng = DefaultSecureRng::new_seeded(lwe_ksk_seed);
2045 let lwe_modop = &self.pbs_info.lwe_modop;
2046 let d_lwe_gadget_vec = self.pbs_info.lwe_decomposer.gadget_vector();
2047 seeded_lwe_ksk_keygen(
2048 sk_rlwe,
2049 sk_lwe,
2050 &d_lwe_gadget_vec,
2051 lwe_modop,
2052 &mut p_rng,
2053 rng,
2054 )
2055 })
2056 }
2057
2058 pub(super) fn multi_party_public_key_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
2059 &self,
2060 cr_seed: &MultiPartyCrs<[u8; 32]>,
2061 client_key: &K,
2062 ) -> CommonReferenceSeededCollectivePublicKeyShare<
2063 <M as Matrix>::R,
2064 [u8; 32],
2065 BoolParameters<<M as Matrix>::MatElement>,
2066 > {
2067 DefaultSecureRng::with_local_mut(|rng| {
2068 let mut share_out = M::R::zeros(self.pbs_info.parameters.rlwe_n().0);
2069 let modop = &self.pbs_info.rlwe_modop;
2070 let nttop = &self.pbs_info.rlwe_nttop;
2071 let pk_seed = cr_seed.public_key_share_seed::<DefaultSecureRng>();
2072 let mut main_prng = DefaultSecureRng::new_seeded(pk_seed);
2073 public_key_share(
2074 &mut share_out,
2075 &client_key.sk_rlwe(),
2076 modop,
2077 nttop,
2078 &mut main_prng,
2079 rng,
2080 );
2081 CommonReferenceSeededCollectivePublicKeyShare::new(
2082 share_out,
2083 pk_seed,
2084 self.pbs_info.parameters.clone(),
2085 )
2086 })
2087 }
2088
2089 pub(super) fn multi_party_decryption_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
2090 &self,
2091 lwe_ct: &M::R,
2092 client_key: &K,
2093 ) -> <M as Matrix>::MatElement {
2094 assert!(lwe_ct.as_ref().len() == self.pbs_info.parameters.rlwe_n().0 + 1);
2095 let modop = &self.pbs_info.rlwe_modop;
2096 let mut neg_s =
2097 M::R::try_convert_from(&client_key.sk_rlwe(), &self.pbs_info.parameters.rlwe_q());
2098 modop.elwise_neg_mut(neg_s.as_mut());
2099
2100 let mut neg_sa = M::MatElement::zero();
2101 izip!(lwe_ct.as_ref().iter().skip(1), neg_s.as_ref().iter()).for_each(|(ai, nsi)| {
2102 neg_sa = modop.add(&neg_sa, &modop.mul(ai, nsi));
2103 });
2104
2105 let e = DefaultSecureRng::with_local_mut(|rng| {
2106 RandomGaussianElementInModulus::random(rng, self.pbs_info.parameters.rlwe_q())
2107 });
2108 let share = modop.add(&neg_sa, &e);
2109
2110 share
2111 }
2112
2113 pub(crate) fn multi_party_decrypt(&self, shares: &[M::MatElement], lwe_ct: &M::R) -> bool {
2114 let modop = &self.pbs_info.rlwe_modop;
2115 let mut sum_a = M::MatElement::zero();
2116 shares
2117 .iter()
2118 .for_each(|share_i| sum_a = modop.add(&sum_a, &share_i));
2119
2120 let encoded_m = modop.add(&lwe_ct.as_ref()[0], &sum_a);
2121 self.pbs_info.parameters.rlwe_q().decode(encoded_m)
2122 }
2123
2124 pub(crate) fn pk_encrypt(&self, pk: &M, m: bool) -> M::R {
2125 self.pk_encrypt_batched(pk, &vec![m]).remove(0)
2126 }
2127
2128 /// Encrypts a batch booleans as multiple LWE ciphertexts.
2129 ///
2130 /// For public key encryption we first encrypt `m` as a RLWE ciphertext and
2131 /// then sample extract LWE samples at required indices.
2132 ///
2133 /// - TODO(Jay:) Communication can be improved by not sample exctracting and
2134 /// instead just truncate degree 0 values (part Bs)
2135 pub(crate) fn pk_encrypt_batched(&self, pk: &M, m: &[bool]) -> Vec<M::R> {
2136 DefaultSecureRng::with_local_mut(|rng| {
2137 let ring_size = self.pbs_info.parameters.rlwe_n().0;
2138 assert!(
2139 m.len() <= ring_size,
2140 "Cannot batch encrypt > ring_size{ring_size} elements at once"
2141 );
2142
2143 let modop = &self.pbs_info.rlwe_modop;
2144 let nttop = &self.pbs_info.rlwe_nttop;
2145
2146 // RLWE(0)
2147 // sample ephemeral key u
2148 let mut u = vec![0i32; ring_size];
2149 fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
2150 let mut u = M::R::try_convert_from(&u, &self.pbs_info.parameters.rlwe_q());
2151 nttop.forward(u.as_mut());
2152
2153 let mut ua = M::R::zeros(ring_size);
2154 ua.as_mut().copy_from_slice(pk.get_row_slice(0));
2155 let mut ub = M::R::zeros(ring_size);
2156 ub.as_mut().copy_from_slice(pk.get_row_slice(1));
2157
2158 // a*u
2159 nttop.forward(ua.as_mut());
2160 modop.elwise_mul_mut(ua.as_mut(), u.as_ref());
2161 nttop.backward(ua.as_mut());
2162
2163 // b*u
2164 nttop.forward(ub.as_mut());
2165 modop.elwise_mul_mut(ub.as_mut(), u.as_ref());
2166 nttop.backward(ub.as_mut());
2167
2168 let mut rlwe = M::zeros(2, ring_size);
2169 // sample error
2170 rlwe.iter_rows_mut().for_each(|ri| {
2171 RandomFillGaussianInModulus::<[M::MatElement], CiphertextModulus<M::MatElement>>::random_fill(
2172 rng,
2173 &self.pbs_info.parameters.rlwe_q(),
2174 ri.as_mut(),
2175 );
2176 });
2177
2178 // a*u + e0
2179 modop.elwise_add_mut(rlwe.get_row_mut(0), ua.as_ref());
2180 // b*u + e1
2181 modop.elwise_add_mut(rlwe.get_row_mut(1), ub.as_ref());
2182
2183 //FIXME(Jay): Figure out a way to get Q/8 form modulus
2184 let mut m_vec = M::R::zeros(ring_size);
2185 izip!(m_vec.as_mut().iter_mut(), m.iter()).for_each(|(m_el, m_bool)| {
2186 if *m_bool {
2187 // Q/8
2188 *m_el = self.pbs_info.rlwe_q().true_el()
2189 } else {
2190 // -Q/8
2191 *m_el = self.pbs_info.rlwe_q().false_el()
2192 }
2193 });
2194
2195 // b*u + e1 + m
2196 modop.elwise_add_mut(rlwe.get_row_mut(1), m_vec.as_ref());
2197 // rlwe.set(1, 0, modop.add(rlwe.get(1, 0), &m));
2198
2199 // sample extract index required indices
2200 let samples = m.len();
2201 (0..samples)
2202 .into_iter()
2203 .map(|i| {
2204 let mut lwe_out = M::R::zeros(ring_size + 1);
2205 sample_extract(&mut lwe_out, &rlwe, modop, i);
2206 lwe_out
2207 })
2208 .collect_vec()
2209 })
2210 }
2211
2212 pub fn sk_encrypt<K: SinglePartyClientKey<Element = i32>>(
2213 &self,
2214 m: bool,
2215 client_key: &K,
2216 ) -> M::R {
2217 //FIXME(Jay): Figure out a way to get Q/8 form modulus
2218 let m = if m {
2219 // Q/8
2220 self.pbs_info.rlwe_q().true_el()
2221 } else {
2222 // -Q/8
2223 self.pbs_info.rlwe_q().false_el()
2224 };
2225
2226 DefaultSecureRng::with_local_mut(|rng| {
2227 encrypt_lwe(&m, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop, rng)
2228 })
2229 }
2230
2231 pub fn sk_decrypt<K: SinglePartyClientKey<Element = i32>>(
2232 &self,
2233 lwe_ct: &M::R,
2234 client_key: &K,
2235 ) -> bool {
2236 let m = decrypt_lwe(lwe_ct, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop);
2237 self.pbs_info.rlwe_q().decode(m)
2238 }
2239}
2240
2241impl<M, NttOp, RlweModOp, LweModOp, Skey> BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
2242where
2243 M: MatrixMut + MatrixEntity,
2244 M::R: RowMut + RowEntity,
2245 M::MatElement: PrimInt + FromPrimitive + One + Copy + Zero + Display + WrappingSub + NumInfo,
2246 RlweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2247 LweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2248 NttOp: Ntt<Element = M::MatElement>,
2249{
2250 /// Returns c0 + c1 + Q/4
2251 fn _add_and_shift_lwe_cts(&self, c0: &mut M::R, c1: &M::R) {
2252 let modop = &self.pbs_info.rlwe_modop;
2253 modop.elwise_add_mut(c0.as_mut(), c1.as_ref());
2254 // +Q/4
2255 c0.as_mut()[0] = modop.add(&c0.as_ref()[0], &self.pbs_info.rlwe_qby4);
2256 }
2257
2258 /// Returns 2(c0 - c1) + Q/4
2259 fn _subtract_double_lwe_cts(&self, c0: &mut M::R, c1: &M::R) {
2260 let modop = &self.pbs_info.rlwe_modop;
2261 // c0 - c1
2262 modop.elwise_sub_mut(c0.as_mut(), c1.as_ref());
2263
2264 // double
2265 c0.as_mut().iter_mut().for_each(|v| *v = modop.add(v, v));
2266 }
2267}
2268
2269impl<M, NttOp, RlweModOp, LweModOp, Skey> BooleanGates
2270 for BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
2271where
2272 M: MatrixMut + MatrixEntity,
2273 M::R: RowMut + RowEntity + Clone,
2274 M::MatElement: PrimInt
2275 + FromPrimitive
2276 + One
2277 + Copy
2278 + Zero
2279 + Display
2280 + WrappingSub
2281 + NumInfo
2282 + From<bool>
2283 + WrappingAdd
2284 + Debug,
2285 RlweModOp: VectorOps<Element = M::MatElement>
2286 + ArithmeticOps<Element = M::MatElement>
2287 + ShoupMatrixFMA<M::R>,
2288 LweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2289 NttOp: Ntt<Element = M::MatElement>,
2290 Skey: PbsKey<AutoKey = <Skey as PbsKey>::RgswCt, LweKskKey = M>,
2291 <Skey as PbsKey>::RgswCt: WithShoupRepr<M = M>,
2292{
2293 type Ciphertext = M::R;
2294 type Key = Skey;
2295
2296 fn nand_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2297 self._add_and_shift_lwe_cts(c0, c1);
2298
2299 // PBS
2300 pbs(
2301 &self.pbs_info,
2302 &self.nand_test_vec,
2303 c0,
2304 server_key,
2305 &mut self.scratch_memory.lwe_vector,
2306 &mut self.scratch_memory.decomposition_matrix,
2307 );
2308 }
2309
2310 fn and_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2311 self._add_and_shift_lwe_cts(c0, c1);
2312
2313 // PBS
2314 pbs(
2315 &self.pbs_info,
2316 &self.and_test_vec,
2317 c0,
2318 server_key,
2319 &mut self.scratch_memory.lwe_vector,
2320 &mut self.scratch_memory.decomposition_matrix,
2321 );
2322 }
2323
2324 fn or_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2325 self._add_and_shift_lwe_cts(c0, c1);
2326
2327 // PBS
2328 pbs(
2329 &self.pbs_info,
2330 &self.or_test_vec,
2331 c0,
2332 server_key,
2333 &mut self.scratch_memory.lwe_vector,
2334 &mut self.scratch_memory.decomposition_matrix,
2335 );
2336 }
2337
2338 fn nor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2339 self._add_and_shift_lwe_cts(c0, c1);
2340
2341 // PBS
2342 pbs(
2343 &self.pbs_info,
2344 &self.nor_test_vec,
2345 c0,
2346 server_key,
2347 &mut self.scratch_memory.lwe_vector,
2348 &mut self.scratch_memory.decomposition_matrix,
2349 )
2350 }
2351
2352 fn xor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2353 self._subtract_double_lwe_cts(c0, c1);
2354
2355 // PBS
2356 pbs(
2357 &self.pbs_info,
2358 &self.xor_test_vec,
2359 c0,
2360 server_key,
2361 &mut self.scratch_memory.lwe_vector,
2362 &mut self.scratch_memory.decomposition_matrix,
2363 );
2364 }
2365
2366 fn xnor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2367 self._subtract_double_lwe_cts(c0, c1);
2368
2369 // PBS
2370 pbs(
2371 &self.pbs_info,
2372 &self.xnor_test_vec,
2373 c0,
2374 server_key,
2375 &mut self.scratch_memory.lwe_vector,
2376 &mut self.scratch_memory.decomposition_matrix,
2377 );
2378 }
2379
2380 fn not_inplace(&mut self, c0: &mut M::R) {
2381 let modop = &self.pbs_info.rlwe_modop;
2382 c0.as_mut().iter_mut().for_each(|v| *v = modop.neg(v));
2383 }
2384
2385 fn and(
2386 &mut self,
2387 c0: &Self::Ciphertext,
2388 c1: &Self::Ciphertext,
2389 key: &Self::Key,
2390 ) -> Self::Ciphertext {
2391 let mut out = c0.clone();
2392 self.and_inplace(&mut out, c1, key);
2393 out
2394 }
2395
2396 fn nand(
2397 &mut self,
2398 c0: &Self::Ciphertext,
2399 c1: &Self::Ciphertext,
2400 key: &Self::Key,
2401 ) -> Self::Ciphertext {
2402 let mut out = c0.clone();
2403 self.nand_inplace(&mut out, c1, key);
2404 out
2405 }
2406
2407 fn or(
2408 &mut self,
2409 c0: &Self::Ciphertext,
2410 c1: &Self::Ciphertext,
2411 key: &Self::Key,
2412 ) -> Self::Ciphertext {
2413 let mut out = c0.clone();
2414 self.or_inplace(&mut out, c1, key);
2415 out
2416 }
2417
2418 fn nor(
2419 &mut self,
2420 c0: &Self::Ciphertext,
2421 c1: &Self::Ciphertext,
2422 key: &Self::Key,
2423 ) -> Self::Ciphertext {
2424 let mut out = c0.clone();
2425 self.nor_inplace(&mut out, c1, key);
2426 out
2427 }
2428
2429 fn xnor(
2430 &mut self,
2431 c0: &Self::Ciphertext,
2432 c1: &Self::Ciphertext,
2433 key: &Self::Key,
2434 ) -> Self::Ciphertext {
2435 let mut out = c0.clone();
2436 self.xnor_inplace(&mut out, c1, key);
2437 out
2438 }
2439
2440 fn xor(
2441 &mut self,
2442 c0: &Self::Ciphertext,
2443 c1: &Self::Ciphertext,
2444 key: &Self::Key,
2445 ) -> Self::Ciphertext {
2446 let mut out = c0.clone();
2447 self.xor_inplace(&mut out, c1, key);
2448 out
2449 }
2450
2451 fn not(&mut self, c: &Self::Ciphertext) -> Self::Ciphertext {
2452 let mut out = c.clone();
2453 self.not_inplace(&mut out);
2454 out
2455 }
2456}