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::{
  14    evaluator::BoolEvaluator,
  15    parameters::{BoolParameters, CiphertextModulus},
  16};
  17
  18pub(crate) trait SinglePartyClientKey {
  19    type Element;
  20    fn sk_rlwe(&self) -> Vec<Self::Element>;
  21    fn sk_lwe(&self) -> Vec<Self::Element>;
  22}
  23
  24pub(crate) trait InteractiveMultiPartyClientKey {
  25    type Element;
  26    fn sk_rlwe(&self) -> Vec<Self::Element>;
  27    fn sk_lwe(&self) -> Vec<Self::Element>;
  28}
  29
  30pub(crate) trait NonInteractiveMultiPartyClientKey {
  31    type Element;
  32    fn sk_rlwe(&self) -> Vec<Self::Element>;
  33    fn sk_u_rlwe(&self) -> Vec<Self::Element>;
  34    fn sk_lwe(&self) -> Vec<Self::Element>;
  35}
  36
  37/// Client key
  38///
  39/// Key is used for all parameter varians - Single party, interactive
  40/// multi-party, and non-interactive multi-party. The only stored the main seed
  41/// and seeds of the Rlwe/Lwe secrets are derived at puncturing the seed desired
  42/// number of times.
  43///
  44/// ### Punctures required:
  45///
  46///     Puncture 1 -> Seed of RLWE secret used as main RLWE secret for
  47///                   single-party, interactive/non-interactive multi-party
  48///
  49///     Puncture 2 -> Seed of LWE secret used main LWE secret for single-party,
  50///                   interactive/non-interactive multi-party
  51///
  52///     Puncture 3 -> Seed of RLWE secret used as `u` in
  53///                   interactive/non-interactive multi-party.
  54#[derive(Clone)]
  55pub struct ClientKey<S, E> {
  56    seed: S,
  57    parameters: BoolParameters<E>,
  58}
  59
  60mod impl_ck {
  61    use crate::{
  62        random::DefaultSecureRng,
  63        utils::{fill_random_ternary_secret_with_hamming_weight, puncture_p_rng},
  64    };
  65
  66    use super::*;
  67
  68    impl<E> ClientKey<[u8; 32], E> {
  69        pub(in super::super) fn new(parameters: BoolParameters<E>) -> ClientKey<[u8; 32], E> {
  70            let mut rng = DefaultSecureRng::new();
  71            let mut seed = [0u8; 32];
  72            rng.fill_bytes(&mut seed);
  73            Self { seed, parameters }
  74        }
  75    }
  76
  77    impl<E> SinglePartyClientKey for ClientKey<[u8; 32], E> {
  78        type Element = i32;
  79        fn sk_lwe(&self) -> Vec<Self::Element> {
  80            let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
  81            let lwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 2);
  82
  83            let mut lwe_prng = DefaultSecureRng::new_seeded(lwe_seed);
  84            let mut out = vec![0i32; self.parameters.lwe_n().0];
  85            fill_random_ternary_secret_with_hamming_weight(
  86                &mut out,
  87                self.parameters.lwe_n().0 >> 1,
  88                &mut lwe_prng,
  89            );
  90            out
  91        }
  92        fn sk_rlwe(&self) -> Vec<Self::Element> {
  93            let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
  94            let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 1);
  95
  96            let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
  97            let mut out = vec![0i32; self.parameters.rlwe_n().0];
  98            fill_random_ternary_secret_with_hamming_weight(
  99                &mut out,
 100                self.parameters.rlwe_n().0 >> 1,
 101                &mut rlwe_prng,
 102            );
 103            out
 104        }
 105    }
 106
 107    impl<E> InteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
 108        type Element = i32;
 109        fn sk_lwe(&self) -> Vec<Self::Element> {
 110            <Self as SinglePartyClientKey>::sk_lwe(&self)
 111        }
 112        fn sk_rlwe(&self) -> Vec<Self::Element> {
 113            <Self as SinglePartyClientKey>::sk_rlwe(&self)
 114        }
 115    }
 116
 117    impl<E> NonInteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
 118        type Element = i32;
 119        fn sk_lwe(&self) -> Vec<Self::Element> {
 120            <Self as SinglePartyClientKey>::sk_lwe(&self)
 121        }
 122        fn sk_rlwe(&self) -> Vec<Self::Element> {
 123            <Self as SinglePartyClientKey>::sk_rlwe(&self)
 124        }
 125        fn sk_u_rlwe(&self) -> Vec<Self::Element> {
 126            let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
 127            let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 3);
 128
 129            let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
 130            let mut out = vec![0i32; self.parameters.rlwe_n().0];
 131            fill_random_ternary_secret_with_hamming_weight(
 132                &mut out,
 133                self.parameters.rlwe_n().0 >> 1,
 134                &mut rlwe_prng,
 135            );
 136            out
 137        }
 138    }
 139}
 140
 141/// Public key
 142pub struct PublicKey<M, Rng, ModOp> {
 143    key: M,
 144    _phantom: PhantomData<(Rng, ModOp)>,
 145}
 146
 147pub(super) mod impl_pk {
 148    use super::*;
 149
 150    impl<M, R, Mo> PublicKey<M, R, Mo> {
 151        pub(in super::super) fn key(&self) -> &M {
 152            &self.key
 153        }
 154    }
 155
 156    impl<
 157            M: MatrixMut + MatrixEntity,
 158            Rng: NewWithSeed
 159                + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
 160            ModOp,
 161        > From<SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>>
 162        for PublicKey<M, Rng, ModOp>
 163    where
 164        <M as Matrix>::R: RowMut,
 165        M::MatElement: Copy,
 166    {
 167        fn from(
 168            value: SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>,
 169        ) -> Self {
 170            let mut prng = Rng::new_with_seed(value.seed);
 171
 172            let mut key = M::zeros(2, value.parameters.rlwe_n().0);
 173            // sample A
 174            RandomFillUniformInModulus::random_fill(
 175                &mut prng,
 176                value.parameters.rlwe_q(),
 177                key.get_row_mut(0),
 178            );
 179            // Copy over B
 180            key.get_row_mut(1).copy_from_slice(value.part_b.as_ref());
 181
 182            PublicKey {
 183                key,
 184                _phantom: PhantomData,
 185            }
 186        }
 187    }
 188
 189    impl<
 190            M: MatrixMut + MatrixEntity,
 191            Rng: NewWithSeed
 192                + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
 193            ModOp: VectorOps<Element = M::MatElement> + ModInit<M = CiphertextModulus<M::MatElement>>,
 194        >
 195        From<
 196            &[CommonReferenceSeededCollectivePublicKeyShare<
 197                M::R,
 198                Rng::Seed,
 199                BoolParameters<M::MatElement>,
 200            >],
 201        > for PublicKey<M, Rng, ModOp>
 202    where
 203        <M as Matrix>::R: RowMut,
 204        Rng::Seed: Copy + PartialEq,
 205        M::MatElement: PartialEq + Copy,
 206    {
 207        fn from(
 208            value: &[CommonReferenceSeededCollectivePublicKeyShare<
 209                M::R,
 210                Rng::Seed,
 211                BoolParameters<M::MatElement>,
 212            >],
 213        ) -> Self {
 214            assert!(value.len() > 0);
 215
 216            let parameters = &value[0].parameters;
 217            let mut key = M::zeros(2, parameters.rlwe_n().0);
 218
 219            // sample A
 220            let seed = value[0].cr_seed;
 221            let mut main_rng = Rng::new_with_seed(seed);
 222            RandomFillUniformInModulus::random_fill(
 223                &mut main_rng,
 224                parameters.rlwe_q(),
 225                key.get_row_mut(0),
 226            );
 227
 228            // Sum all Bs
 229            let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
 230            value.iter().for_each(|share_i| {
 231                assert!(share_i.cr_seed == seed);
 232                assert!(&share_i.parameters == parameters);
 233
 234                rlweq_modop.elwise_add_mut(key.get_row_mut(1), share_i.share.as_ref());
 235            });
 236
 237            PublicKey {
 238                key,
 239                _phantom: PhantomData,
 240            }
 241        }
 242    }
 243}
 244
 245/// Seeded public key
 246struct SeededPublicKey<Ro, S, P, ModOp> {
 247    part_b: Ro,
 248    seed: S,
 249    parameters: P,
 250    _phantom: PhantomData<ModOp>,
 251}
 252
 253mod impl_seeded_pk {
 254    use super::*;
 255
 256    impl<R, S, ModOp>
 257        From<&[CommonReferenceSeededCollectivePublicKeyShare<R, S, BoolParameters<R::Element>>]>
 258        for SeededPublicKey<R, S, BoolParameters<R::Element>, ModOp>
 259    where
 260        ModOp: VectorOps<Element = R::Element> + ModInit<M = CiphertextModulus<R::Element>>,
 261        S: PartialEq + Clone,
 262        R: RowMut + RowEntity + Clone,
 263        R::Element: Clone + PartialEq,
 264    {
 265        fn from(
 266            value: &[CommonReferenceSeededCollectivePublicKeyShare<
 267                R,
 268                S,
 269                BoolParameters<R::Element>,
 270            >],
 271        ) -> Self {
 272            assert!(value.len() > 0);
 273
 274            let parameters = &value[0].parameters;
 275            let cr_seed = value[0].cr_seed.clone();
 276
 277            // Sum all Bs
 278            let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
 279            let mut part_b = value[0].share.clone();
 280            value.iter().skip(1).for_each(|share_i| {
 281                assert!(&share_i.cr_seed == &cr_seed);
 282                assert!(&share_i.parameters == parameters);
 283
 284                rlweq_modop.elwise_add_mut(part_b.as_mut(), share_i.share.as_ref());
 285            });
 286
 287            Self {
 288                part_b,
 289                seed: cr_seed,
 290                parameters: parameters.clone(),
 291                _phantom: PhantomData,
 292            }
 293        }
 294    }
 295}
 296
 297/// CRS seeded collective public key share
 298pub struct CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
 299    share: Ro,
 300    cr_seed: S,
 301    parameters: P,
 302}
 303impl<Ro, S, P> CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
 304    pub(super) fn new(share: Ro, cr_seed: S, parameters: P) -> Self {
 305        CommonReferenceSeededCollectivePublicKeyShare {
 306            share,
 307            cr_seed,
 308            parameters,
 309        }
 310    }
 311}
 312
 313/// CRS seeded Multi-party server key share
 314pub struct CommonReferenceSeededMultiPartyServerKeyShare<M: Matrix, P, S> {
 315    rgsw_cts: Vec<M>,
 316    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 317    /// to -g is at 0
 318    auto_keys: HashMap<usize, M>,
 319    lwe_ksk: M::R,
 320    /// Common reference seed
 321    cr_seed: S,
 322    parameters: P,
 323}
 324
 325impl<M: Matrix, P, S> CommonReferenceSeededMultiPartyServerKeyShare<M, P, S> {
 326    pub(super) fn new(
 327        rgsw_cts: Vec<M>,
 328        auto_keys: HashMap<usize, M>,
 329        lwe_ksk: M::R,
 330        cr_seed: S,
 331        parameters: P,
 332    ) -> Self {
 333        CommonReferenceSeededMultiPartyServerKeyShare {
 334            rgsw_cts,
 335            auto_keys,
 336            lwe_ksk,
 337            cr_seed,
 338            parameters,
 339        }
 340    }
 341
 342    pub(super) fn cr_seed(&self) -> &S {
 343        &self.cr_seed
 344    }
 345
 346    pub(super) fn parameters(&self) -> &P {
 347        &self.parameters
 348    }
 349
 350    pub(super) fn auto_keys(&self) -> &HashMap<usize, M> {
 351        &self.auto_keys
 352    }
 353
 354    pub(super) fn rgsw_cts(&self) -> &[M] {
 355        &self.rgsw_cts
 356    }
 357
 358    pub(super) fn lwe_ksk(&self) -> &M::R {
 359        &self.lwe_ksk
 360    }
 361}
 362
 363/// CRS seeded MultiParty server key
 364pub struct SeededMultiPartyServerKey<M: Matrix, S, P> {
 365    rgsw_cts: Vec<M>,
 366    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 367    /// to -g is at 0
 368    auto_keys: HashMap<usize, M>,
 369    lwe_ksk: M::R,
 370    cr_seed: S,
 371    parameters: P,
 372}
 373
 374impl<M: Matrix, S, P> SeededMultiPartyServerKey<M, S, P> {
 375    pub(super) fn new(
 376        rgsw_cts: Vec<M>,
 377        auto_keys: HashMap<usize, M>,
 378        lwe_ksk: M::R,
 379        cr_seed: S,
 380        parameters: P,
 381    ) -> Self {
 382        SeededMultiPartyServerKey {
 383            rgsw_cts,
 384            auto_keys,
 385            lwe_ksk,
 386            cr_seed,
 387            parameters,
 388        }
 389    }
 390
 391    pub(super) fn rgsw_cts(&self) -> &[M] {
 392        &self.rgsw_cts
 393    }
 394}
 395
 396/// Seeded single party server key
 397pub struct SeededSinglePartyServerKey<M: Matrix, P, S> {
 398    /// Rgsw cts of LWE secret elements
 399    pub(crate) rgsw_cts: Vec<M>,
 400    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 401    /// to -g is at 0
 402    pub(crate) auto_keys: HashMap<usize, M>,
 403    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
 404    pub(crate) lwe_ksk: M::R,
 405    /// Parameters
 406    pub(crate) parameters: P,
 407    /// Main seed
 408    pub(crate) seed: S,
 409}
 410impl<M: Matrix, S> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, S> {
 411    pub(super) fn from_raw(
 412        auto_keys: HashMap<usize, M>,
 413        rgsw_cts: Vec<M>,
 414        lwe_ksk: M::R,
 415        parameters: BoolParameters<M::MatElement>,
 416        seed: S,
 417    ) -> Self {
 418        // sanity checks
 419        auto_keys.iter().for_each(|v| {
 420            assert!(
 421                v.1.dimension()
 422                    == (
 423                        parameters.auto_decomposition_count().0,
 424                        parameters.rlwe_n().0
 425                    )
 426            )
 427        });
 428
 429        let (part_a_d, part_b_d) = parameters.rlwe_rgsw_decomposition_count();
 430        rgsw_cts.iter().for_each(|v| {
 431            assert!(v.dimension() == (part_a_d.0 * 2 + part_b_d.0, parameters.rlwe_n().0))
 432        });
 433        assert!(
 434            lwe_ksk.as_ref().len()
 435                == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
 436        );
 437
 438        SeededSinglePartyServerKey {
 439            rgsw_cts,
 440            auto_keys,
 441            lwe_ksk,
 442            parameters,
 443            seed,
 444        }
 445    }
 446}
 447
 448/// Server key in evaluation domain
 449pub(crate) struct ServerKeyEvaluationDomain<M, P, R, N> {
 450    /// Rgsw cts of LWE secret elements
 451    rgsw_cts: Vec<M>,
 452    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 453    /// to -g is at 0
 454    galois_keys: HashMap<usize, M>,
 455    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
 456    lwe_ksk: M,
 457    parameters: P,
 458    _phanton: PhantomData<(R, N)>,
 459}
 460
 461pub(super) mod impl_server_key_eval_domain {
 462    use itertools::{izip, Itertools};
 463
 464    use crate::{
 465        ntt::{Ntt, NttInit},
 466        pbs::PbsKey,
 467    };
 468
 469    use super::*;
 470
 471    impl<M, Mod, R, N> ServerKeyEvaluationDomain<M, Mod, R, N> {
 472        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 473            &self.rgsw_cts
 474        }
 475    }
 476
 477    impl<
 478            M: MatrixMut + MatrixEntity,
 479            R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 480                + NewWithSeed,
 481            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
 482        > From<&SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
 483        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
 484    where
 485        <M as Matrix>::R: RowMut,
 486        M::MatElement: Copy,
 487        R::Seed: Clone,
 488    {
 489        fn from(
 490            value: &SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>,
 491        ) -> Self {
 492            let mut main_prng = R::new_with_seed(value.seed.clone());
 493            let parameters = &value.parameters;
 494            let g = parameters.g() as isize;
 495            let ring_size = value.parameters.rlwe_n().0;
 496            let lwe_n = value.parameters.lwe_n().0;
 497            let rlwe_q = value.parameters.rlwe_q();
 498            let lwq_q = value.parameters.lwe_q();
 499
 500            let nttop = N::new(rlwe_q, ring_size);
 501
 502            // galois keys
 503            let mut auto_keys = HashMap::new();
 504            let auto_decomp_count = parameters.auto_decomposition_count().0;
 505            let auto_element_dlogs = parameters.auto_element_dlogs();
 506            for i in auto_element_dlogs.into_iter() {
 507                let seeded_auto_key = value.auto_keys.get(&i).unwrap();
 508                assert!(seeded_auto_key.dimension() == (auto_decomp_count, ring_size));
 509
 510                let mut data = M::zeros(auto_decomp_count * 2, ring_size);
 511
 512                // sample RLWE'_A(-s(X^k))
 513                data.iter_rows_mut().take(auto_decomp_count).for_each(|ri| {
 514                    RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
 515                });
 516
 517                // copy over RLWE'B_(-s(X^k))
 518                izip!(
 519                    data.iter_rows_mut().skip(auto_decomp_count),
 520                    seeded_auto_key.iter_rows()
 521                )
 522                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 523
 524                // Send to Evaluation domain
 525                data.iter_rows_mut()
 526                    .for_each(|ri| nttop.forward(ri.as_mut()));
 527
 528                auto_keys.insert(i, data);
 529            }
 530
 531            // RGSW ciphertexts
 532            let (rlrg_a_decomp, rlrg_b_decomp) = parameters.rlwe_rgsw_decomposition_count();
 533            let rgsw_cts = value
 534                .rgsw_cts
 535                .iter()
 536                .map(|seeded_rgsw_si| {
 537                    assert!(
 538                        seeded_rgsw_si.dimension()
 539                            == (rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0, ring_size)
 540                    );
 541
 542                    let mut data = M::zeros(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0 * 2, ring_size);
 543
 544                    // copy over RLWE'(-sm)
 545                    izip!(
 546                        data.iter_rows_mut().take(rlrg_a_decomp.0 * 2),
 547                        seeded_rgsw_si.iter_rows().take(rlrg_a_decomp.0 * 2)
 548                    )
 549                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 550
 551                    // sample RLWE'_A(m)
 552                    data.iter_rows_mut()
 553                        .skip(rlrg_a_decomp.0 * 2)
 554                        .take(rlrg_b_decomp.0)
 555                        .for_each(|ri| {
 556                            RandomFillUniformInModulus::random_fill(
 557                                &mut main_prng,
 558                                &rlwe_q,
 559                                ri.as_mut(),
 560                            )
 561                        });
 562
 563                    // copy over RLWE'_B(m)
 564                    izip!(
 565                        data.iter_rows_mut()
 566                            .skip(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0),
 567                        seeded_rgsw_si.iter_rows().skip(rlrg_a_decomp.0 * 2)
 568                    )
 569                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 570
 571                    // send polynomials to evaluation domain
 572                    data.iter_rows_mut()
 573                        .for_each(|ri| nttop.forward(ri.as_mut()));
 574
 575                    data
 576                })
 577                .collect_vec();
 578
 579            // LWE ksk
 580            let lwe_ksk = {
 581                let d = parameters.lwe_decomposition_count().0;
 582                assert!(value.lwe_ksk.as_ref().len() == d * ring_size);
 583
 584                let mut data = M::zeros(d * ring_size, lwe_n + 1);
 585                izip!(data.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
 586                    |(lwe_i, bi)| {
 587                        RandomFillUniformInModulus::random_fill(
 588                            &mut main_prng,
 589                            &lwq_q,
 590                            &mut lwe_i.as_mut()[1..],
 591                        );
 592                        lwe_i.as_mut()[0] = *bi;
 593                    },
 594                );
 595
 596                data
 597            };
 598
 599            ServerKeyEvaluationDomain {
 600                rgsw_cts,
 601                galois_keys: auto_keys,
 602                lwe_ksk,
 603                parameters: parameters.clone(),
 604                _phanton: PhantomData,
 605            }
 606        }
 607    }
 608
 609    impl<
 610            M: MatrixMut + MatrixEntity,
 611            Rng: NewWithSeed,
 612            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
 613        > From<&SeededMultiPartyServerKey<M, Rng::Seed, BoolParameters<M::MatElement>>>
 614        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 615    where
 616        <M as Matrix>::R: RowMut,
 617        Rng::Seed: Copy,
 618        Rng: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
 619        M::MatElement: Copy,
 620    {
 621        fn from(
 622            value: &SeededMultiPartyServerKey<M, Rng::Seed, BoolParameters<M::MatElement>>,
 623        ) -> Self {
 624            let g = value.parameters.g() as isize;
 625            let rlwe_n = value.parameters.rlwe_n().0;
 626            let lwe_n = value.parameters.lwe_n().0;
 627            let rlwe_q = value.parameters.rlwe_q();
 628            let lwe_q = value.parameters.lwe_q();
 629
 630            let mut main_prng = Rng::new_with_seed(value.cr_seed);
 631
 632            let rlwe_nttop = N::new(rlwe_q, rlwe_n);
 633
 634            // auto keys
 635            let mut auto_keys = HashMap::new();
 636            let auto_d_count = value.parameters.auto_decomposition_count().0;
 637            let auto_element_dlogs = value.parameters.auto_element_dlogs();
 638            for i in auto_element_dlogs.into_iter() {
 639                let mut key = M::zeros(auto_d_count * 2, rlwe_n);
 640
 641                // sample a
 642                key.iter_rows_mut().take(auto_d_count).for_each(|ri| {
 643                    RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
 644                });
 645
 646                let key_part_b = value.auto_keys.get(&i).unwrap();
 647                assert!(key_part_b.dimension() == (auto_d_count, rlwe_n));
 648                izip!(
 649                    key.iter_rows_mut().skip(auto_d_count),
 650                    key_part_b.iter_rows()
 651                )
 652                .for_each(|(to_ri, from_ri)| {
 653                    to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 654                });
 655
 656                // send to evaluation domain
 657                key.iter_rows_mut()
 658                    .for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
 659
 660                auto_keys.insert(i, key);
 661            }
 662
 663            // rgsw cts
 664            let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
 665            let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
 666            let rgsw_cts = value
 667                .rgsw_cts
 668                .iter()
 669                .map(|ct_i_in| {
 670                    assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
 671                    let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
 672
 673                    izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
 674                        |(to_ri, from_ri)| {
 675                            to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 676                            rlwe_nttop.forward(to_ri.as_mut());
 677                        },
 678                    );
 679
 680                    eval_ct_i_out
 681                })
 682                .collect_vec();
 683
 684            // lwe ksk
 685            let d_lwe = value.parameters.lwe_decomposition_count().0;
 686            let mut lwe_ksk = M::zeros(rlwe_n * d_lwe, lwe_n + 1);
 687            izip!(lwe_ksk.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
 688                |(lwe_i, bi)| {
 689                    RandomFillUniformInModulus::random_fill(
 690                        &mut main_prng,
 691                        &lwe_q,
 692                        &mut lwe_i.as_mut()[1..],
 693                    );
 694                    lwe_i.as_mut()[0] = *bi;
 695                },
 696            );
 697
 698            ServerKeyEvaluationDomain {
 699                rgsw_cts,
 700                galois_keys: auto_keys,
 701                lwe_ksk,
 702                parameters: value.parameters.clone(),
 703                _phanton: PhantomData,
 704            }
 705        }
 706    }
 707
 708    impl<M: Matrix, P, R, N> PbsKey for ServerKeyEvaluationDomain<M, P, R, N> {
 709        type AutoKey = M;
 710        type LweKskKey = M;
 711        type RgswCt = M;
 712
 713        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
 714            self.galois_keys.get(&k).unwrap()
 715        }
 716        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
 717            &self.rgsw_cts[si]
 718        }
 719
 720        fn lwe_ksk(&self) -> &Self::LweKskKey {
 721            &self.lwe_ksk
 722        }
 723    }
 724}
 725
 726pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 727    /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
 728    rgsw_cts: Vec<M>,
 729    /// Automorphism keys under ideal rlwe secret
 730    auto_keys: HashMap<usize, M>,
 731    /// LWE key switching key from Q -> Q_{ks}
 732    lwe_ksk: M,
 733    /// Key switching key from user j to ideal secret key s. User j's ksk is at
 734    /// j'th element
 735    ui_to_s_ksks: Vec<M>,
 736    parameters: P,
 737    _phanton: PhantomData<(R, N)>,
 738}
 739
 740pub(super) mod impl_non_interactive_server_key_eval_domain {
 741    use itertools::{izip, Itertools};
 742
 743    use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
 744
 745    use super::*;
 746
 747    impl<M, P, R, N> NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 748        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 749            &self.rgsw_cts
 750        }
 751    }
 752
 753    impl<M, Rng, N>
 754        From<
 755            SeededNonInteractiveMultiPartyServerKey<
 756                M,
 757                NonInteractiveMultiPartyCrs<Rng::Seed>,
 758                BoolParameters<M::MatElement>,
 759            >,
 760        > for NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 761    where
 762        M: MatrixMut + MatrixEntity + Clone,
 763        Rng: NewWithSeed
 764            + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 765            + RandomFill<<Rng as NewWithSeed>::Seed>,
 766        N: Ntt<Element = M::MatElement> + NttInit<CiphertextModulus<M::MatElement>>,
 767        M::R: RowMut,
 768        M::MatElement: Copy,
 769        Rng::Seed: Clone + Copy + Default,
 770    {
 771        fn from(
 772            value: SeededNonInteractiveMultiPartyServerKey<
 773                M,
 774                NonInteractiveMultiPartyCrs<Rng::Seed>,
 775                BoolParameters<M::MatElement>,
 776            >,
 777        ) -> Self {
 778            let rlwe_nttop = N::new(value.parameters.rlwe_q(), value.parameters.rlwe_n().0);
 779            let ring_size = value.parameters.rlwe_n().0;
 780
 781            // RGSW cts
 782            // copy over rgsw cts and send to evaluation domain
 783            let mut rgsw_cts = value.rgsw_cts.clone();
 784            rgsw_cts.iter_mut().for_each(|c| {
 785                c.iter_rows_mut()
 786                    .for_each(|ri| rlwe_nttop.forward(ri.as_mut()))
 787            });
 788
 789            // Auto keys
 790            // populate pseudo random part of auto keys. Then send auto keys to
 791            // evaluation domain
 792            let mut auto_keys = HashMap::new();
 793            let auto_seed = value.cr_seed.auto_keys_cts_seed::<Rng>();
 794            let mut auto_prng = Rng::new_with_seed(auto_seed);
 795            let auto_element_dlogs = value.parameters.auto_element_dlogs();
 796            let d_auto = value.parameters.auto_decomposition_count().0;
 797            auto_element_dlogs.iter().for_each(|el| {
 798                let auto_part_b = value
 799                    .auto_keys
 800                    .get(el)
 801                    .expect(&format!("Auto key for element g^{el} not found"));
 802
 803                assert!(auto_part_b.dimension() == (d_auto, ring_size));
 804
 805                let mut auto_ct = M::zeros(d_auto, ring_size);
 806
 807                // sample part A
 808                auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
 809                    RandomFillUniformInModulus::random_fill(
 810                        &mut auto_prng,
 811                        value.parameters.rlwe_q(),
 812                        ri.as_mut(),
 813                    )
 814                });
 815
 816                // Copy over part B
 817                izip!(
 818                    auto_ct.iter_rows_mut().skip(d_auto),
 819                    auto_part_b.iter_rows()
 820                )
 821                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 822
 823                // send to evaluation domain
 824                auto_ct
 825                    .iter_rows_mut()
 826                    .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 827
 828                auto_keys.insert(*el, auto_ct);
 829            });
 830
 831            // LWE ksk
 832            // populate pseudo random part of lwe ciphertexts in ksk and copy over part b
 833            // elements
 834            let lwe_ksk_seed = value.cr_seed.lwe_ksk_cts_seed::<Rng>();
 835            let mut lwe_ksk_prng = Rng::new_with_seed(lwe_ksk_seed);
 836            let mut lwe_ksk = M::zeros(
 837                value.parameters.lwe_decomposition_count().0 * ring_size,
 838                value.parameters.lwe_n().0 + 1,
 839            );
 840            lwe_ksk.iter_rows_mut().for_each(|ri| {
 841                // first element is resereved for part b. Only sample a_is in the rest
 842                RandomFillUniformInModulus::random_fill(
 843                    &mut lwe_ksk_prng,
 844                    value.parameters.lwe_q(),
 845                    &mut ri.as_mut()[1..],
 846                )
 847            });
 848            // copy over part bs
 849            assert!(
 850                value.lwe_ksk.as_ref().len()
 851                    == value.parameters.lwe_decomposition_count().0 * ring_size
 852            );
 853            izip!(value.lwe_ksk.as_ref().iter(), lwe_ksk.iter_rows_mut()).for_each(
 854                |(b_el, lwe_ct)| {
 855                    lwe_ct.as_mut()[0] = *b_el;
 856                },
 857            );
 858
 859            // u_i to s ksk
 860            let d_uitos = value
 861                .parameters
 862                .non_interactive_ui_to_s_key_switch_decomposition_count()
 863                .0;
 864            let total_users = *value.ui_to_s_ksks_key_order.iter().max().unwrap();
 865            let ui_to_s_ksks = (0..total_users)
 866                .map(|user_index| {
 867                    let user_i_seed = value.cr_seed.ui_to_s_ks_seed_for_user_i::<Rng>(user_index);
 868                    let mut prng = Rng::new_with_seed(user_i_seed);
 869
 870                    let mut ksk_ct = M::zeros(d_uitos * 2, ring_size);
 871
 872                    ksk_ct.iter_rows_mut().take(d_uitos).for_each(|r| {
 873                        RandomFillUniformInModulus::random_fill(
 874                            &mut prng,
 875                            value.parameters.rlwe_q(),
 876                            r.as_mut(),
 877                        );
 878                    });
 879
 880                    let incoming_ksk_partb_ref =
 881                        &value.ui_to_s_ksks[value.ui_to_s_ksks_key_order[user_index]];
 882                    assert!(incoming_ksk_partb_ref.dimension() == (d_uitos, ring_size));
 883                    izip!(
 884                        ksk_ct.iter_rows_mut().skip(d_uitos),
 885                        incoming_ksk_partb_ref.iter_rows()
 886                    )
 887                    .for_each(|(to_ri, from_ri)| {
 888                        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 889                    });
 890
 891                    ksk_ct
 892                        .iter_rows_mut()
 893                        .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 894                    ksk_ct
 895                })
 896                .collect_vec();
 897
 898            NonInteractiveServerKeyEvaluationDomain {
 899                rgsw_cts,
 900                auto_keys,
 901                lwe_ksk,
 902                ui_to_s_ksks,
 903                parameters: value.parameters.clone(),
 904                _phanton: PhantomData,
 905            }
 906        }
 907    }
 908}
 909
 910pub struct SeededNonInteractiveMultiPartyServerKey<M: Matrix, S, P> {
 911    /// u_i to s key switching keys in random order
 912    ui_to_s_ksks: Vec<M>,
 913    /// Defines order for u_i to s key switchin keys by storing the index of
 914    /// user j's ksk in `ui_to_s_ksks` at index `j`. Find user j's u_i to s ksk
 915    /// at `ui_to_s_ksks[ui_to_s_ksks_key_order[j]]`
 916    ui_to_s_ksks_key_order: Vec<usize>,
 917    /// RGSW ciphertets
 918    rgsw_cts: Vec<M>,
 919    auto_keys: HashMap<usize, M>,
 920    lwe_ksk: M::R,
 921    cr_seed: S,
 922    parameters: P,
 923}
 924
 925impl<M: Matrix, S, P> SeededNonInteractiveMultiPartyServerKey<M, S, P> {
 926    pub(super) fn new(
 927        ui_to_s_ksks: Vec<M>,
 928        ui_to_s_ksks_key_order: Vec<usize>,
 929        rgsw_cts: Vec<M>,
 930        auto_keys: HashMap<usize, M>,
 931        lwe_ksk: M::R,
 932        cr_seed: S,
 933        parameters: P,
 934    ) -> Self {
 935        Self {
 936            ui_to_s_ksks,
 937            ui_to_s_ksks_key_order,
 938            rgsw_cts,
 939            auto_keys,
 940            lwe_ksk,
 941            cr_seed,
 942            parameters,
 943        }
 944    }
 945}
 946
 947pub(crate) struct ShoupNonInteractiveServerKeyEvaluationDomain<M> {
 948    /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
 949    rgsw_cts: Vec<NormalAndShoup<M>>,
 950    /// Automorphism keys under ideal rlwe secret
 951    auto_keys: HashMap<usize, NormalAndShoup<M>>,
 952    /// LWE key switching key from Q -> Q_{ks}
 953    lwe_ksk: M,
 954    /// Key switching key from user j to ideal secret key s. User j's ksk is at
 955    /// j'th element
 956    ui_to_s_ksks: Vec<NormalAndShoup<M>>,
 957}
 958
 959mod impl_shoup_non_interactive_server_key_eval_domain {
 960    use itertools::Itertools;
 961    use num_traits::{FromPrimitive, PrimInt, ToPrimitive};
 962
 963    use super::*;
 964    use crate::{backend::Modulus, pbs::PbsKey};
 965
 966    impl<M: Matrix + ToShoup<Modulus = M::MatElement>, R, N>
 967        From<NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
 968        for ShoupNonInteractiveServerKeyEvaluationDomain<M>
 969    where
 970        M::MatElement: FromPrimitive + ToPrimitive + PrimInt,
 971    {
 972        fn from(
 973            value: NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>,
 974        ) -> Self {
 975            let rlwe_q = value.parameters.rlwe_q().q().unwrap();
 976
 977            let rgsw_cts = value
 978                .rgsw_cts
 979                .into_iter()
 980                .map(|m| NormalAndShoup::new_with_modulus(m, rlwe_q))
 981                .collect_vec();
 982
 983            let mut auto_keys = HashMap::new();
 984            value.auto_keys.into_iter().for_each(|(k, v)| {
 985                auto_keys.insert(k, NormalAndShoup::new_with_modulus(v, rlwe_q));
 986            });
 987
 988            let ui_to_s_ksks = value
 989                .ui_to_s_ksks
 990                .into_iter()
 991                .map(|m| NormalAndShoup::new_with_modulus(m, rlwe_q))
 992                .collect_vec();
 993
 994            Self {
 995                rgsw_cts,
 996                auto_keys,
 997                lwe_ksk: value.lwe_ksk,
 998                ui_to_s_ksks,
 999            }
1000        }
1001    }
1002
1003    impl<M: Matrix> PbsKey for ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1004        type AutoKey = NormalAndShoup<M>;
1005        type LweKskKey = M;
1006        type RgswCt = NormalAndShoup<M>;
1007
1008        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1009            self.auto_keys.get(&k).unwrap()
1010        }
1011        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1012            &self.rgsw_cts[si]
1013        }
1014
1015        fn lwe_ksk(&self) -> &Self::LweKskKey {
1016            &self.lwe_ksk
1017        }
1018    }
1019}
1020
1021/// Server key in evaluation domain with Shoup representations
1022pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
1023    /// Rgsw cts of LWE secret elements
1024    rgsw_cts: Vec<NormalAndShoup<M>>,
1025    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
1026    /// to -g is at 0
1027    galois_keys: HashMap<usize, NormalAndShoup<M>>,
1028    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
1029    lwe_ksk: M,
1030}
1031
1032mod shoup_server_key_eval_domain {
1033    use itertools::{izip, Itertools};
1034    use num_traits::{FromPrimitive, PrimInt};
1035
1036    use crate::{backend::Modulus, pbs::PbsKey};
1037
1038    use super::*;
1039
1040    impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
1041        From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1042        for ShoupServerKeyEvaluationDomain<M>
1043    where
1044        <M as Matrix>::R: RowMut,
1045        M::MatElement: PrimInt + FromPrimitive,
1046    {
1047        fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
1048            let q = value.parameters.rlwe_q().q().unwrap();
1049            // Rgsw ciphertexts
1050            let rgsw_cts = value
1051                .rgsw_cts
1052                .into_iter()
1053                .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
1054                .collect_vec();
1055
1056            let mut auto_keys = HashMap::new();
1057            value.galois_keys.into_iter().for_each(|(index, key)| {
1058                auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
1059            });
1060
1061            Self {
1062                rgsw_cts,
1063                galois_keys: auto_keys,
1064                lwe_ksk: value.lwe_ksk,
1065            }
1066        }
1067    }
1068
1069    impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
1070        type AutoKey = NormalAndShoup<M>;
1071        type LweKskKey = M;
1072        type RgswCt = NormalAndShoup<M>;
1073
1074        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1075            self.galois_keys.get(&k).unwrap()
1076        }
1077        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1078            &self.rgsw_cts[si]
1079        }
1080
1081        fn lwe_ksk(&self) -> &Self::LweKskKey {
1082            &self.lwe_ksk
1083        }
1084    }
1085}
1086
1087/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
1088pub(crate) struct NormalAndShoup<M>(M, M);
1089
1090impl<M: ToShoup> NormalAndShoup<M> {
1091    fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
1092        let value_shoup = M::to_shoup(&value, modulus);
1093        NormalAndShoup(value, value_shoup)
1094    }
1095}
1096
1097impl<M> AsRef<M> for NormalAndShoup<M> {
1098    fn as_ref(&self) -> &M {
1099        &self.0
1100    }
1101}
1102
1103impl<M> WithShoupRepr for NormalAndShoup<M> {
1104    type M = M;
1105    fn shoup_repr(&self) -> &Self::M {
1106        &self.1
1107    }
1108}