arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/bool/keys.rs
src/bool/keys.rsRaw
   1use std::{collections::HashMap, marker::PhantomData};
   2
   3use crate::{
   4    backend::{ModInit, VectorOps},
   5    pbs::WithShoupRepr,
   6    random::{NewWithSeed, RandomFillUniformInModulus},
   7    utils::ToShoup,
   8    Matrix, MatrixEntity, MatrixMut, RowEntity, RowMut,
   9};
  10
  11use super::parameters::{BoolParameters, CiphertextModulus};
  12
  13pub(crate) trait SinglePartyClientKey {
  14    type Element;
  15    fn sk_rlwe(&self) -> Vec<Self::Element>;
  16    fn sk_lwe(&self) -> Vec<Self::Element>;
  17}
  18
  19pub(crate) trait InteractiveMultiPartyClientKey {
  20    type Element;
  21    fn sk_rlwe(&self) -> Vec<Self::Element>;
  22    fn sk_lwe(&self) -> Vec<Self::Element>;
  23}
  24
  25pub(crate) trait NonInteractiveMultiPartyClientKey {
  26    type Element;
  27    fn sk_rlwe(&self) -> Vec<Self::Element>;
  28    fn sk_u_rlwe(&self) -> Vec<Self::Element>;
  29    fn sk_lwe(&self) -> Vec<Self::Element>;
  30}
  31
  32/// Client key
  33///
  34/// Key is used for all parameter varians - Single party, interactive
  35/// multi-party, and non-interactive multi-party. The only stored the main seed
  36/// and seeds of the Rlwe/Lwe secrets are derived at puncturing the seed desired
  37/// number of times.
  38///
  39/// ### Punctures required:
  40///
  41///     Puncture 1 -> Seed of RLWE secret used as main RLWE secret for
  42///                   single-party, interactive/non-interactive multi-party
  43///
  44///     Puncture 2 -> Seed of LWE secret used main LWE secret for single-party,
  45///                   interactive/non-interactive multi-party
  46///
  47///     Puncture 3 -> Seed of RLWE secret used as `u` in
  48///                   non-interactive multi-party.
  49#[derive(Clone)]
  50pub struct ClientKey<S, E> {
  51    seed: S,
  52    parameters: BoolParameters<E>,
  53}
  54
  55mod impl_ck {
  56    use crate::{
  57        random::DefaultSecureRng,
  58        utils::{fill_random_ternary_secret_with_hamming_weight, puncture_p_rng},
  59    };
  60
  61    use super::*;
  62
  63    impl<E> ClientKey<[u8; 32], E> {
  64        pub(in super::super) fn new(parameters: BoolParameters<E>) -> ClientKey<[u8; 32], E> {
  65            let mut rng = DefaultSecureRng::new();
  66            let mut seed = [0u8; 32];
  67            rng.fill_bytes(&mut seed);
  68            Self { seed, parameters }
  69        }
  70    }
  71
  72    impl<E> SinglePartyClientKey for ClientKey<[u8; 32], E> {
  73        type Element = i32;
  74        fn sk_lwe(&self) -> Vec<Self::Element> {
  75            let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
  76            let lwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 2);
  77
  78            let mut lwe_prng = DefaultSecureRng::new_seeded(lwe_seed);
  79            let mut out = vec![0i32; self.parameters.lwe_n().0];
  80            fill_random_ternary_secret_with_hamming_weight(
  81                &mut out,
  82                self.parameters.lwe_n().0 >> 1,
  83                &mut lwe_prng,
  84            );
  85            out
  86        }
  87        fn sk_rlwe(&self) -> Vec<Self::Element> {
  88            let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
  89            let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 1);
  90
  91            let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
  92            let mut out = vec![0i32; self.parameters.rlwe_n().0];
  93            fill_random_ternary_secret_with_hamming_weight(
  94                &mut out,
  95                self.parameters.rlwe_n().0 >> 1,
  96                &mut rlwe_prng,
  97            );
  98            out
  99        }
 100    }
 101
 102    impl<E> InteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
 103        type Element = i32;
 104        fn sk_lwe(&self) -> Vec<Self::Element> {
 105            <Self as SinglePartyClientKey>::sk_lwe(&self)
 106        }
 107        fn sk_rlwe(&self) -> Vec<Self::Element> {
 108            <Self as SinglePartyClientKey>::sk_rlwe(&self)
 109        }
 110    }
 111
 112    impl<E> NonInteractiveMultiPartyClientKey for ClientKey<[u8; 32], E> {
 113        type Element = i32;
 114        fn sk_lwe(&self) -> Vec<Self::Element> {
 115            <Self as SinglePartyClientKey>::sk_lwe(&self)
 116        }
 117        fn sk_rlwe(&self) -> Vec<Self::Element> {
 118            <Self as SinglePartyClientKey>::sk_rlwe(&self)
 119        }
 120        fn sk_u_rlwe(&self) -> Vec<Self::Element> {
 121            let mut p_rng = DefaultSecureRng::new_seeded(self.seed);
 122            let rlwe_seed = puncture_p_rng::<[u8; 32], DefaultSecureRng>(&mut p_rng, 3);
 123
 124            let mut rlwe_prng = DefaultSecureRng::new_seeded(rlwe_seed);
 125            let mut out = vec![0i32; self.parameters.rlwe_n().0];
 126            fill_random_ternary_secret_with_hamming_weight(
 127                &mut out,
 128                self.parameters.rlwe_n().0 >> 1,
 129                &mut rlwe_prng,
 130            );
 131            out
 132        }
 133    }
 134}
 135
 136/// Public key
 137pub struct PublicKey<M, Rng, ModOp> {
 138    key: M,
 139    _phantom: PhantomData<(Rng, ModOp)>,
 140}
 141
 142pub(super) mod impl_pk {
 143    use super::*;
 144
 145    impl<M, R, Mo> PublicKey<M, R, Mo> {
 146        pub(in super::super) fn key(&self) -> &M {
 147            &self.key
 148        }
 149    }
 150
 151    impl<
 152            M: MatrixMut + MatrixEntity,
 153            Rng: NewWithSeed
 154                + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
 155            ModOp,
 156        > From<SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>>
 157        for PublicKey<M, Rng, ModOp>
 158    where
 159        <M as Matrix>::R: RowMut,
 160        M::MatElement: Copy,
 161    {
 162        fn from(
 163            value: SeededPublicKey<M::R, Rng::Seed, BoolParameters<M::MatElement>, ModOp>,
 164        ) -> Self {
 165            let mut prng = Rng::new_with_seed(value.seed);
 166
 167            let mut key = M::zeros(2, value.parameters.rlwe_n().0);
 168            // sample A
 169            RandomFillUniformInModulus::random_fill(
 170                &mut prng,
 171                value.parameters.rlwe_q(),
 172                key.get_row_mut(0),
 173            );
 174            // Copy over B
 175            key.get_row_mut(1).copy_from_slice(value.part_b.as_ref());
 176
 177            PublicKey {
 178                key,
 179                _phantom: PhantomData,
 180            }
 181        }
 182    }
 183
 184    impl<
 185            M: MatrixMut + MatrixEntity,
 186            Rng: NewWithSeed
 187                + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>,
 188            ModOp: VectorOps<Element = M::MatElement> + ModInit<M = CiphertextModulus<M::MatElement>>,
 189        >
 190        From<
 191            &[CommonReferenceSeededCollectivePublicKeyShare<
 192                M::R,
 193                Rng::Seed,
 194                BoolParameters<M::MatElement>,
 195            >],
 196        > for PublicKey<M, Rng, ModOp>
 197    where
 198        <M as Matrix>::R: RowMut,
 199        Rng::Seed: Copy + PartialEq,
 200        M::MatElement: PartialEq + Copy,
 201    {
 202        fn from(
 203            value: &[CommonReferenceSeededCollectivePublicKeyShare<
 204                M::R,
 205                Rng::Seed,
 206                BoolParameters<M::MatElement>,
 207            >],
 208        ) -> Self {
 209            assert!(value.len() > 0);
 210
 211            let parameters = &value[0].parameters;
 212            let mut key = M::zeros(2, parameters.rlwe_n().0);
 213
 214            // sample A
 215            let seed = value[0].cr_seed;
 216            let mut main_rng = Rng::new_with_seed(seed);
 217            RandomFillUniformInModulus::random_fill(
 218                &mut main_rng,
 219                parameters.rlwe_q(),
 220                key.get_row_mut(0),
 221            );
 222
 223            // Sum all Bs
 224            let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
 225            value.iter().for_each(|share_i| {
 226                assert!(share_i.cr_seed == seed);
 227                assert!(&share_i.parameters == parameters);
 228
 229                rlweq_modop.elwise_add_mut(key.get_row_mut(1), share_i.share.as_ref());
 230            });
 231
 232            PublicKey {
 233                key,
 234                _phantom: PhantomData,
 235            }
 236        }
 237    }
 238}
 239
 240/// Seeded public key
 241struct SeededPublicKey<Ro, S, P, ModOp> {
 242    part_b: Ro,
 243    seed: S,
 244    parameters: P,
 245    _phantom: PhantomData<ModOp>,
 246}
 247
 248mod impl_seeded_pk {
 249    use super::*;
 250
 251    impl<R, S, ModOp>
 252        From<&[CommonReferenceSeededCollectivePublicKeyShare<R, S, BoolParameters<R::Element>>]>
 253        for SeededPublicKey<R, S, BoolParameters<R::Element>, ModOp>
 254    where
 255        ModOp: VectorOps<Element = R::Element> + ModInit<M = CiphertextModulus<R::Element>>,
 256        S: PartialEq + Clone,
 257        R: RowMut + RowEntity + Clone,
 258        R::Element: Clone + PartialEq,
 259    {
 260        fn from(
 261            value: &[CommonReferenceSeededCollectivePublicKeyShare<
 262                R,
 263                S,
 264                BoolParameters<R::Element>,
 265            >],
 266        ) -> Self {
 267            assert!(value.len() > 0);
 268
 269            let parameters = &value[0].parameters;
 270            let cr_seed = value[0].cr_seed.clone();
 271
 272            // Sum all Bs
 273            let rlweq_modop = ModOp::new(parameters.rlwe_q().clone());
 274            let mut part_b = value[0].share.clone();
 275            value.iter().skip(1).for_each(|share_i| {
 276                assert!(&share_i.cr_seed == &cr_seed);
 277                assert!(&share_i.parameters == parameters);
 278
 279                rlweq_modop.elwise_add_mut(part_b.as_mut(), share_i.share.as_ref());
 280            });
 281
 282            Self {
 283                part_b,
 284                seed: cr_seed,
 285                parameters: parameters.clone(),
 286                _phantom: PhantomData,
 287            }
 288        }
 289    }
 290}
 291
 292/// CRS seeded collective public key share
 293pub struct CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
 294    /// Public key share polynomial
 295    share: Ro,
 296    /// Common reference seed
 297    cr_seed: S,
 298    /// Parameters
 299    parameters: P,
 300}
 301impl<Ro, S, P> CommonReferenceSeededCollectivePublicKeyShare<Ro, S, P> {
 302    pub(super) fn new(share: Ro, cr_seed: S, parameters: P) -> Self {
 303        CommonReferenceSeededCollectivePublicKeyShare {
 304            share,
 305            cr_seed,
 306            parameters,
 307        }
 308    }
 309}
 310
 311/// Common reference seed seeded interactive multi-party server key share
 312pub struct CommonReferenceSeededInteractiveMultiPartyServerKeyShare<M: Matrix, P, S> {
 313    /// Public key encrypted RGSW(m = X^{s[i]}) ciphertexts for LWE secret
 314    /// indices for which `Self` is the leader. Note that when `Self` is
 315    /// leader RGSW ciphertext is encrypted using RLWE x RGSW decomposer
 316    self_leader_rgsws: Vec<M>,
 317    /// Public key encrypted RGSW(m = X^{s[i]}) ciphertext for LWE secret
 318    /// indices for which `Self` is `not` the leader. Note that when `Self`
 319    /// is not the leader RGSW ciphertext is encrypted using RGSW1
 320    /// decomposer for RGSW0 x RGSW1
 321    not_self_leader_rgsws: Vec<M>,
 322    /// Auto key shares for auto elements [-g, g, g^2, .., g^{w}] where `w`
 323    /// is the window size parameter. Share corresponding to auto element -g
 324    /// is stored at key `0` and share corresponding to auto element g^{k} is
 325    /// stored at key `k`.
 326    auto_keys: HashMap<usize, M>,
 327    /// LWE key switching key share to key switching ciphertext LWE_{q, s}(m) to
 328    /// LWE_{q, z}(m) where q is LWE ciphertext modulus, `s` is the ideal RLWE
 329    /// secret with dimension N, and `z` is the ideal LWE secret of dimension n.
 330    lwe_ksk: M::R,
 331    /// Common reference seed
 332    cr_seed: S,
 333    parameters: P,
 334    /// User id assigned by the server.
 335    ///
 336    /// User id must be unique and  a number in range [0, total_users)
 337    user_id: usize,
 338}
 339
 340impl<M: Matrix, P, S> CommonReferenceSeededInteractiveMultiPartyServerKeyShare<M, P, S> {
 341    pub(super) fn new(
 342        self_leader_rgsws: Vec<M>,
 343        not_self_leader_rgsws: Vec<M>,
 344        auto_keys: HashMap<usize, M>,
 345        lwe_ksk: M::R,
 346        cr_seed: S,
 347        parameters: P,
 348        user_id: usize,
 349    ) -> Self {
 350        CommonReferenceSeededInteractiveMultiPartyServerKeyShare {
 351            self_leader_rgsws,
 352            not_self_leader_rgsws,
 353            auto_keys,
 354            lwe_ksk,
 355            cr_seed,
 356            parameters,
 357            user_id,
 358        }
 359    }
 360
 361    pub(super) fn cr_seed(&self) -> &S {
 362        &self.cr_seed
 363    }
 364
 365    pub(super) fn parameters(&self) -> &P {
 366        &self.parameters
 367    }
 368
 369    pub(super) fn auto_keys(&self) -> &HashMap<usize, M> {
 370        &self.auto_keys
 371    }
 372
 373    pub(crate) fn self_leader_rgsws(&self) -> &[M] {
 374        &self.self_leader_rgsws
 375    }
 376
 377    pub(super) fn not_self_leader_rgsws(&self) -> &[M] {
 378        &self.not_self_leader_rgsws
 379    }
 380
 381    pub(super) fn lwe_ksk(&self) -> &M::R {
 382        &self.lwe_ksk
 383    }
 384
 385    pub(super) fn user_id(&self) -> usize {
 386        self.user_id
 387    }
 388}
 389
 390/// Common reference seeded interactive multi-party server key
 391pub struct SeededInteractiveMultiPartyServerKey<M: Matrix, S, P> {
 392    /// RGSW ciphertexts RGSW(X^{s[i]}) encrypted under ideal RLWE secret key
 393    /// where `s` is ideal LWE secret key for each LWE secret dimension.
 394    rgsw_cts: Vec<M>,
 395    /// Seeded auto keys under ideal RLWE secret for RLWE automorphisms with
 396    /// auto elements [-g, g, g^2,..., g^{w}]. Auto key corresponidng to
 397    /// auto element -g is stored at key `0` and key corresponding to auto
 398    /// element g^{k} is stored at key `k`
 399    auto_keys: HashMap<usize, M>,
 400    /// Seeded LWE key switching key under ideal LWE secret to switch LWE_{q,
 401    /// s}(m) to LWE_{q, z}(m) where s is ideal RLWE secret and z is ideal LWE
 402    /// secret.
 403    lwe_ksk: M::R,
 404    /// Common reference seed
 405    cr_seed: S,
 406    parameters: P,
 407}
 408
 409impl<M: Matrix, S, P> SeededInteractiveMultiPartyServerKey<M, S, P> {
 410    pub(super) fn new(
 411        rgsw_cts: Vec<M>,
 412        auto_keys: HashMap<usize, M>,
 413        lwe_ksk: M::R,
 414        cr_seed: S,
 415        parameters: P,
 416    ) -> Self {
 417        SeededInteractiveMultiPartyServerKey {
 418            rgsw_cts,
 419            auto_keys,
 420            lwe_ksk,
 421            cr_seed,
 422            parameters,
 423        }
 424    }
 425
 426    pub(super) fn rgsw_cts(&self) -> &[M] {
 427        &self.rgsw_cts
 428    }
 429}
 430
 431/// Seeded single party server key
 432pub struct SeededSinglePartyServerKey<M: Matrix, P, S> {
 433    /// Rgsw cts of LWE secret elements
 434    pub(crate) rgsw_cts: Vec<M>,
 435    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 436    /// to -g is at 0
 437    pub(crate) auto_keys: HashMap<usize, M>,
 438    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
 439    pub(crate) lwe_ksk: M::R,
 440    /// Parameters
 441    pub(crate) parameters: P,
 442    /// Main seed
 443    pub(crate) seed: S,
 444}
 445impl<M: Matrix, S> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, S> {
 446    pub(super) fn from_raw(
 447        auto_keys: HashMap<usize, M>,
 448        rgsw_cts: Vec<M>,
 449        lwe_ksk: M::R,
 450        parameters: BoolParameters<M::MatElement>,
 451        seed: S,
 452    ) -> Self {
 453        // sanity checks
 454        auto_keys.iter().for_each(|v| {
 455            assert!(
 456                v.1.dimension()
 457                    == (
 458                        parameters.auto_decomposition_count().0,
 459                        parameters.rlwe_n().0
 460                    )
 461            )
 462        });
 463
 464        let (part_a_d, part_b_d) = parameters.rlwe_rgsw_decomposition_count();
 465        rgsw_cts.iter().for_each(|v| {
 466            assert!(v.dimension() == (part_a_d.0 * 2 + part_b_d.0, parameters.rlwe_n().0))
 467        });
 468        assert!(
 469            lwe_ksk.as_ref().len()
 470                == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
 471        );
 472
 473        SeededSinglePartyServerKey {
 474            rgsw_cts,
 475            auto_keys,
 476            lwe_ksk,
 477            parameters,
 478            seed,
 479        }
 480    }
 481}
 482
 483/// Server key in evaluation domain
 484pub(crate) struct ServerKeyEvaluationDomain<M, P, R, N> {
 485    /// RGSW ciphertext RGSW(X^{s[i]}) for each LWE index in evaluation domain
 486    rgsw_cts: Vec<M>,
 487    /// Auto keys for all auto elements [-g, g, g^2,..., g^w] in evaluation
 488    /// domain
 489    galois_keys: HashMap<usize, M>,
 490    /// LWE key switching key to key switch LWE_{q, s}(m) to LWE_{q, z}(m)
 491    lwe_ksk: M,
 492    parameters: P,
 493    _phanton: PhantomData<(R, N)>,
 494}
 495
 496pub(super) mod impl_server_key_eval_domain {
 497    use itertools::{izip, Itertools};
 498
 499    use crate::{
 500        evaluator::InteractiveMultiPartyCrs,
 501        ntt::{Ntt, NttInit},
 502        pbs::PbsKey,
 503        random::RandomFill,
 504    };
 505
 506    use super::*;
 507
 508    impl<M, Mod, R, N> ServerKeyEvaluationDomain<M, Mod, R, N> {
 509        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 510            &self.rgsw_cts
 511        }
 512    }
 513
 514    impl<
 515            M: MatrixMut + MatrixEntity,
 516            R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 517                + NewWithSeed,
 518            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
 519        > From<&SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
 520        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
 521    where
 522        <M as Matrix>::R: RowMut,
 523        M::MatElement: Copy,
 524        R::Seed: Clone,
 525    {
 526        fn from(
 527            value: &SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>,
 528        ) -> Self {
 529            let mut main_prng = R::new_with_seed(value.seed.clone());
 530            let parameters = &value.parameters;
 531            let g = parameters.g() as isize;
 532            let ring_size = value.parameters.rlwe_n().0;
 533            let lwe_n = value.parameters.lwe_n().0;
 534            let rlwe_q = value.parameters.rlwe_q();
 535            let lwq_q = value.parameters.lwe_q();
 536
 537            let nttop = N::new(rlwe_q, ring_size);
 538
 539            // galois keys
 540            let mut auto_keys = HashMap::new();
 541            let auto_decomp_count = parameters.auto_decomposition_count().0;
 542            let auto_element_dlogs = parameters.auto_element_dlogs();
 543            for i in auto_element_dlogs.into_iter() {
 544                let seeded_auto_key = value.auto_keys.get(&i).unwrap();
 545                assert!(seeded_auto_key.dimension() == (auto_decomp_count, ring_size));
 546
 547                let mut data = M::zeros(auto_decomp_count * 2, ring_size);
 548
 549                // sample RLWE'_A(-s(X^k))
 550                data.iter_rows_mut().take(auto_decomp_count).for_each(|ri| {
 551                    RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
 552                });
 553
 554                // copy over RLWE'B_(-s(X^k))
 555                izip!(
 556                    data.iter_rows_mut().skip(auto_decomp_count),
 557                    seeded_auto_key.iter_rows()
 558                )
 559                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 560
 561                // Send to Evaluation domain
 562                data.iter_rows_mut()
 563                    .for_each(|ri| nttop.forward(ri.as_mut()));
 564
 565                auto_keys.insert(i, data);
 566            }
 567
 568            // RGSW ciphertexts
 569            let (rlrg_a_decomp, rlrg_b_decomp) = parameters.rlwe_rgsw_decomposition_count();
 570            let rgsw_cts = value
 571                .rgsw_cts
 572                .iter()
 573                .map(|seeded_rgsw_si| {
 574                    assert!(
 575                        seeded_rgsw_si.dimension()
 576                            == (rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0, ring_size)
 577                    );
 578
 579                    let mut data = M::zeros(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0 * 2, ring_size);
 580
 581                    // copy over RLWE'(-sm)
 582                    izip!(
 583                        data.iter_rows_mut().take(rlrg_a_decomp.0 * 2),
 584                        seeded_rgsw_si.iter_rows().take(rlrg_a_decomp.0 * 2)
 585                    )
 586                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 587
 588                    // sample RLWE'_A(m)
 589                    data.iter_rows_mut()
 590                        .skip(rlrg_a_decomp.0 * 2)
 591                        .take(rlrg_b_decomp.0)
 592                        .for_each(|ri| {
 593                            RandomFillUniformInModulus::random_fill(
 594                                &mut main_prng,
 595                                &rlwe_q,
 596                                ri.as_mut(),
 597                            )
 598                        });
 599
 600                    // copy over RLWE'_B(m)
 601                    izip!(
 602                        data.iter_rows_mut()
 603                            .skip(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0),
 604                        seeded_rgsw_si.iter_rows().skip(rlrg_a_decomp.0 * 2)
 605                    )
 606                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 607
 608                    // send polynomials to evaluation domain
 609                    data.iter_rows_mut()
 610                        .for_each(|ri| nttop.forward(ri.as_mut()));
 611
 612                    data
 613                })
 614                .collect_vec();
 615
 616            // LWE ksk
 617            let lwe_ksk = {
 618                let d = parameters.lwe_decomposition_count().0;
 619                assert!(value.lwe_ksk.as_ref().len() == d * ring_size);
 620
 621                let mut data = M::zeros(d * ring_size, lwe_n + 1);
 622                izip!(data.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
 623                    |(lwe_i, bi)| {
 624                        RandomFillUniformInModulus::random_fill(
 625                            &mut main_prng,
 626                            &lwq_q,
 627                            &mut lwe_i.as_mut()[1..],
 628                        );
 629                        lwe_i.as_mut()[0] = *bi;
 630                    },
 631                );
 632
 633                data
 634            };
 635
 636            ServerKeyEvaluationDomain {
 637                rgsw_cts,
 638                galois_keys: auto_keys,
 639                lwe_ksk,
 640                parameters: parameters.clone(),
 641                _phanton: PhantomData,
 642            }
 643        }
 644    }
 645
 646    impl<
 647            M: MatrixMut + MatrixEntity,
 648            Rng: NewWithSeed,
 649            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
 650        >
 651        From<
 652            &SeededInteractiveMultiPartyServerKey<
 653                M,
 654                InteractiveMultiPartyCrs<Rng::Seed>,
 655                BoolParameters<M::MatElement>,
 656            >,
 657        > for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 658    where
 659        <M as Matrix>::R: RowMut,
 660        Rng::Seed: Copy + Default,
 661        Rng: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 662            + RandomFill<Rng::Seed>,
 663        M::MatElement: Copy,
 664    {
 665        fn from(
 666            value: &SeededInteractiveMultiPartyServerKey<
 667                M,
 668                InteractiveMultiPartyCrs<Rng::Seed>,
 669                BoolParameters<M::MatElement>,
 670            >,
 671        ) -> Self {
 672            let g = value.parameters.g() as isize;
 673            let rlwe_n = value.parameters.rlwe_n().0;
 674            let lwe_n = value.parameters.lwe_n().0;
 675            let rlwe_q = value.parameters.rlwe_q();
 676            let lwe_q = value.parameters.lwe_q();
 677
 678            let rlwe_nttop = N::new(rlwe_q, rlwe_n);
 679
 680            // auto keys
 681            let mut auto_keys = HashMap::new();
 682            {
 683                let mut auto_prng = Rng::new_with_seed(value.cr_seed.auto_keys_cts_seed::<Rng>());
 684                let auto_d_count = value.parameters.auto_decomposition_count().0;
 685                let auto_element_dlogs = value.parameters.auto_element_dlogs();
 686                for i in auto_element_dlogs.into_iter() {
 687                    let mut key = M::zeros(auto_d_count * 2, rlwe_n);
 688
 689                    // sample a
 690                    key.iter_rows_mut().take(auto_d_count).for_each(|ri| {
 691                        RandomFillUniformInModulus::random_fill(
 692                            &mut auto_prng,
 693                            &rlwe_q,
 694                            ri.as_mut(),
 695                        )
 696                    });
 697
 698                    let key_part_b = value.auto_keys.get(&i).unwrap();
 699                    assert!(key_part_b.dimension() == (auto_d_count, rlwe_n));
 700                    izip!(
 701                        key.iter_rows_mut().skip(auto_d_count),
 702                        key_part_b.iter_rows()
 703                    )
 704                    .for_each(|(to_ri, from_ri)| {
 705                        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 706                    });
 707
 708                    // send to evaluation domain
 709                    key.iter_rows_mut()
 710                        .for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
 711
 712                    auto_keys.insert(i, key);
 713                }
 714            }
 715
 716            // rgsw cts
 717            let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
 718            let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
 719            let rgsw_cts = value
 720                .rgsw_cts
 721                .iter()
 722                .map(|ct_i_in| {
 723                    assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
 724                    let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
 725
 726                    izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
 727                        |(to_ri, from_ri)| {
 728                            to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 729                            rlwe_nttop.forward(to_ri.as_mut());
 730                        },
 731                    );
 732
 733                    eval_ct_i_out
 734                })
 735                .collect_vec();
 736
 737            // lwe ksk
 738            let mut lwe_ksk_prng = Rng::new_with_seed(value.cr_seed.lwe_ksk_cts_seed_seed::<Rng>());
 739            let d_lwe = value.parameters.lwe_decomposition_count().0;
 740            let mut lwe_ksk = M::zeros(rlwe_n * d_lwe, lwe_n + 1);
 741            izip!(lwe_ksk.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
 742                |(lwe_i, bi)| {
 743                    RandomFillUniformInModulus::random_fill(
 744                        &mut lwe_ksk_prng,
 745                        &lwe_q,
 746                        &mut lwe_i.as_mut()[1..],
 747                    );
 748                    lwe_i.as_mut()[0] = *bi;
 749                },
 750            );
 751
 752            ServerKeyEvaluationDomain {
 753                rgsw_cts,
 754                galois_keys: auto_keys,
 755                lwe_ksk,
 756                parameters: value.parameters.clone(),
 757                _phanton: PhantomData,
 758            }
 759        }
 760    }
 761
 762    impl<M: Matrix, P, R, N> PbsKey for ServerKeyEvaluationDomain<M, P, R, N> {
 763        type AutoKey = M;
 764        type LweKskKey = M;
 765        type RgswCt = M;
 766
 767        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
 768            self.galois_keys.get(&k).unwrap()
 769        }
 770        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
 771            &self.rgsw_cts[si]
 772        }
 773
 774        fn lwe_ksk(&self) -> &Self::LweKskKey {
 775            &self.lwe_ksk
 776        }
 777    }
 778
 779    #[cfg(test)]
 780    impl<M, P, R, N> super::super::print_noise::CollectRuntimeServerKeyStats
 781        for ServerKeyEvaluationDomain<M, P, R, N>
 782    {
 783        type M = M;
 784        fn galois_key_for_auto(&self, k: usize) -> &Self::M {
 785            self.galois_keys.get(&k).unwrap()
 786        }
 787        fn lwe_ksk(&self) -> &Self::M {
 788            &self.lwe_ksk
 789        }
 790        fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M {
 791            &self.rgsw_cts[s_index]
 792        }
 793    }
 794}
 795
 796/// Non-interactive multi-party server key in evaluation domain.
 797///
 798/// The key is derived from Seeded non-interactive mmulti-party server key
 799/// `SeededNonInteractiveMultiPartyServerKey`.
 800pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 801    /// RGSW ciphertexts RGSW(X^{s[i]}) under ideal RLWE secret key in
 802    /// evaluation domain
 803    rgsw_cts: Vec<M>,
 804    /// Auto keys for all auto elements [-g, g, g^2, g^w] in evaluation
 805    /// domain
 806    auto_keys: HashMap<usize, M>,
 807    /// LWE key switching key to key switch LWE_{q, s}(m) to LWE_{q, z}(m)
 808    lwe_ksk: M,
 809    /// Key switching key from user j's secret u_j to ideal RLWE secret key `s`
 810    /// in evaluation domain. User j's key switching key is at j'th index.
 811    ui_to_s_ksks: Vec<M>,
 812    parameters: P,
 813    _phanton: PhantomData<(R, N)>,
 814}
 815
 816pub(super) mod impl_non_interactive_server_key_eval_domain {
 817    use itertools::{izip, Itertools};
 818
 819    use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
 820
 821    use super::*;
 822
 823    impl<M, P, R, N> NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 824        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 825            &self.rgsw_cts
 826        }
 827    }
 828
 829    impl<M, Rng, N>
 830        From<
 831            &SeededNonInteractiveMultiPartyServerKey<
 832                M,
 833                NonInteractiveMultiPartyCrs<Rng::Seed>,
 834                BoolParameters<M::MatElement>,
 835            >,
 836        > for NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 837    where
 838        M: MatrixMut + MatrixEntity + Clone,
 839        Rng: NewWithSeed
 840            + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 841            + RandomFill<<Rng as NewWithSeed>::Seed>,
 842        N: Ntt<Element = M::MatElement> + NttInit<CiphertextModulus<M::MatElement>>,
 843        M::R: RowMut,
 844        M::MatElement: Copy,
 845        Rng::Seed: Clone + Copy + Default,
 846    {
 847        fn from(
 848            value: &SeededNonInteractiveMultiPartyServerKey<
 849                M,
 850                NonInteractiveMultiPartyCrs<Rng::Seed>,
 851                BoolParameters<M::MatElement>,
 852            >,
 853        ) -> Self {
 854            let rlwe_nttop = N::new(value.parameters.rlwe_q(), value.parameters.rlwe_n().0);
 855            let ring_size = value.parameters.rlwe_n().0;
 856
 857            // RGSW cts
 858            // copy over rgsw cts and send to evaluation domain
 859            let mut rgsw_cts = value.rgsw_cts.clone();
 860            rgsw_cts.iter_mut().for_each(|c| {
 861                c.iter_rows_mut()
 862                    .for_each(|ri| rlwe_nttop.forward(ri.as_mut()))
 863            });
 864
 865            // Auto keys
 866            // populate pseudo random part of auto keys. Then send auto keys to
 867            // evaluation domain
 868            let mut auto_keys = HashMap::new();
 869            let auto_seed = value.cr_seed.auto_keys_cts_seed::<Rng>();
 870            let mut auto_prng = Rng::new_with_seed(auto_seed);
 871            let auto_element_dlogs = value.parameters.auto_element_dlogs();
 872            let d_auto = value.parameters.auto_decomposition_count().0;
 873            auto_element_dlogs.iter().for_each(|el| {
 874                let auto_part_b = value
 875                    .auto_keys
 876                    .get(el)
 877                    .expect(&format!("Auto key for element g^{el} not found"));
 878
 879                assert!(auto_part_b.dimension() == (d_auto, ring_size));
 880
 881                let mut auto_ct = M::zeros(d_auto * 2, ring_size);
 882
 883                // sample part A
 884                auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
 885                    RandomFillUniformInModulus::random_fill(
 886                        &mut auto_prng,
 887                        value.parameters.rlwe_q(),
 888                        ri.as_mut(),
 889                    )
 890                });
 891
 892                // Copy over part B
 893                izip!(
 894                    auto_ct.iter_rows_mut().skip(d_auto),
 895                    auto_part_b.iter_rows()
 896                )
 897                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 898
 899                // send to evaluation domain
 900                auto_ct
 901                    .iter_rows_mut()
 902                    .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 903
 904                auto_keys.insert(*el, auto_ct);
 905            });
 906
 907            // LWE ksk
 908            // populate pseudo random part of lwe ciphertexts in ksk and copy over part b
 909            // elements
 910            let lwe_ksk_seed = value.cr_seed.lwe_ksk_cts_seed::<Rng>();
 911            let mut lwe_ksk_prng = Rng::new_with_seed(lwe_ksk_seed);
 912            let mut lwe_ksk = M::zeros(
 913                value.parameters.lwe_decomposition_count().0 * ring_size,
 914                value.parameters.lwe_n().0 + 1,
 915            );
 916            lwe_ksk.iter_rows_mut().for_each(|ri| {
 917                // first element is resereved for part b. Only sample a_is in the rest
 918                RandomFillUniformInModulus::random_fill(
 919                    &mut lwe_ksk_prng,
 920                    value.parameters.lwe_q(),
 921                    &mut ri.as_mut()[1..],
 922                )
 923            });
 924            // copy over part bs
 925            assert!(
 926                value.lwe_ksk.as_ref().len()
 927                    == value.parameters.lwe_decomposition_count().0 * ring_size
 928            );
 929            izip!(value.lwe_ksk.as_ref().iter(), lwe_ksk.iter_rows_mut()).for_each(
 930                |(b_el, lwe_ct)| {
 931                    lwe_ct.as_mut()[0] = *b_el;
 932                },
 933            );
 934
 935            // u_i to s ksk
 936            let d_uitos = value
 937                .parameters
 938                .non_interactive_ui_to_s_key_switch_decomposition_count()
 939                .0;
 940            let ui_to_s_ksks = value
 941                .ui_to_s_ksks
 942                .iter()
 943                .enumerate()
 944                .map(|(user_id, incoming_ksk_partb)| {
 945                    let user_i_seed = value.cr_seed.ui_to_s_ks_seed_for_user_i::<Rng>(user_id);
 946                    let mut prng = Rng::new_with_seed(user_i_seed);
 947
 948                    let mut ksk_ct = M::zeros(d_uitos * 2, ring_size);
 949
 950                    ksk_ct.iter_rows_mut().take(d_uitos).for_each(|r| {
 951                        RandomFillUniformInModulus::random_fill(
 952                            &mut prng,
 953                            value.parameters.rlwe_q(),
 954                            r.as_mut(),
 955                        );
 956                    });
 957
 958                    assert!(incoming_ksk_partb.dimension() == (d_uitos, ring_size));
 959                    izip!(
 960                        ksk_ct.iter_rows_mut().skip(d_uitos),
 961                        incoming_ksk_partb.iter_rows()
 962                    )
 963                    .for_each(|(to_ri, from_ri)| {
 964                        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 965                    });
 966
 967                    ksk_ct
 968                        .iter_rows_mut()
 969                        .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 970                    ksk_ct
 971                })
 972                .collect_vec();
 973
 974            NonInteractiveServerKeyEvaluationDomain {
 975                rgsw_cts,
 976                auto_keys,
 977                lwe_ksk,
 978                ui_to_s_ksks,
 979                parameters: value.parameters.clone(),
 980                _phanton: PhantomData,
 981            }
 982        }
 983    }
 984
 985    #[cfg(test)]
 986    impl<M, P, R, N> super::super::print_noise::CollectRuntimeServerKeyStats
 987        for NonInteractiveServerKeyEvaluationDomain<M, P, R, N>
 988    {
 989        type M = M;
 990        fn galois_key_for_auto(&self, k: usize) -> &Self::M {
 991            self.auto_keys.get(&k).unwrap()
 992        }
 993        fn lwe_ksk(&self) -> &Self::M {
 994            &self.lwe_ksk
 995        }
 996        fn rgsw_cts_lwe_si(&self, s_index: usize) -> &Self::M {
 997            &self.rgsw_cts[s_index]
 998        }
 999    }
