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