arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/bool/keys.rs
src/bool/keys.rsRaw
  1use std::{collections::HashMap, hash::Hash, marker::PhantomData};
  2
  3use crate::{
  4    backend::{ModInit, VectorOps},
  5    lwe::LweSecret,
  6    pbs::WithShoupRepr,
  7    random::{NewWithSeed, RandomFillUniformInModulus},
  8    rgsw::RlweSecret,
  9    utils::{ToShoup, WithLocal},
 10    Decryptor, Encryptor, Matrix, MatrixEntity, MatrixMut, MultiPartyDecryptor, RowEntity, RowMut,
 11};
 12
 13use super::{parameters, BoolEvaluator, BoolParameters, CiphertextModulus};
 14
 15/// Client key with RLWE and LWE secrets
 16#[derive(Clone)]
 17pub struct ClientKey {
 18    sk_rlwe: RlweSecret,
 19    sk_lwe: LweSecret,
 20}
 21
 22/// Client key with RLWE and LWE secrets
 23#[derive(Clone)]
 24pub struct NonInteractiveClientKey {
 25    sk_rlwe: RlweSecret,
 26    sk_u_rlwe: RlweSecret,
 27    sk_lwe: LweSecret,
 28}
 29
 30mod impl_ck {
 31    use super::*;
 32
 33    // Client key
 34    impl ClientKey {
 35        pub(in super::super) fn random() -> Self {
 36            let sk_rlwe = RlweSecret::random(0, 0);
 37            let sk_lwe = LweSecret::random(0, 0);
 38            Self { sk_rlwe, sk_lwe }
 39        }
 40
 41        pub(in super::super) fn new(sk_rlwe: RlweSecret, sk_lwe: LweSecret) -> Self {
 42            Self { sk_rlwe, sk_lwe }
 43        }
 44
 45        pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret {
 46            &self.sk_rlwe
 47        }
 48
 49        pub(in super::super) fn sk_lwe(&self) -> &LweSecret {
 50            &self.sk_lwe
 51        }
 52    }
 53
 54    // Client key
 55    impl NonInteractiveClientKey {
 56        pub(in super::super) fn random() -> Self {
 57            let sk_rlwe = RlweSecret::random(0, 0);
 58            let sk_u_rlwe = RlweSecret::random(0, 0);
 59            let sk_lwe = LweSecret::random(0, 0);
 60            Self {
 61                sk_rlwe,
 62                sk_u_rlwe,
 63                sk_lwe,
 64            }
 65        }
 66
 67        pub(in super::super) fn new(
 68            sk_rlwe: RlweSecret,
 69            sk_u_rlwe: RlweSecret,
 70            sk_lwe: LweSecret,
 71        ) -> Self {
 72            Self {
 73                sk_rlwe,
 74                sk_u_rlwe,
 75                sk_lwe,
 76            }
 77        }
 78
 79        pub(in super::super) fn sk_rlwe(&self) -> &RlweSecret {
 80            &self.sk_rlwe
 81        }
 82
 83        pub(in super::super) fn sk_u_rlwe(&self) -> &RlweSecret {
 84            &self.sk_u_rlwe
 85        }
 86
 87        pub(in super::super) fn sk_lwe(&self) -> &LweSecret {
 88            &self.sk_lwe
 89        }
 90    }
 91
 92    impl Encryptor<bool, Vec<u64>> for ClientKey {
 93        fn encrypt(&self, m: &bool) -> Vec<u64> {
 94            BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self))
 95        }
 96    }
 97
 98    impl Decryptor<bool, Vec<u64>> for ClientKey {
 99        fn decrypt(&self, c: &Vec<u64>) -> bool {
100            BoolEvaluator::with_local(|e| e.sk_decrypt(c, self))
101        }
102    }
103
104    impl MultiPartyDecryptor<bool, Vec<u64>> for ClientKey {
105        type DecryptionShare = u64;
106
107        fn gen_decryption_share(&self, c: &Vec<u64>) -> Self::DecryptionShare {
108            BoolEvaluator::with_local(|e| e.multi_party_decryption_share(c, &self))
109        }
110
111        fn aggregate_decryption_shares(
112            &self,
113            c: &Vec<u64>,
114            shares: &[Self::DecryptionShare],
115        ) -> bool {
116            BoolEvaluator::with_local(|e| e.multi_party_decrypt(shares, c))
117        }
118    }
119}
120
121/// Public key
122pub struct PublicKey<M, Rng, ModOp> {
123    key: M,
124    _phantom: PhantomData<(Rng, ModOp)>,
125}
126
127pub(super) mod impl_pk {
128    use super::*;
129
130    impl<M, R, Mo> PublicKey<M, R, Mo> {
131        pub(in super::super) fn key(&self) -> &M {
132            &self.key
133        }
134    }
135
136    impl<Rng, ModOp> Encryptor<bool, Vec<u64>> for PublicKey<Vec<Vec<u64>>, Rng, ModOp> {
137        fn encrypt(&self, m: &bool) -> Vec<u64> {
138            BoolEvaluator::with_local(|e| e.pk_encrypt(&self.key, *m))
139        }
140    }
141
142    impl<Rng, ModOp> Encryptor<[bool], Vec<Vec<u64>>> for PublicKey<Vec<Vec<u64>>, Rng, ModOp> {
143        fn encrypt(&self, m: &[bool]) -> Vec<Vec<u64>> {
144            BoolEvaluator::with_local(|e| e.pk_encrypt_batched(&self.key, m))
145        }
146    }
147
148    impl<
149            M: MatrixMut + MatrixEntity,
150            Rng: NewWithSeed
151                + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
152            ModOp,
153        > From<SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>>
154        for PublicKey<M, Rng, ModOp>
155    where
156        <M as Matrix>::R: RowMut,
157        M::MatElement: Copy,
158    {
159        fn from(
160            value: SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>,
161        ) -> Self {
162            let mut prng = Rng::new_with_seed(value.seed);
163
164            let mut key = M::zeros(2, value.parameters.rlwe_n().0);
165            // sample A
166            RandomFillUniformInModulus::random_fill(
167                &mut prng,
168                value.parameters.rlwe_q(),
169                key.get_row_mut(0),
170            );
171            // Copy over B
172            key.get_row_mut(1).copy_from_slice(value.part_b.as_ref());
173
174            PublicKey {
175                key,
176                _phantom: PhantomData,
177            }
178        }
179    }
180
181    impl<
182            M: MatrixMut + MatrixEntity,
183            Rng: NewWithSeed
184                + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
185            ModOp: VectorOps<Element = M::MatElement> + ModInit<M = CiphertextModulus<M::MatElement>>,
186        >
187        From<
188            &[CommonReferenceSeededCollectivePublicKeyShare<
189                M::R,
190                Rng::Seed,
191                BoolParameters<M::MatElement>,
192            >],
193        > for PublicKey<M, Rng, ModOp>
194    where
195        <M as Matrix>::R: RowMut,
196        Rng::Seed: Copy + PartialEq,
197        M::MatElement: PartialEq + Copy,
198    {
199        fn from(
200            value: &[CommonReferenceSeededCollectivePublicKeyShare<
201                M::R,
202                Rng::Seed,
203                BoolParameters<M::MatElement>,
204            >],
205        ) -> Self {
206            assert!(value.len() > 0);
207
208            let parameters = &value[0].parameters;
209            let mut key = M::zeros(2, parameters.rlwe_n().0);
210
211            // sample A
212            let seed = value[0].cr_seed;
213            let mut main_rng = Rng::new_with_seed(seed);
214            RandomFillUniformInModulus::random_fill(
215                &mut main_rng,
216                parameters.rlwe_q(),
217                key.get_row_mut(0),
218            );
219
220            // Sum all Bs
221            let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
222            value.iter().for_each(|share_i| {
223                assert!(share_i.cr_seed == seed);
224                assert!(&share_i.parameters == parameters);
225
226                rlweq_modop.elwise_add_mut(key.get_row_mut(1), share_i.share.as_ref());
227            });
228
229            PublicKey {
230                key,
231                _phantom: PhantomData,
232            }
233        }
234    }
235}
236
237/// Seeded public key
238struct SeededPublicKey<Ro, S, P, ModOp> {
239    part_b: Ro,
240    seed: S,
241    parameters: P,
242    _phantom: PhantomData<ModOp>,
243}
244
245mod impl_seeded_pk {
246    use super::*;
247
248    impl<R, S, ModOp>
249        From<&[CommonReferenceSeededCollectivePublicKeyShare<R, S, BoolParameters<R::Element>>]>
250        for SeededPublicKey<R, S, BoolParameters<R::Element>, ModOp>
251    where
252        ModOp: VectorOps<Element = R::Element> + ModInit<M = CiphertextModulus<R::Element>>,
253        S: PartialEq + Clone,
254        R: RowMut + RowEntity + Clone,
255        R::Element: Clone + PartialEq,
256    {
257        fn from(
258            value: &[CommonReferenceSeededCollectivePublicKeyShare<
259                R,
260                S,
261                BoolParameters<R::Element>,
262            >],
263        ) -> Self {
264            assert!(value.len() > 0);
265
266            let parameters = &value[0].parameters;
267            let cr_seed = value[0].cr_seed.clone();
268
269            // Sum all Bs
270            let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
271            let mut part_b = value[0].share.clone();
272            value.iter().skip(1).for_each(|share_i| {
273                assert!(&share_i.cr_seed == &cr_seed);
274                assert!(&share_i.parameters == parameters);
275
276                rlweq_modop.elwise_add_mut(part_b.as_mut(), share_i.share.as_ref());
277            });
278
279            Self {
280                part_b,
281                seed: cr_seed,
282                parameters: parameters.clone(),
283                _phantom: PhantomData,
284            }
285        }
286    }
287}
288
289/// CRS seeded collective public key share
290pub struct CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
291    share: Ro,
292    cr_seed: S,
293    parameters: P,
294}
295impl<Ro, S, P> CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
296    pub(super) fn new(share: Ro, cr_seed: S, parameters: P) -> Self {
297        CommonReferenceSeededCollectivePublicKeyShare {
298            share,
299            cr_seed,
300            parameters,
301        }
302    }
303}
304
305/// CRS seeded Multi-party server key share
306pub struct CommonReferenceSeededMultiPartyServerKeyShare<M: Matrix, P, S> {
307    rgsw_cts: Vec<M>,
308    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
309    /// to -g is at 0
310    auto_keys: HashMap<usize, M>,
311    lwe_ksk: M::R,
312    /// Common reference seed
313    cr_seed: S,
314    parameters: P,
315}
316
317impl<M: Matrix, P, S> CommonReferenceSeededMultiPartyServerKeyShare<M, P, S> {
318    pub(super) fn new(
319        rgsw_cts: Vec<M>,
320        auto_keys: HashMap<usize, M>,
321        lwe_ksk: M::R,
322        cr_seed: S,
323        parameters: P,
324    ) -> Self {
325        CommonReferenceSeededMultiPartyServerKeyShare {
326            rgsw_cts,
327            auto_keys,
328            lwe_ksk,
329            cr_seed,
330            parameters,
331        }
332    }
333
334    pub(super) fn cr_seed(&self) -> &S {
335        &self.cr_seed
336    }
337
338    pub(super) fn parameters(&self) -> &P {
339        &self.parameters
340    }
341
342    pub(super) fn auto_keys(&self) -> &HashMap<usize, M> {
343        &self.auto_keys
344    }
345
346    pub(super) fn rgsw_cts(&self) -> &[M] {
347        &self.rgsw_cts
348    }
349
350    pub(super) fn lwe_ksk(&self) -> &M::R {
351        &self.lwe_ksk
352    }
353}
354
355/// CRS seeded MultiParty server key
356pub struct SeededMultiPartyServerKey<M: Matrix, S, P> {
357    rgsw_cts: Vec<M>,
358    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
359    /// to -g is at 0
360    auto_keys: HashMap<usize, M>,
361    lwe_ksk: M::R,
362    cr_seed: S,
363    parameters: P,
364}
365
366impl<M: Matrix, S, P> SeededMultiPartyServerKey<M, S, P> {
367    pub(super) fn new(
368        rgsw_cts: Vec<M>,
369        auto_keys: HashMap<usize, M>,
370        lwe_ksk: M::R,
371        cr_seed: S,
372        parameters: P,
373    ) -> Self {
374        SeededMultiPartyServerKey {
375            rgsw_cts,
376            auto_keys,
377            lwe_ksk,
378            cr_seed,
379            parameters,
380        }
381    }
382
383    pub(super) fn rgsw_cts(&self) -> &[M] {
384        &self.rgsw_cts
385    }
386}
387
388/// Seeded single party server key
389pub struct SeededServerKey<M: Matrix, P, S> {
390    /// Rgsw cts of LWE secret elements
391    pub(crate) rgsw_cts: Vec<M>,
392    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
393    /// to -g is at 0
394    pub(crate) auto_keys: HashMap<usize, M>,
395    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
396    pub(crate) lwe_ksk: M::R,
397    /// Parameters
398    pub(crate) parameters: P,
399    /// Main seed
400    pub(crate) seed: S,
401}
402impl<M: Matrix, S> SeededServerKey<M, BoolParameters<M::MatElement>, S> {
403    pub(super) fn from_raw(
404        auto_keys: HashMap<usize, M>,
405        rgsw_cts: Vec<M>,
406        lwe_ksk: M::R,
407        parameters: BoolParameters<M::MatElement>,
408        seed: S,
409    ) -> Self {
410        // sanity checks
411        auto_keys.iter().for_each(|v| {
412            assert!(
413                v.1.dimension()
414                    == (
415                        parameters.auto_decomposition_count().0,
416                        parameters.rlwe_n().0
417                    )
418            )
419        });
420
421        let (part_a_d, part_b_d) = parameters.rlwe_rgsw_decomposition_count();
422        rgsw_cts.iter().for_each(|v| {
423            assert!(v.dimension() == (part_a_d.0 * 2 + part_b_d.0, parameters.rlwe_n().0))
424        });
425        assert!(
426            lwe_ksk.as_ref().len()
427                == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
428        );
429
430        SeededServerKey {
431            rgsw_cts,
432            auto_keys,
433            lwe_ksk,
434            parameters,
435            seed,
436        }
437    }
438}
439
440/// Server key in evaluation domain
441pub(crate) struct ServerKeyEvaluationDomain<M, P, R, N> {
442    /// Rgsw cts of LWE secret elements
443    rgsw_cts: Vec<M>,
444    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
445    /// to -g is at 0
446    galois_keys: HashMap<usize, M>,
447    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
448    lwe_ksk: M,
449    parameters: P,
450    _phanton: PhantomData<(R, N)>,
451}
452
453pub(super) mod impl_server_key_eval_domain {
454    use itertools::{izip, Itertools};
455
456    use crate::{
457        backend::Modulus,
458        ntt::{Ntt, NttInit},
459        pbs::PbsKey,
460    };
461
462    use super::*;
463
464    impl<M, Mod, R, N> ServerKeyEvaluationDomain<M, Mod, R, N> {
465        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
466            &self.rgsw_cts
467        }
468    }
469
470    impl<
471            M: MatrixMut + MatrixEntity,
472            R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
473                + NewWithSeed,
474            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
475        > From<&SeededServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
476        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
477    where
478        <M as Matrix>::R: RowMut,
479        M::MatElement: Copy,
480        R::Seed: Clone,
481    {
482        fn from(value: &SeededServerKey<M, BoolParameters<M::MatElement>, R::Seed>) -> Self {
483            let mut main_prng = R::new_with_seed(value.seed.clone());
484            let parameters = &value.parameters;
485            let g = parameters.g() as isize;
486            let ring_size = value.parameters.rlwe_n().0;
487            let lwe_n = value.parameters.lwe_n().0;
488            let rlwe_q = value.parameters.rlwe_q();
489            let lwq_q = value.parameters.lwe_q();
490
491            let nttop = N::new(rlwe_q, ring_size);
492
493            // galois keys
494            let mut auto_keys = HashMap::new();
495            let auto_decomp_count = parameters.auto_decomposition_count().0;
496            let auto_element_dlogs = parameters.auto_element_dlogs();
497            for i in auto_element_dlogs.into_iter() {
498                let seeded_auto_key = value.auto_keys.get(&i).unwrap();
499                assert!(seeded_auto_key.dimension() == (auto_decomp_count, ring_size));
500
501                let mut data = M::zeros(auto_decomp_count * 2, ring_size);
502
503                // sample RLWE'_A(-s(X^k))
504                data.iter_rows_mut().take(auto_decomp_count).for_each(|ri| {
505                    RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
506                });
507
508                // copy over RLWE'B_(-s(X^k))
509                izip!(
510                    data.iter_rows_mut().skip(auto_decomp_count),
511                    seeded_auto_key.iter_rows()
512                )
513                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
514
515                // Send to Evaluation domain
516                data.iter_rows_mut()
517                    .for_each(|ri| nttop.forward(ri.as_mut()));
518
519                auto_keys.insert(i, data);
520            }
521
522            // RGSW ciphertexts
523            let (rlrg_a_decomp, rlrg_b_decomp) = parameters.rlwe_rgsw_decomposition_count();
524            let rgsw_cts = value
525                .rgsw_cts
526                .iter()
527                .map(|seeded_rgsw_si| {
528                    assert!(
529                        seeded_rgsw_si.dimension()
530                            == (rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0, ring_size)
531                    );
532
533                    let mut data = M::zeros(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0 * 2, ring_size);
534
535                    // copy over RLWE'(-sm)
536                    izip!(
537                        data.iter_rows_mut().take(rlrg_a_decomp.0 * 2),
538                        seeded_rgsw_si.iter_rows().take(rlrg_a_decomp.0 * 2)
539                    )
540                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
541
542                    // sample RLWE'_A(m)
543                    data.iter_rows_mut()
544                        .skip(rlrg_a_decomp.0 * 2)
545                        .take(rlrg_b_decomp.0)
546                        .for_each(|ri| {
547                            RandomFillUniformInModulus::random_fill(
548                                &mut main_prng,
549                                &rlwe_q,
550                                ri.as_mut(),
551                            )
552                        });
553
554                    // copy over RLWE'_B(m)
555                    izip!(
556                        data.iter_rows_mut()
557                            .skip(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0),
558                        seeded_rgsw_si.iter_rows().skip(rlrg_a_decomp.0 * 2)
559                    )
560                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
561
562                    // send polynomials to evaluation domain
563                    data.iter_rows_mut()
564                        .for_each(|ri| nttop.forward(ri.as_mut()));
565
566                    data
567                })
568                .collect_vec();
569
570            // LWE ksk
571            let lwe_ksk = {
572                let d = parameters.lwe_decomposition_count().0;
573                assert!(value.lwe_ksk.as_ref().len() == d * ring_size);
574
575                let mut data = M::zeros(d * ring_size, lwe_n + 1);
576                izip!(data.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
577                    |(lwe_i, bi)| {
578                        RandomFillUniformInModulus::random_fill(
579                            &mut main_prng,
580                            &lwq_q,
581                            &mut lwe_i.as_mut()[1..],
582                        );
583                        lwe_i.as_mut()[0] = *bi;
584                    },
585                );
586
587                data
588            };
589
590            ServerKeyEvaluationDomain {
591                rgsw_cts,
592                galois_keys: auto_keys,
593                lwe_ksk,
594                parameters: parameters.clone(),
595                _phanton: PhantomData,
596            }
597        }
598    }
599
600    impl<
601            M: MatrixMut + MatrixEntity,
602            Rng: NewWithSeed,
603            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
604        > From<&SeededMultiPartyServerKey<M, Rng::Seed, BoolParameters<M::MatElement>>>
605        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
606    where
607        <M as Matrix>::R: RowMut,
608        Rng::Seed: Copy,
609        Rng: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
610        M::MatElement: Copy,
611    {
612        fn from(
613            value: &SeededMultiPartyServerKey<M, Rng::Seed, BoolParameters<M::MatElement>>,
614        ) -> Self {
615            let g = value.parameters.g() as isize;
616            let rlwe_n = value.parameters.rlwe_n().0;
617            let lwe_n = value.parameters.lwe_n().0;
618            let rlwe_q = value.parameters.rlwe_q();
619            let lwe_q = value.parameters.lwe_q();
620
621            let mut main_prng = Rng::new_with_seed(value.cr_seed);
622
623            let rlwe_nttop = N::new(rlwe_q, rlwe_n);
624
625            // auto keys
626            let mut auto_keys = HashMap::new();
627            let auto_d_count = value.parameters.auto_decomposition_count().0;
628            let auto_element_dlogs = value.parameters.auto_element_dlogs();
629            for i in auto_element_dlogs.into_iter() {
630                let mut key = M::zeros(auto_d_count * 2, rlwe_n);
631
632                // sample a
633                key.iter_rows_mut().take(auto_d_count).for_each(|ri| {
634                    RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
635                });
636
637                let key_part_b = value.auto_keys.get(&i).unwrap();
638                assert!(key_part_b.dimension() == (auto_d_count, rlwe_n));
639                izip!(
640                    key.iter_rows_mut().skip(auto_d_count),
641                    key_part_b.iter_rows()
642                )
643                .for_each(|(to_ri, from_ri)| {
644                    to_ri.as_mut().copy_from_slice(from_ri.as_ref());
645                });
646
647                // send to evaluation domain
648                key.iter_rows_mut()
649                    .for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
650
651                auto_keys.insert(i, key);
652            }
653
654            // rgsw cts
655            let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
656            let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
657            let rgsw_cts = value
658                .rgsw_cts
659                .iter()
660                .map(|ct_i_in| {
661                    assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
662                    let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
663
664                    izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
665                        |(to_ri, from_ri)| {
666                            to_ri.as_mut().copy_from_slice(from_ri.as_ref());
667                            rlwe_nttop.forward(to_ri.as_mut());
668                        },
669                    );
670
671                    eval_ct_i_out
672                })
673                .collect_vec();
674
675            // lwe ksk
676            let d_lwe = value.parameters.lwe_decomposition_count().0;
677            let mut lwe_ksk = M::zeros(rlwe_n * d_lwe, lwe_n + 1);
678            izip!(lwe_ksk.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
679                |(lwe_i, bi)| {
680                    RandomFillUniformInModulus::random_fill(
681                        &mut main_prng,
682                        &lwe_q,
683                        &mut lwe_i.as_mut()[1..],
684                    );
685                    lwe_i.as_mut()[0] = *bi;
686                },
687            );
688
689            ServerKeyEvaluationDomain {
690                rgsw_cts,
691                galois_keys: auto_keys,
692                lwe_ksk,
693                parameters: value.parameters.clone(),
694                _phanton: PhantomData,
695            }
696        }
697    }
698
699    impl<M: Matrix, P, R, N> PbsKey for ServerKeyEvaluationDomain<M, P, R, N> {
700        type AutoKey = M;
701        type LweKskKey = M;
702        type RgswCt = M;
703
704        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
705            self.galois_keys.get(&k).unwrap()
706        }
707        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
708            &self.rgsw_cts[si]
709        }
710
711        fn lwe_ksk(&self) -> &Self::LweKskKey {
712            &self.lwe_ksk
713        }
714    }
715}
716
717/// Server key in evaluation domain
718pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
719    /// Rgsw cts of LWE secret elements
720    rgsw_cts: Vec<NormalAndShoup<M>>,
721    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
722    /// to -g is at 0
723    galois_keys: HashMap<usize, NormalAndShoup<M>>,
724    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
725    lwe_ksk: M,
726}
727
728/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
729pub(crate) struct NormalAndShoup<M>(M, M);
730
731impl<M: ToShoup> NormalAndShoup<M> {
732    fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
733        let value_shoup = M::to_shoup(&value, modulus);
734        NormalAndShoup(value, value_shoup)
735    }
736}
737
738impl<M> AsRef<M> for NormalAndShoup<M> {
739    fn as_ref(&self) -> &M {
740        &self.0
741    }
742}
743
744impl<M> WithShoupRepr for NormalAndShoup<M> {
745    type M = M;
746    fn shoup_repr(&self) -> &Self::M {
747        &self.1
748    }
749}
750
751mod shoup_server_key_eval_domain {
752    use itertools::{izip, Itertools};
753    use num_traits::{FromPrimitive, PrimInt};
754
755    use crate::{backend::Modulus, pbs::PbsKey};
756
757    use super::*;
758
759    impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
760        From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
761        for ShoupServerKeyEvaluationDomain<M>
762    where
763        <M as Matrix>::R: RowMut,
764        M::MatElement: PrimInt + FromPrimitive,
765    {
766        fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
767            let q = value.parameters.rlwe_q().q().unwrap();
768            // Rgsw ciphertexts
769            let rgsw_cts = value
770                .rgsw_cts
771                .into_iter()
772                .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
773                .collect_vec();
774
775            let mut auto_keys = HashMap::new();
776            value.galois_keys.into_iter().for_each(|(index, key)| {
777                auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
778            });
779
780            Self {
781                rgsw_cts,
782                galois_keys: auto_keys,
783                lwe_ksk: value.lwe_ksk,
784            }
785        }
786    }
787
788    impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
789        type AutoKey = NormalAndShoup<M>;
790        type LweKskKey = M;
791        type RgswCt = NormalAndShoup<M>;
792
793        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
794            self.galois_keys.get(&k).unwrap()
795        }
796        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
797            &self.rgsw_cts[si]
798        }
799
800        fn lwe_ksk(&self) -> &Self::LweKskKey {
801            &self.lwe_ksk
802        }
803    }
804}