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
 756pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 757    /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
 758    rgsw_cts: Vec<M>,
 759    /// Automorphism keys under ideal rlwe secret
 760    auto_keys: HashMap<usize, M>,
 761    /// LWE key switching key from Q -> Q_{ks}
 762    lwe_ksk: M,
 763    /// Key switching key from user j to ideal secret key s. User j's ksk is at
 764    /// j'th element
 765    ui_to_s_ksks: Vec<M>,
 766    parameters: P,
 767    _phanton: PhantomData<(R, N)>,
 768}
 769
 770pub(super) mod impl_non_interactive_server_key_eval_domain {
 771    use itertools::{izip, Itertools};
 772
 773    use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
 774
 775    use super::*;
 776
 777    impl<M, P, R, N> NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 778        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 779            &self.rgsw_cts
 780        }
 781    }
 782
 783    impl<M, Rng, N>
 784        From<
 785            &SeededNonInteractiveMultiPartyServerKey<
 786                M,
 787                NonInteractiveMultiPartyCrs<Rng::Seed>,
 788                BoolParameters<M::MatElement>,
 789            >,
 790        > for NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 791    where
 792        M: MatrixMut + MatrixEntity + Clone,
 793        Rng: NewWithSeed
 794            + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 795            + RandomFill<<Rng as NewWithSeed>::Seed>,
 796        N: Ntt<Element = M::MatElement> + NttInit<CiphertextModulus<M::MatElement>>,
 797        M::R: RowMut,
 798        M::MatElement: Copy,
 799        Rng::Seed: Clone + Copy + Default,
 800    {
 801        fn from(
 802            value: &SeededNonInteractiveMultiPartyServerKey<
 803                M,
 804                NonInteractiveMultiPartyCrs<Rng::Seed>,
 805                BoolParameters<M::MatElement>,
 806            >,
 807        ) -> Self {
 808            let rlwe_nttop = N::new(value.parameters.rlwe_q(), value.parameters.rlwe_n().0);
 809            let ring_size = value.parameters.rlwe_n().0;
 810
 811            // RGSW cts
 812            // copy over rgsw cts and send to evaluation domain
 813            let mut rgsw_cts = value.rgsw_cts.clone();
 814            rgsw_cts.iter_mut().for_each(|c| {
 815                c.iter_rows_mut()
 816                    .for_each(|ri| rlwe_nttop.forward(ri.as_mut()))
 817            });
 818
 819            // Auto keys
 820            // populate pseudo random part of auto keys. Then send auto keys to
 821            // evaluation domain
 822            let mut auto_keys = HashMap::new();
 823            let auto_seed = value.cr_seed.auto_keys_cts_seed::<Rng>();
 824            let mut auto_prng = Rng::new_with_seed(auto_seed);
 825            let auto_element_dlogs = value.parameters.auto_element_dlogs();
 826            let d_auto = value.parameters.auto_decomposition_count().0;
 827            auto_element_dlogs.iter().for_each(|el| {
 828                let auto_part_b = value
 829                    .auto_keys
 830                    .get(el)
 831                    .expect(&format!("Auto key for element g^{el} not found"));
 832
 833                assert!(auto_part_b.dimension() == (d_auto, ring_size));
 834
 835                let mut auto_ct = M::zeros(d_auto * 2, ring_size);
 836
 837                // sample part A
 838                auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
 839                    RandomFillUniformInModulus::random_fill(
 840                        &mut auto_prng,
 841                        value.parameters.rlwe_q(),
 842                        ri.as_mut(),
 843                    )
 844                });
 845
 846                // Copy over part B
 847                izip!(
 848                    auto_ct.iter_rows_mut().skip(d_auto),
 849                    auto_part_b.iter_rows()
 850                )
 851                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 852
 853                // send to evaluation domain
 854                auto_ct
 855                    .iter_rows_mut()
 856                    .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 857
 858                auto_keys.insert(*el, auto_ct);
 859            });
 860
 861            // LWE ksk
 862            // populate pseudo random part of lwe ciphertexts in ksk and copy over part b
 863            // elements
 864            let lwe_ksk_seed = value.cr_seed.lwe_ksk_cts_seed::<Rng>();
 865            let mut lwe_ksk_prng = Rng::new_with_seed(lwe_ksk_seed);
 866            let mut lwe_ksk = M::zeros(
 867                value.parameters.lwe_decomposition_count().0 * ring_size,
 868                value.parameters.lwe_n().0 + 1,
 869            );
 870            lwe_ksk.iter_rows_mut().for_each(|ri| {
 871                // first element is resereved for part b. Only sample a_is in the rest
 872                RandomFillUniformInModulus::random_fill(
 873                    &mut lwe_ksk_prng,
 874                    value.parameters.lwe_q(),
 875                    &mut ri.as_mut()[1..],
 876                )
 877            });
 878            // copy over part bs
 879            assert!(
 880                value.lwe_ksk.as_ref().len()
 881                    == value.parameters.lwe_decomposition_count().0 * ring_size
 882            );
 883            izip!(value.lwe_ksk.as_ref().iter(), lwe_ksk.iter_rows_mut()).for_each(
 884                |(b_el, lwe_ct)| {
 885                    lwe_ct.as_mut()[0] = *b_el;
 886                },
 887            );
 888
 889            // u_i to s ksk
 890            let d_uitos = value
 891                .parameters
 892                .non_interactive_ui_to_s_key_switch_decomposition_count()
 893                .0;
 894            let total_users = *value.ui_to_s_ksks_key_order.iter().max().unwrap();
 895            let ui_to_s_ksks = (0..total_users + 1)
 896                .map(|user_index| {
 897                    let user_i_seed = value.cr_seed.ui_to_s_ks_seed_for_user_i::<Rng>(user_index);
 898                    let mut prng = Rng::new_with_seed(user_i_seed);
 899
 900                    let mut ksk_ct = M::zeros(d_uitos * 2, ring_size);
 901
 902                    ksk_ct.iter_rows_mut().take(d_uitos).for_each(|r| {
 903                        RandomFillUniformInModulus::random_fill(
 904                            &mut prng,
 905                            value.parameters.rlwe_q(),
 906                            r.as_mut(),
 907                        );
 908                    });
 909
 910                    let incoming_ksk_partb_ref =
 911                        &value.ui_to_s_ksks[value.ui_to_s_ksks_key_order[user_index]];
 912                    assert!(incoming_ksk_partb_ref.dimension() == (d_uitos, ring_size));
 913                    izip!(
 914                        ksk_ct.iter_rows_mut().skip(d_uitos),
 915                        incoming_ksk_partb_ref.iter_rows()
 916                    )
 917                    .for_each(|(to_ri, from_ri)| {
 918                        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 919                    });
 920
 921                    ksk_ct
 922                        .iter_rows_mut()
 923                        .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 924                    ksk_ct
 925                })
 926                .collect_vec();
 927
 928            NonInteractiveServerKeyEvaluationDomain {
 929                rgsw_cts,
 930                auto_keys,
 931                lwe_ksk,
 932                ui_to_s_ksks,
 933                parameters: value.parameters.clone(),
 934                _phanton: PhantomData,
 935            }
 936        }
 937    }
 938}
 939
 940pub struct SeededNonInteractiveMultiPartyServerKey<M: Matrix, S, P> {
 941    /// u_i to s key switching keys in random order
 942    ui_to_s_ksks: Vec<M>,
 943    /// Defines order for u_i to s key switchin keys by storing the index of
 944    /// user j's ksk in `ui_to_s_ksks` at index `j`. Find user j's u_i to s ksk
 945    /// at `ui_to_s_ksks[ui_to_s_ksks_key_order[j]]`
 946    ui_to_s_ksks_key_order: Vec<usize>,
 947    /// RGSW ciphertets
 948    rgsw_cts: Vec<M>,
 949    auto_keys: HashMap<usize, M>,
 950    lwe_ksk: M::R,
 951    cr_seed: S,
 952    parameters: P,
 953}
 954
 955impl<M: Matrix, S, P> SeededNonInteractiveMultiPartyServerKey<M, S, P> {
 956    pub(super) fn new(
 957        ui_to_s_ksks: Vec<M>,
 958        ui_to_s_ksks_key_order: Vec<usize>,
 959        rgsw_cts: Vec<M>,
 960        auto_keys: HashMap<usize, M>,
 961        lwe_ksk: M::R,
 962        cr_seed: S,
 963        parameters: P,
 964    ) -> Self {
 965        Self {
 966            ui_to_s_ksks,
 967            ui_to_s_ksks_key_order,
 968            rgsw_cts,
 969            auto_keys,
 970            lwe_ksk,
 971            cr_seed,
 972            parameters,
 973        }
 974    }
 975}
 976
 977pub(crate) struct ShoupNonInteractiveServerKeyEvaluationDomain<M> {
 978    /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
 979    rgsw_cts: Vec<NormalAndShoup<M>>,
 980    /// Automorphism keys under ideal rlwe secret
 981    auto_keys: HashMap<usize, NormalAndShoup<M>>,
 982    /// LWE key switching key from Q -> Q_{ks}
 983    lwe_ksk: M,
 984    /// Key switching key from user j to ideal secret key s. User j's ksk is at
 985    /// j'th element
 986    ui_to_s_ksks: Vec<NormalAndShoup<M>>,
 987}
 988
 989mod impl_shoup_non_interactive_server_key_eval_domain {
 990    use itertools::Itertools;
 991    use num_traits::{FromPrimitive, PrimInt, ToPrimitive};
 992
 993    use super::*;
 994    use crate::{backend::Modulus, pbs::PbsKey};
 995
 996    impl<M> ShoupNonInteractiveServerKeyEvaluationDomain<M> {
 997        pub(in super::super) fn ui_to_s_ksk(&self, user_id: usize) -> &NormalAndShoup<M> {
 998            &self.ui_to_s_ksks[user_id]
 999        }
1000    }
1001
1002    impl<M: Matrix + ToShoup<Modulus = M::MatElement>, R, N>
1003        From<NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1004        for ShoupNonInteractiveServerKeyEvaluationDomain<M>
1005    where
1006        M::MatElement: FromPrimitive + ToPrimitive + PrimInt,
1007    {
1008        fn from(
1009            value: NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>,
1010        ) -> Self {
1011            let rlwe_q = value.parameters.rlwe_q().q().unwrap();
1012
1013            let rgsw_dim = (
1014                value.parameters.rlwe_rgsw_decomposition_count().0 .0 * 2
1015                    + value.parameters.rlwe_rgsw_decomposition_count().1 .0 * 2,
1016                value.parameters.rlwe_n().0,
1017            );
1018            let rgsw_cts = value
1019                .rgsw_cts
1020                .into_iter()
1021                .map(|m| {
1022                    assert!(m.dimension() == rgsw_dim);
1023                    NormalAndShoup::new_with_modulus(m, rlwe_q)
1024                })
1025                .collect_vec();
1026
1027            let auto_dim = (
1028                value.parameters.auto_decomposition_count().0 * 2,
1029                value.parameters.rlwe_n().0,
1030            );
1031            let mut auto_keys = HashMap::new();
1032            value.auto_keys.into_iter().for_each(|(k, v)| {
1033                assert!(v.dimension() == auto_dim);
1034                auto_keys.insert(k, NormalAndShoup::new_with_modulus(v, rlwe_q));
1035            });
1036
1037            let ui_ks_dim = (
1038                value
1039                    .parameters
1040                    .non_interactive_ui_to_s_key_switch_decomposition_count()
1041                    .0
1042                    * 2,
1043                value.parameters.rlwe_n().0,
1044            );
1045            let ui_to_s_ksks = value
1046                .ui_to_s_ksks
1047                .into_iter()
1048                .map(|m| {
1049                    assert!(m.dimension() == ui_ks_dim);
1050                    NormalAndShoup::new_with_modulus(m, rlwe_q)
1051                })
1052                .collect_vec();
1053
1054            assert!(
1055                value.lwe_ksk.dimension()
1056                    == (
1057                        value.parameters.rlwe_n().0 * value.parameters.lwe_decomposition_count().0,
1058                        value.parameters.lwe_n().0 + 1
1059                    )
1060            );
1061
1062            Self {
1063                rgsw_cts,
1064                auto_keys,
1065                lwe_ksk: value.lwe_ksk,
1066                ui_to_s_ksks,
1067            }
1068        }
1069    }
1070
1071    impl<M: Matrix> PbsKey for ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1072        type AutoKey = NormalAndShoup<M>;
1073        type LweKskKey = M;
1074        type RgswCt = NormalAndShoup<M>;
1075
1076        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1077            let d = self.auto_keys.get(&k).unwrap();
1078            d
1079        }
1080        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1081            &self.rgsw_cts[si]
1082        }
1083
1084        fn lwe_ksk(&self) -> &Self::LweKskKey {
1085            &self.lwe_ksk
1086        }
1087    }
1088}
1089
1090/// Server key in evaluation domain with Shoup representations
1091pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
1092    /// Rgsw cts of LWE secret elements
1093    rgsw_cts: Vec<NormalAndShoup<M>>,
1094    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
1095    /// to -g is at 0
1096    galois_keys: HashMap<usize, NormalAndShoup<M>>,
1097    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
1098    lwe_ksk: M,
1099}
1100
1101mod shoup_server_key_eval_domain {
1102    use itertools::{izip, Itertools};
1103    use num_traits::{FromPrimitive, PrimInt};
1104
1105    use crate::{backend::Modulus, pbs::PbsKey};
1106
1107    use super::*;
1108
1109    impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
1110        From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1111        for ShoupServerKeyEvaluationDomain<M>
1112    where
1113        <M as Matrix>::R: RowMut,
1114        M::MatElement: PrimInt + FromPrimitive,
1115    {
1116        fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
1117            let q = value.parameters.rlwe_q().q().unwrap();
1118            // Rgsw ciphertexts
1119            let rgsw_cts = value
1120                .rgsw_cts
1121                .into_iter()
1122                .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
1123                .collect_vec();
1124
1125            let mut auto_keys = HashMap::new();
1126            value.galois_keys.into_iter().for_each(|(index, key)| {
1127                auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
1128            });
1129
1130            Self {
1131                rgsw_cts,
1132                galois_keys: auto_keys,
1133                lwe_ksk: value.lwe_ksk,
1134            }
1135        }
1136    }
1137
1138    impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
1139        type AutoKey = NormalAndShoup<M>;
1140        type LweKskKey = M;
1141        type RgswCt = NormalAndShoup<M>;
1142
1143        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1144            self.galois_keys.get(&k).unwrap()
1145        }
1146        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1147            &self.rgsw_cts[si]
1148        }
1149
1150        fn lwe_ksk(&self) -> &Self::LweKskKey {
1151            &self.lwe_ksk
1152        }
1153    }
1154}
1155
1156pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M: Matrix, S> {
1157    /// (ak*si + e + \beta ui, ak*si + e)
1158    ni_rgsw_cts: (Vec<M>, Vec<M>),
1159    ui_to_s_ksk: M,
1160    others_ksk_zero_encs: Vec<M>,
1161
1162    auto_keys_share: HashMap<usize, M>,
1163    lwe_ksk_share: M::R,
1164
1165    user_index: usize,
1166    cr_seed: S,
1167}
1168
1169mod impl_common_ref_non_interactive_multi_party_server_share {
1170    use super::*;
1171
1172    impl<M: Matrix, S> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, S> {
1173        pub(in super::super) fn new(
1174            ni_rgsw_cts: (Vec<M>, Vec<M>),
1175            ui_to_s_ksk: M,
1176            others_ksk_zero_encs: Vec<M>,
1177            auto_keys_share: HashMap<usize, M>,
1178            lwe_ksk_share: M::R,
1179            user_index: usize,
1180            cr_seed: S,
1181        ) -> Self {
1182            Self {
1183                ni_rgsw_cts,
1184                ui_to_s_ksk,
1185                others_ksk_zero_encs,
1186                auto_keys_share,
1187                lwe_ksk_share,
1188                user_index,
1189                cr_seed,
1190            }
1191        }
1192
1193        pub(in super::super) fn ni_rgsw_cts(&self) -> &(Vec<M>, Vec<M>) {
1194            &self.ni_rgsw_cts
1195        }
1196
1197        pub(in super::super) fn ui_to_s_ksk(&self) -> &M {
1198            &self.ui_to_s_ksk
1199        }
1200
1201        pub(in super::super) fn user_index(&self) -> usize {
1202            self.user_index
1203        }
1204
1205        pub(in super::super) fn auto_keys_share(&self) -> &HashMap<usize, M> {
1206            &self.auto_keys_share
1207        }
1208
1209        pub(in super::super) fn lwe_ksk_share(&self) -> &M::R {
1210            &self.lwe_ksk_share
1211        }
1212
1213        pub(in super::super) fn ui_to_s_ksk_zero_encs_for_user_i(&self, user_i: usize) -> &M {
1214            assert!(user_i != self.user_index);
1215            if user_i < self.user_index {
1216                &self.others_ksk_zero_encs[user_i]
1217            } else {
1218                &self.others_ksk_zero_encs[user_i - 1]
1219            }
1220        }
1221    }
1222}
1223
1224/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
1225pub(crate) struct NormalAndShoup<M>(M, M);
1226
1227impl<M: ToShoup> NormalAndShoup<M> {
1228    fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
1229        let value_shoup = M::to_shoup(&value, modulus);
1230        NormalAndShoup(value, value_shoup)
1231    }
1232}
1233
1234impl<M> AsRef<M> for NormalAndShoup<M> {
1235    fn as_ref(&self) -> &M {
1236        &self.0
1237    }
1238}
1239
1240impl<M> WithShoupRepr for NormalAndShoup<M> {
1241    type M = M;
1242    fn shoup_repr(&self) -> &Self::M {
1243        &self.1
1244    }
1245}
1246
1247pub(super) mod tests {
1248    use itertools::izip;
1249    use num_traits::{FromPrimitive, PrimInt, ToPrimitive, Zero};
1250
1251    use crate::{
1252        backend::{GetModulus, Modulus},
1253        bool::ClientKey,
1254        lwe::decrypt_lwe,
1255        parameters::CiphertextModulus,
1256        utils::TryConvertFrom1,
1257        ArithmeticOps, Row,
1258    };
1259
1260    use super::SinglePartyClientKey;
1261
1262    pub(crate) fn ideal_sk_rlwe(cks: &[ClientKey]) -> Vec<i32> {
1263        let mut ideal_rlwe_sk = cks[0].sk_rlwe();
1264        cks.iter().skip(1).for_each(|k| {
1265            let sk_rlwe = k.sk_rlwe();
1266            izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
1267                *a = *a + b;
1268            });
1269        });
1270        ideal_rlwe_sk
1271    }
1272
1273    pub(crate) fn ideal_sk_lwe(cks: &[ClientKey]) -> Vec<i32> {
1274        let mut ideal_rlwe_sk = cks[0].sk_lwe();
1275        cks.iter().skip(1).for_each(|k| {
1276            let sk_rlwe = k.sk_lwe();
1277            izip!(ideal_rlwe_sk.iter_mut(), sk_rlwe.iter()).for_each(|(a, b)| {
1278                *a = *a + b;
1279            });
1280        });
1281        ideal_rlwe_sk
1282    }
1283
1284    pub(crate) fn measure_noise_lwe<
1285        R: Row,
1286        S,
1287        Modop: ArithmeticOps<Element = R::Element>
1288            + GetModulus<M = CiphertextModulus<R::Element>, Element = R::Element>,
1289    >(
1290        lwe_ct: &R,
1291        m_expected: R::Element,
1292        sk: &[S],
1293        modop: &Modop,
1294    ) -> f64
1295    where
1296        R: TryConvertFrom1<[S], CiphertextModulus<R::Element>>,
1297        R::Element: Zero + FromPrimitive + PrimInt,
1298    {
1299        let noisy_m = decrypt_lwe(lwe_ct, &sk, modop);
1300        let noise = modop.sub(&m_expected, &noisy_m);
1301        modop
1302            .modulus()
1303            .map_element_to_i64(&noise)
1304            .abs()
1305            .to_f64()
1306            .unwrap()
1307            .log2()
1308    }
1309}