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