1000}
1001
1002/// Seeded non-interactive multi-party server key.
1003///
1004/// Given common reference seeded non-interactive multi-party key shares of each
1005/// users with unique user-ids, seeded non-interactive can be generated using
1006/// `BoolEvaluator::aggregate_non_interactive_multi_party_key_share`
1007pub struct SeededNonInteractiveMultiPartyServerKey<M: Matrix, S, P> {
1008    /// Key switching key from user j's secret u_j to ideal RLWE secret key `s`.
1009    /// User j's key switching key is at j'th index.
1010    ui_to_s_ksks: Vec<M>,
1011    /// RGSW ciphertexts RGSW(X^{s[i]}) under ideal RLWE secret key
1012    rgsw_cts: Vec<M>,
1013    /// Auto keys for all auto elements [-g, g, g^2, g^w]
1014    auto_keys: HashMap<usize, M>,
1015    /// LWE key switching key to key switch LWE_{q, s}(m) to LWE_{q, z}(m)
1016    lwe_ksk: M::R,
1017    /// Common reference seed
1018    cr_seed: S,
1019    parameters: P,
1020}
1021
1022impl<M: Matrix, S, P> SeededNonInteractiveMultiPartyServerKey<M, S, P> {
1023    pub(super) fn new(
1024        ui_to_s_ksks: Vec<M>,
1025        rgsw_cts: Vec<M>,
1026        auto_keys: HashMap<usize, M>,
1027        lwe_ksk: M::R,
1028        cr_seed: S,
1029        parameters: P,
1030    ) -> Self {
1031        Self {
1032            ui_to_s_ksks,
1033
1034            rgsw_cts,
1035            auto_keys,
1036            lwe_ksk,
1037            cr_seed,
1038            parameters,
1039        }
1040    }
1041}
1042
1043/// This key is equivalent to NonInteractiveServerKeyEvaluationDomain with the
1044/// addition that each polynomial in evaluation domain has a corresponding shoup
1045/// representation suitable for shoup multiplication.
1046pub(crate) struct ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1047    rgsw_cts: Vec<NormalAndShoup<M>>,
1048    auto_keys: HashMap<usize, NormalAndShoup<M>>,
1049    lwe_ksk: M,
1050    ui_to_s_ksks: Vec<NormalAndShoup<M>>,
1051}
1052
1053mod impl_shoup_non_interactive_server_key_eval_domain {
1054    use itertools::Itertools;
1055    use num_traits::{FromPrimitive, PrimInt, ToPrimitive};
1056
1057    use super::*;
1058    use crate::{backend::Modulus, decomposer::NumInfo, pbs::PbsKey};
1059
1060    impl<M> ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1061        pub(in super::super) fn ui_to_s_ksk(&self, user_id: usize) -> &NormalAndShoup<M> {
1062            &self.ui_to_s_ksks[user_id]
1063        }
1064    }
1065
1066    impl<M: Matrix + ToShoup<Modulus = M::MatElement>, R, N>
1067        From<NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1068        for ShoupNonInteractiveServerKeyEvaluationDomain<M>
1069    where
1070        M::MatElement: FromPrimitive + ToPrimitive + PrimInt + NumInfo,
1071    {
1072        fn from(
1073            value: NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>,
1074        ) -> Self {
1075            let rlwe_q = value.parameters.rlwe_q().q().unwrap();
1076
1077            let rgsw_dim = (
1078                value.parameters.rlwe_rgsw_decomposition_count().0 .0 * 2
1079                    + value.parameters.rlwe_rgsw_decomposition_count().1 .0 * 2,
1080                value.parameters.rlwe_n().0,
1081            );
1082            let rgsw_cts = value
1083                .rgsw_cts
1084                .into_iter()
1085                .map(|m| {
1086                    assert!(m.dimension() == rgsw_dim);
1087                    NormalAndShoup::new_with_modulus(m, rlwe_q)
1088                })
1089                .collect_vec();
1090
1091            let auto_dim = (
1092                value.parameters.auto_decomposition_count().0 * 2,
1093                value.parameters.rlwe_n().0,
1094            );
1095            let mut auto_keys = HashMap::new();
1096            value.auto_keys.into_iter().for_each(|(k, v)| {
1097                assert!(v.dimension() == auto_dim);
1098                auto_keys.insert(k, NormalAndShoup::new_with_modulus(v, rlwe_q));
1099            });
1100
1101            let ui_ks_dim = (
1102                value
1103                    .parameters
1104                    .non_interactive_ui_to_s_key_switch_decomposition_count()
1105                    .0
1106                    * 2,
1107                value.parameters.rlwe_n().0,
1108            );
1109            let ui_to_s_ksks = value
1110                .ui_to_s_ksks
1111                .into_iter()
1112                .map(|m| {
1113                    assert!(m.dimension() == ui_ks_dim);
1114                    NormalAndShoup::new_with_modulus(m, rlwe_q)
1115                })
1116                .collect_vec();
1117
1118            assert!(
1119                value.lwe_ksk.dimension()
1120                    == (
1121                        value.parameters.rlwe_n().0 * value.parameters.lwe_decomposition_count().0,
1122                        value.parameters.lwe_n().0 + 1
1123                    )
1124            );
1125
1126            Self {
1127                rgsw_cts,
1128                auto_keys,
1129                lwe_ksk: value.lwe_ksk,
1130                ui_to_s_ksks,
1131            }
1132        }
1133    }
1134
1135    impl<M: Matrix> PbsKey for ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1136        type AutoKey = NormalAndShoup<M>;
1137        type LweKskKey = M;
1138        type RgswCt = NormalAndShoup<M>;
1139
1140        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1141            let d = self.auto_keys.get(&k).unwrap();
1142            d
1143        }
1144        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1145            &self.rgsw_cts[si]
1146        }
1147
1148        fn lwe_ksk(&self) -> &Self::LweKskKey {
1149            &self.lwe_ksk
1150        }
1151    }
1152}
1153
1154/// This is equivalent to ServerKeyEvaluationDomain with the addition that each
1155/// polynomial in evaluation domain has corresponding shoup representation
1156/// suitable for shoup multiplication.
1157pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
1158    rgsw_cts: Vec<NormalAndShoup<M>>,
1159    galois_keys: HashMap<usize, NormalAndShoup<M>>,
1160    lwe_ksk: M,
1161}
1162
1163mod shoup_server_key_eval_domain {
1164    use itertools::{izip, Itertools};
1165    use num_traits::{FromPrimitive, PrimInt};
1166
1167    use crate::{backend::Modulus, decomposer::NumInfo, pbs::PbsKey};
1168
1169    use super::*;
1170
1171    impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
1172        From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1173        for ShoupServerKeyEvaluationDomain<M>
1174    where
1175        <M as Matrix>::R: RowMut,
1176        M::MatElement: PrimInt + FromPrimitive + NumInfo,
1177    {
1178        fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
1179            let q = value.parameters.rlwe_q().q().unwrap();
1180            // Rgsw ciphertexts
1181            let rgsw_cts = value
1182                .rgsw_cts
1183                .into_iter()
1184                .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
1185                .collect_vec();
1186
1187            let mut auto_keys = HashMap::new();
1188            value.galois_keys.into_iter().for_each(|(index, key)| {
1189                auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
1190            });
1191
1192            Self {
1193                rgsw_cts,
1194                galois_keys: auto_keys,
1195                lwe_ksk: value.lwe_ksk,
1196            }
1197        }
1198    }
1199
1200    impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
1201        type AutoKey = NormalAndShoup<M>;
1202        type LweKskKey = M;
1203        type RgswCt = NormalAndShoup<M>;
1204
1205        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1206            self.galois_keys.get(&k).unwrap()
1207        }
1208        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1209            &self.rgsw_cts[si]
1210        }
1211
1212        fn lwe_ksk(&self) -> &Self::LweKskKey {
1213            &self.lwe_ksk
1214        }
1215    }
1216}
1217
1218pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M: Matrix, P, S> {
1219    /// Non-interactive RGSW ciphertexts for LWE secret indices for which user
1220    /// is the leader
1221    self_leader_ni_rgsw_cts: Vec<M>,
1222    /// Non-interactive RGSW ciphertexts for LWE secret indices for which user
1223    /// is not the leader
1224    not_self_leader_ni_rgsw_cts: Vec<M>,
1225    /// Zero encryptions for RGSW ciphertexts for all indices
1226    ni_rgsw_zero_encs: Vec<M>,
1227
1228    /// Key switching key from u_j to s where u_j is user j's RLWE secret `u`
1229    /// and `s` is ideal RLWE secret. Note that in server key share the key
1230    /// switching key is encrypted under user j's RLWE secret `s_j`. It is
1231    /// then switched to ideal RLWE secret after adding zero encryptions
1232    /// generated using same `a_k`s from other users.
1233    ///
1234    /// That is the key share has the following key switching key:
1235    ///      (a_k*s_j + e + \beta u_j, a_k*s_j + e)
1236    ui_to_s_ksk: M,
1237    /// Zero encryptions to switch user l's key switching key u_l to s from
1238    /// user l's RLWE secret s_l to ideal RLWE secret `s`.
1239    ///
1240    /// If there are P total parties then zero encryption sets are generated for
1241    /// each party l \in [0, P) and l != j where j self's user_id.
1242    ///
1243    /// Zero encryption set for user `l` is stored at index l is l < j otherwise
1244    /// it is stored at index l - 1, where j is self's user_id
1245    ksk_zero_encs_for_others: Vec<M>,
1246
1247    /// RLWE auto key shares for auto elements [-g, g, g^2, g^{w}] where `w`
1248    /// is the window size. Auto key share corresponding to auto element -g
1249    /// is stored at key 0 and key share corresponding to auto element g^{k} is
1250    /// stored at key `k`
1251    auto_keys_share: HashMap<usize, M>,
1252    /// LWE key switching key share to key switching LWE_{q, s}(m) to LWE_{q,
1253    /// z}(m)
1254    lwe_ksk_share: M::R,
1255
1256    /// User's id.
1257    ///
1258    /// If there are P total parties, then user id must be inque and in range
1259    /// [0, P)
1260    user_id: usize,
1261    /// Total users participating in multi-party compute
1262    total_users: usize,
1263    /// LWE dimension
1264    lwe_n: usize,
1265    /// Common reference seed
1266    cr_seed: S,
1267    parameters: P,
1268}
1269
1270mod impl_common_ref_non_interactive_multi_party_server_share {
1271    use crate::evaluator::multi_party_user_id_lwe_segment;
1272
1273    use super::*;
1274
1275    impl<M: Matrix, P, S> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, P, S> {
1276        pub(in super::super) fn new(
1277            self_leader_ni_rgsw_cts: Vec<M>,
1278            not_self_leader_ni_rgsw_cts: Vec<M>,
1279            ni_rgsw_zero_encs: Vec<M>,
1280            ui_to_s_ksk: M,
1281            ksk_zero_encs_for_others: Vec<M>,
1282            auto_keys_share: HashMap<usize, M>,
1283            lwe_ksk_share: M::R,
1284            user_index: usize,
1285            total_users: usize,
1286            lwe_n: usize,
1287            cr_seed: S,
1288            parameters: P,
1289        ) -> Self {
1290            Self {
1291                self_leader_ni_rgsw_cts,
1292                not_self_leader_ni_rgsw_cts,
1293                ni_rgsw_zero_encs,
1294                ui_to_s_ksk,
1295                ksk_zero_encs_for_others,
1296                auto_keys_share,
1297                lwe_ksk_share,
1298                user_id: user_index,
1299                total_users,
1300                lwe_n,
1301                cr_seed,
1302                parameters,
1303            }
1304        }
1305
1306        pub(in super::super) fn ni_rgsw_cts_for_self_leader_lwe_index(
1307            &self,
1308            lwe_index: usize,
1309        ) -> &M {
1310            let self_segment =
1311                multi_party_user_id_lwe_segment(self.user_id, self.total_users, self.lwe_n);
1312            assert!(lwe_index >= self_segment.0 && lwe_index < self_segment.1);
1313            &self.self_leader_ni_rgsw_cts[lwe_index - self_segment.0]
1314        }
1315
1316        pub(in super::super) fn ni_rgsw_cts_for_self_not_leader_lwe_index(
1317            &self,
1318            lwe_index: usize,
1319        ) -> &M {
1320            let self_segment =
1321                multi_party_user_id_lwe_segment(self.user_id, self.total_users, self.lwe_n);
1322            // Non-interactive RGSW cts when self is not leader are stored in
1323            // sorted-order. For ex, if self is the leader for indices (5, 6]
1324            // then self stores NI-RGSW cts for rest of indices like [0, 1, 2,
1325            // 3, 4, 6, 7, 8, 9]
1326            assert!(lwe_index < self.lwe_n);
1327            assert!(lwe_index < self_segment.0 || lwe_index >= self_segment.1);
1328            if lwe_index < self_segment.0 {
1329                &self.not_self_leader_ni_rgsw_cts[lwe_index]
1330            } else {
1331                &self.not_self_leader_ni_rgsw_cts[lwe_index - (self_segment.1 - self_segment.0)]
1332            }
1333        }
1334
1335        pub(in super::super) fn ni_rgsw_zero_enc_for_lwe_index(&self, lwe_index: usize) -> &M {
1336            &self.ni_rgsw_zero_encs[lwe_index]
1337        }
1338
1339        pub(in super::super) fn ui_to_s_ksk(&self) -> &M {
1340            &self.ui_to_s_ksk
1341        }
1342
1343        pub(in super::super) fn user_index(&self) -> usize {
1344            self.user_id
1345        }
1346
1347        pub(in super::super) fn auto_keys_share(&self) -> &HashMap<usize, M> {
1348            &self.auto_keys_share
1349        }
1350
1351        pub(in super::super) fn lwe_ksk_share(&self) -> &M::R {
1352            &self.lwe_ksk_share
1353        }
1354
1355        pub(in super::super) fn ui_to_s_ksk_zero_encs_for_user_i(&self, user_i: usize) -> &M {
1356            assert!(user_i != self.user_id);
1357            if user_i < self.user_id {
1358                &self.ksk_zero_encs_for_others[user_i]
1359            } else {
1360                &self.ksk_zero_encs_for_others[user_i - 1]
1361            }
1362        }
1363
1364        pub(in super::super) fn cr_seed(&self) -> &S {
1365            &self.cr_seed
1366        }
1367
1368        pub(in super::super) fn parameters(&self) -> &P {
1369            &self.parameters
1370        }
1371    }
1372}
1373
1374/// Stores both normal and shoup representation of elements in the container
1375/// (for ex, a matrix).
1376///
1377/// To access normal representation borrow self as a `self.as_ref()`. To access
1378/// shoup representation call `self.shoup_repr()`
1379pub(crate) struct NormalAndShoup<M>(M, M);
1380
1381impl<M: ToShoup> NormalAndShoup<M> {
1382    fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
1383        let value_shoup = M::to_shoup(&value, modulus);
1384        NormalAndShoup(value, value_shoup)
1385    }
1386}
1387
1388impl<M> AsRef<M> for NormalAndShoup<M> {
1389    fn as_ref(&self) -> &M {
1390        &self.0
1391    }
1392}
1393
1394impl<M> WithShoupRepr for NormalAndShoup<M> {
1395    type M = M;
1396    fn shoup_repr(&self) -> &Self::M {
1397        &self.1
1398    }
1399}
1400
1401#[cfg(test)]
1402pub(crate) mod key_size {
1403    use num_traits::{FromPrimitive, PrimInt};
1404
1405    use crate::{backend::Modulus, decomposer::NumInfo, SizeInBitsWithLogModulus};
1406
1407    use super::*;
1408
1409    /// Size of the Key in Bits
1410    pub(crate) trait KeySize {
1411        /// Returns size of the key in bits
1412        fn size(&self) -> usize;
1413    }
1414
1415    impl<M: Matrix, El, S> KeySize
1416        for CommonReferenceSeededInteractiveMultiPartyServerKeyShare<M, BoolParameters<El>, S>
1417    where
1418        M: SizeInBitsWithLogModulus,
1419        M::R: SizeInBitsWithLogModulus,
1420        El: PrimInt + NumInfo + FromPrimitive,
1421    {
1422        fn size(&self) -> usize {
1423            let mut total = 0;
1424
1425            let log_rlweq = self.parameters().rlwe_q().log_q();
1426            self.self_leader_rgsws
1427                .iter()
1428                .for_each(|v| total += v.size(log_rlweq));
1429            self.not_self_leader_rgsws
1430                .iter()
1431                .for_each(|v| total += v.size(log_rlweq));
1432            self.auto_keys
1433                .values()
1434                .for_each(|v| total += v.size(log_rlweq));
1435
1436            let log_lweq = self.parameters().lwe_q().log_q();
1437            total += self.lwe_ksk.size(log_lweq);
1438            total
1439        }
1440    }
1441
1442    impl<M: Matrix, El, S> KeySize
1443        for CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, BoolParameters<El>, S>
1444    where
1445        M: SizeInBitsWithLogModulus,
1446        M::R: SizeInBitsWithLogModulus,
1447        El: PrimInt + NumInfo + FromPrimitive,
1448    {
1449        fn size(&self) -> usize {
1450            let mut total = 0;
1451
1452            let log_rlweq = self.parameters.rlwe_q().log_q();
1453            self.self_leader_ni_rgsw_cts
1454                .iter()
1455                .for_each(|v| total += v.size(log_rlweq));
1456            self.not_self_leader_ni_rgsw_cts
1457                .iter()
1458                .for_each(|v| total += v.size(log_rlweq));
1459            self.ni_rgsw_zero_encs
1460                .iter()
1461                .for_each(|v| total += v.size(log_rlweq));
1462            total += self.ui_to_s_ksk.size(log_rlweq);
1463            self.ksk_zero_encs_for_others
1464                .iter()
1465                .for_each(|v| total += v.size(log_rlweq));
1466            self.auto_keys_share
1467                .values()
1468                .for_each(|v| total += v.size(log_rlweq));
1469
1470            let log_lweq = self.parameters.lwe_q().log_q();
1471            total += self.lwe_ksk_share.size(log_lweq);
1472
1473            total
1474        }
1475    }
1476}
1477
1478pub(super) mod tests {
1479    use itertools::izip;
1480    use num_traits::{FromPrimitive, PrimInt, ToPrimitive, Zero};
1481
1482    use crate::{
1483        backend::{GetModulus, Modulus},
1484        bool::ClientKey,
1485        decomposer::NumInfo,
1486        lwe::decrypt_lwe,
1487        parameters::CiphertextModulus,
1488        utils::TryConvertFrom1,
1489        ArithmeticOps, Row,
1490    };
1491
1492    use super::SinglePartyClientKey;
1493
1494    pub(crate) fn ideal_sk_rlwe(cks: &[ClientKey]) -> Vec<i32> {
1495        let mut ideal_rlwe_sk = cks[0].sk_rlwe();
1496        cks.iter().skip(1).for_each(|k| {
1497            let sk_rlwe = k.sk_rlwe();
1498            izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
1499                *a = *a + b;
1500            });
1501        });
1502        ideal_rlwe_sk
1503    }
1504
1505    pub(crate) fn ideal_sk_lwe(cks: &[ClientKey]) -> Vec<i32> {
1506        let mut ideal_rlwe_sk = cks[0].sk_lwe();
1507        cks.iter().skip(1).for_each(|k| {
1508            let sk_rlwe = k.sk_lwe();
1509            izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
1510                *a = *a + b;
1511            });
1512        });
1513        ideal_rlwe_sk
1514    }
1515
1516    pub(crate) fn measure_noise_lwe<
1517        R: Row,
1518        S,
1519        Modop: ArithmeticOps<Element = R::Element>
1520            + GetModulus<M = CiphertextModulus<R::Element>, Element = R::Element>,
1521    >(
1522        lwe_ct: &R,
1523        m_expected: R::Element,
1524        sk: &[S],
1525        modop: &Modop,
1526    ) -> f64
1527    where
1528        R: TryConvertFrom1<[S], CiphertextModulus<R::Element>>,
1529        R::Element: Zero + FromPrimitive + PrimInt + NumInfo,
1530    {
1531        let noisy_m = decrypt_lwe(lwe_ct, &sk, modop);
1532        let noise = modop.sub(&m_expected, &noisy_m);
1533        modop
1534            .modulus()
1535            .map_element_to_i64(&noise)
1536            .abs()
1537            .to_f64()
1538            .unwrap()
1539            .log2()
1540    }
1541}