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