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