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    rgsw_cts: Vec<M>,
 318    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 319    /// to -g is at 0
 320    auto_keys: HashMap<usize, M>,
 321    lwe_ksk: M::R,
 322    /// Common reference seed
 323    cr_seed: S,
 324    parameters: P,
 325}
 326
 327impl<M: Matrix, P, S> CommonReferenceSeededMultiPartyServerKeyShare<M, P, S> {
 328    pub(super) fn new(
 329        rgsw_cts: Vec<M>,
 330        auto_keys: HashMap<usize, M>,
 331        lwe_ksk: M::R,
 332        cr_seed: S,
 333        parameters: P,
 334    ) -> Self {
 335        CommonReferenceSeededMultiPartyServerKeyShare {
 336            rgsw_cts,
 337            auto_keys,
 338            lwe_ksk,
 339            cr_seed,
 340            parameters,
 341        }
 342    }
 343
 344    pub(super) fn cr_seed(&self) -> &S {
 345        &self.cr_seed
 346    }
 347
 348    pub(super) fn parameters(&self) -> &P {
 349        &self.parameters
 350    }
 351
 352    pub(super) fn auto_keys(&self) -> &HashMap<usize, M> {
 353        &self.auto_keys
 354    }
 355
 356    pub(super) fn rgsw_cts(&self) -> &[M] {
 357        &self.rgsw_cts
 358    }
 359
 360    pub(super) fn lwe_ksk(&self) -> &M::R {
 361        &self.lwe_ksk
 362    }
 363}
 364
 365/// CRS seeded MultiParty server key
 366pub struct SeededMultiPartyServerKey<M: Matrix, S, P> {
 367    rgsw_cts: Vec<M>,
 368    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 369    /// to -g is at 0
 370    auto_keys: HashMap<usize, M>,
 371    lwe_ksk: M::R,
 372    cr_seed: S,
 373    parameters: P,
 374}
 375
 376impl<M: Matrix, S, P> SeededMultiPartyServerKey<M, S, P> {
 377    pub(super) fn new(
 378        rgsw_cts: Vec<M>,
 379        auto_keys: HashMap<usize, M>,
 380        lwe_ksk: M::R,
 381        cr_seed: S,
 382        parameters: P,
 383    ) -> Self {
 384        SeededMultiPartyServerKey {
 385            rgsw_cts,
 386            auto_keys,
 387            lwe_ksk,
 388            cr_seed,
 389            parameters,
 390        }
 391    }
 392
 393    pub(super) fn rgsw_cts(&self) -> &[M] {
 394        &self.rgsw_cts
 395    }
 396}
 397
 398/// Seeded single party server key
 399pub struct SeededSinglePartyServerKey<M: Matrix, P, S> {
 400    /// Rgsw cts of LWE secret elements
 401    pub(crate) rgsw_cts: Vec<M>,
 402    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 403    /// to -g is at 0
 404    pub(crate) auto_keys: HashMap<usize, M>,
 405    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
 406    pub(crate) lwe_ksk: M::R,
 407    /// Parameters
 408    pub(crate) parameters: P,
 409    /// Main seed
 410    pub(crate) seed: S,
 411}
 412impl<M: Matrix, S> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, S> {
 413    pub(super) fn from_raw(
 414        auto_keys: HashMap<usize, M>,
 415        rgsw_cts: Vec<M>,
 416        lwe_ksk: M::R,
 417        parameters: BoolParameters<M::MatElement>,
 418        seed: S,
 419    ) -> Self {
 420        // sanity checks
 421        auto_keys.iter().for_each(|v| {
 422            assert!(
 423                v.1.dimension()
 424                    == (
 425                        parameters.auto_decomposition_count().0,
 426                        parameters.rlwe_n().0
 427                    )
 428            )
 429        });
 430
 431        let (part_a_d, part_b_d) = parameters.rlwe_rgsw_decomposition_count();
 432        rgsw_cts.iter().for_each(|v| {
 433            assert!(v.dimension() == (part_a_d.0 * 2 + part_b_d.0, parameters.rlwe_n().0))
 434        });
 435        assert!(
 436            lwe_ksk.as_ref().len()
 437                == (parameters.lwe_decomposition_count().0 * parameters.rlwe_n().0)
 438        );
 439
 440        SeededSinglePartyServerKey {
 441            rgsw_cts,
 442            auto_keys,
 443            lwe_ksk,
 444            parameters,
 445            seed,
 446        }
 447    }
 448}
 449
 450/// Server key in evaluation domain
 451pub(crate) struct ServerKeyEvaluationDomain<M, P, R, N> {
 452    /// Rgsw cts of LWE secret elements
 453    rgsw_cts: Vec<M>,
 454    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
 455    /// to -g is at 0
 456    galois_keys: HashMap<usize, M>,
 457    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
 458    lwe_ksk: M,
 459    parameters: P,
 460    _phanton: PhantomData<(R, N)>,
 461}
 462
 463pub(super) mod impl_server_key_eval_domain {
 464    use itertools::{izip, Itertools};
 465
 466    use crate::{
 467        evaluator::MultiPartyCrs,
 468        ntt::{Ntt, NttInit},
 469        pbs::PbsKey,
 470        random::RandomFill,
 471    };
 472
 473    use super::*;
 474
 475    impl<M, Mod, R, N> ServerKeyEvaluationDomain<M, Mod, R, N> {
 476        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 477            &self.rgsw_cts
 478        }
 479    }
 480
 481    impl<
 482            M: MatrixMut + MatrixEntity,
 483            R: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 484                + NewWithSeed,
 485            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
 486        > From<&SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>>
 487        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>
 488    where
 489        <M as Matrix>::R: RowMut,
 490        M::MatElement: Copy,
 491        R::Seed: Clone,
 492    {
 493        fn from(
 494            value: &SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, R::Seed>,
 495        ) -> Self {
 496            let mut main_prng = R::new_with_seed(value.seed.clone());
 497            let parameters = &value.parameters;
 498            let g = parameters.g() as isize;
 499            let ring_size = value.parameters.rlwe_n().0;
 500            let lwe_n = value.parameters.lwe_n().0;
 501            let rlwe_q = value.parameters.rlwe_q();
 502            let lwq_q = value.parameters.lwe_q();
 503
 504            let nttop = N::new(rlwe_q, ring_size);
 505
 506            // galois keys
 507            let mut auto_keys = HashMap::new();
 508            let auto_decomp_count = parameters.auto_decomposition_count().0;
 509            let auto_element_dlogs = parameters.auto_element_dlogs();
 510            for i in auto_element_dlogs.into_iter() {
 511                let seeded_auto_key = value.auto_keys.get(&i).unwrap();
 512                assert!(seeded_auto_key.dimension() == (auto_decomp_count, ring_size));
 513
 514                let mut data = M::zeros(auto_decomp_count * 2, ring_size);
 515
 516                // sample RLWE'_A(-s(X^k))
 517                data.iter_rows_mut().take(auto_decomp_count).for_each(|ri| {
 518                    RandomFillUniformInModulus::random_fill(&mut main_prng, &rlwe_q, ri.as_mut())
 519                });
 520
 521                // copy over RLWE'B_(-s(X^k))
 522                izip!(
 523                    data.iter_rows_mut().skip(auto_decomp_count),
 524                    seeded_auto_key.iter_rows()
 525                )
 526                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 527
 528                // Send to Evaluation domain
 529                data.iter_rows_mut()
 530                    .for_each(|ri| nttop.forward(ri.as_mut()));
 531
 532                auto_keys.insert(i, data);
 533            }
 534
 535            // RGSW ciphertexts
 536            let (rlrg_a_decomp, rlrg_b_decomp) = parameters.rlwe_rgsw_decomposition_count();
 537            let rgsw_cts = value
 538                .rgsw_cts
 539                .iter()
 540                .map(|seeded_rgsw_si| {
 541                    assert!(
 542                        seeded_rgsw_si.dimension()
 543                            == (rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0, ring_size)
 544                    );
 545
 546                    let mut data = M::zeros(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0 * 2, ring_size);
 547
 548                    // copy over RLWE'(-sm)
 549                    izip!(
 550                        data.iter_rows_mut().take(rlrg_a_decomp.0 * 2),
 551                        seeded_rgsw_si.iter_rows().take(rlrg_a_decomp.0 * 2)
 552                    )
 553                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 554
 555                    // sample RLWE'_A(m)
 556                    data.iter_rows_mut()
 557                        .skip(rlrg_a_decomp.0 * 2)
 558                        .take(rlrg_b_decomp.0)
 559                        .for_each(|ri| {
 560                            RandomFillUniformInModulus::random_fill(
 561                                &mut main_prng,
 562                                &rlwe_q,
 563                                ri.as_mut(),
 564                            )
 565                        });
 566
 567                    // copy over RLWE'_B(m)
 568                    izip!(
 569                        data.iter_rows_mut()
 570                            .skip(rlrg_a_decomp.0 * 2 + rlrg_b_decomp.0),
 571                        seeded_rgsw_si.iter_rows().skip(rlrg_a_decomp.0 * 2)
 572                    )
 573                    .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 574
 575                    // send polynomials to evaluation domain
 576                    data.iter_rows_mut()
 577                        .for_each(|ri| nttop.forward(ri.as_mut()));
 578
 579                    data
 580                })
 581                .collect_vec();
 582
 583            // LWE ksk
 584            let lwe_ksk = {
 585                let d = parameters.lwe_decomposition_count().0;
 586                assert!(value.lwe_ksk.as_ref().len() == d * ring_size);
 587
 588                let mut data = M::zeros(d * ring_size, lwe_n + 1);
 589                izip!(data.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
 590                    |(lwe_i, bi)| {
 591                        RandomFillUniformInModulus::random_fill(
 592                            &mut main_prng,
 593                            &lwq_q,
 594                            &mut lwe_i.as_mut()[1..],
 595                        );
 596                        lwe_i.as_mut()[0] = *bi;
 597                    },
 598                );
 599
 600                data
 601            };
 602
 603            ServerKeyEvaluationDomain {
 604                rgsw_cts,
 605                galois_keys: auto_keys,
 606                lwe_ksk,
 607                parameters: parameters.clone(),
 608                _phanton: PhantomData,
 609            }
 610        }
 611    }
 612
 613    impl<
 614            M: MatrixMut + MatrixEntity,
 615            Rng: NewWithSeed,
 616            N: NttInit<CiphertextModulus<M::MatElement>> + Ntt<Element = M::MatElement>,
 617        >
 618        From<&SeededMultiPartyServerKey<M, MultiPartyCrs<Rng::Seed>, BoolParameters<M::MatElement>>>
 619        for ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 620    where
 621        <M as Matrix>::R: RowMut,
 622        Rng::Seed: Copy + Default,
 623        Rng: RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 624            + RandomFill<Rng::Seed>,
 625        M::MatElement: Copy,
 626    {
 627        fn from(
 628            value: &SeededMultiPartyServerKey<
 629                M,
 630                MultiPartyCrs<Rng::Seed>,
 631                BoolParameters<M::MatElement>,
 632            >,
 633        ) -> Self {
 634            let g = value.parameters.g() as isize;
 635            let rlwe_n = value.parameters.rlwe_n().0;
 636            let lwe_n = value.parameters.lwe_n().0;
 637            let rlwe_q = value.parameters.rlwe_q();
 638            let lwe_q = value.parameters.lwe_q();
 639
 640            let rlwe_nttop = N::new(rlwe_q, rlwe_n);
 641
 642            // auto keys
 643            let mut auto_keys = HashMap::new();
 644            {
 645                let mut auto_prng = Rng::new_with_seed(value.cr_seed.auto_keys_cts_seed::<Rng>());
 646                let auto_d_count = value.parameters.auto_decomposition_count().0;
 647                let auto_element_dlogs = value.parameters.auto_element_dlogs();
 648                for i in auto_element_dlogs.into_iter() {
 649                    let mut key = M::zeros(auto_d_count * 2, rlwe_n);
 650
 651                    // sample a
 652                    key.iter_rows_mut().take(auto_d_count).for_each(|ri| {
 653                        RandomFillUniformInModulus::random_fill(
 654                            &mut auto_prng,
 655                            &rlwe_q,
 656                            ri.as_mut(),
 657                        )
 658                    });
 659
 660                    let key_part_b = value.auto_keys.get(&i).unwrap();
 661                    assert!(key_part_b.dimension() == (auto_d_count, rlwe_n));
 662                    izip!(
 663                        key.iter_rows_mut().skip(auto_d_count),
 664                        key_part_b.iter_rows()
 665                    )
 666                    .for_each(|(to_ri, from_ri)| {
 667                        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 668                    });
 669
 670                    // send to evaluation domain
 671                    key.iter_rows_mut()
 672                        .for_each(|ri| rlwe_nttop.forward(ri.as_mut()));
 673
 674                    auto_keys.insert(i, key);
 675                }
 676            }
 677
 678            // rgsw cts
 679            let (rlrg_d_a, rlrg_d_b) = value.parameters.rlwe_rgsw_decomposition_count();
 680            let rgsw_ct_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
 681            let rgsw_cts = value
 682                .rgsw_cts
 683                .iter()
 684                .map(|ct_i_in| {
 685                    assert!(ct_i_in.dimension() == (rgsw_ct_out, rlwe_n));
 686                    let mut eval_ct_i_out = M::zeros(rgsw_ct_out, rlwe_n);
 687
 688                    izip!(eval_ct_i_out.iter_rows_mut(), ct_i_in.iter_rows()).for_each(
 689                        |(to_ri, from_ri)| {
 690                            to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 691                            rlwe_nttop.forward(to_ri.as_mut());
 692                        },
 693                    );
 694
 695                    eval_ct_i_out
 696                })
 697                .collect_vec();
 698
 699            // lwe ksk
 700            let mut lwe_ksk_prng = Rng::new_with_seed(value.cr_seed.lwe_ksk_cts_seed_seed::<Rng>());
 701            let d_lwe = value.parameters.lwe_decomposition_count().0;
 702            let mut lwe_ksk = M::zeros(rlwe_n * d_lwe, lwe_n + 1);
 703            izip!(lwe_ksk.iter_rows_mut(), value.lwe_ksk.as_ref().iter()).for_each(
 704                |(lwe_i, bi)| {
 705                    RandomFillUniformInModulus::random_fill(
 706                        &mut lwe_ksk_prng,
 707                        &lwe_q,
 708                        &mut lwe_i.as_mut()[1..],
 709                    );
 710                    lwe_i.as_mut()[0] = *bi;
 711                },
 712            );
 713
 714            ServerKeyEvaluationDomain {
 715                rgsw_cts,
 716                galois_keys: auto_keys,
 717                lwe_ksk,
 718                parameters: value.parameters.clone(),
 719                _phanton: PhantomData,
 720            }
 721        }
 722    }
 723
 724    impl<M: Matrix, P, R, N> PbsKey for ServerKeyEvaluationDomain<M, P, R, N> {
 725        type AutoKey = M;
 726        type LweKskKey = M;
 727        type RgswCt = M;
 728
 729        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
 730            self.galois_keys.get(&k).unwrap()
 731        }
 732        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
 733            &self.rgsw_cts[si]
 734        }
 735
 736        fn lwe_ksk(&self) -> &Self::LweKskKey {
 737            &self.lwe_ksk
 738        }
 739    }
 740}
 741
 742pub(crate) struct NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 743    /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
 744    rgsw_cts: Vec<M>,
 745    /// Automorphism keys under ideal rlwe secret
 746    auto_keys: HashMap<usize, M>,
 747    /// LWE key switching key from Q -> Q_{ks}
 748    lwe_ksk: M,
 749    /// Key switching key from user j to ideal secret key s. User j's ksk is at
 750    /// j'th element
 751    ui_to_s_ksks: Vec<M>,
 752    parameters: P,
 753    _phanton: PhantomData<(R, N)>,
 754}
 755
 756pub(super) mod impl_non_interactive_server_key_eval_domain {
 757    use itertools::{izip, Itertools};
 758
 759    use crate::{bool::evaluator::NonInteractiveMultiPartyCrs, random::RandomFill, Ntt, NttInit};
 760
 761    use super::*;
 762
 763    impl<M, P, R, N> NonInteractiveServerKeyEvaluationDomain<M, P, R, N> {
 764        pub(in super::super) fn rgsw_cts(&self) -> &[M] {
 765            &self.rgsw_cts
 766        }
 767    }
 768
 769    impl<M, Rng, N>
 770        From<
 771            &SeededNonInteractiveMultiPartyServerKey<
 772                M,
 773                NonInteractiveMultiPartyCrs<Rng::Seed>,
 774                BoolParameters<M::MatElement>,
 775            >,
 776        > for NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, Rng, N>
 777    where
 778        M: MatrixMut + MatrixEntity + Clone,
 779        Rng: NewWithSeed
 780            + RandomFillUniformInModulus<[M::MatElement], CiphertextModulus<M::MatElement>>
 781            + RandomFill<<Rng as NewWithSeed>::Seed>,
 782        N: Ntt<Element = M::MatElement> + NttInit<CiphertextModulus<M::MatElement>>,
 783        M::R: RowMut,
 784        M::MatElement: Copy,
 785        Rng::Seed: Clone + Copy + Default,
 786    {
 787        fn from(
 788            value: &SeededNonInteractiveMultiPartyServerKey<
 789                M,
 790                NonInteractiveMultiPartyCrs<Rng::Seed>,
 791                BoolParameters<M::MatElement>,
 792            >,
 793        ) -> Self {
 794            let rlwe_nttop = N::new(value.parameters.rlwe_q(), value.parameters.rlwe_n().0);
 795            let ring_size = value.parameters.rlwe_n().0;
 796
 797            // RGSW cts
 798            // copy over rgsw cts and send to evaluation domain
 799            let mut rgsw_cts = value.rgsw_cts.clone();
 800            rgsw_cts.iter_mut().for_each(|c| {
 801                c.iter_rows_mut()
 802                    .for_each(|ri| rlwe_nttop.forward(ri.as_mut()))
 803            });
 804
 805            // Auto keys
 806            // populate pseudo random part of auto keys. Then send auto keys to
 807            // evaluation domain
 808            let mut auto_keys = HashMap::new();
 809            let auto_seed = value.cr_seed.auto_keys_cts_seed::<Rng>();
 810            let mut auto_prng = Rng::new_with_seed(auto_seed);
 811            let auto_element_dlogs = value.parameters.auto_element_dlogs();
 812            let d_auto = value.parameters.auto_decomposition_count().0;
 813            auto_element_dlogs.iter().for_each(|el| {
 814                let auto_part_b = value
 815                    .auto_keys
 816                    .get(el)
 817                    .expect(&format!("Auto key for element g^{el} not found"));
 818
 819                assert!(auto_part_b.dimension() == (d_auto, ring_size));
 820
 821                let mut auto_ct = M::zeros(d_auto * 2, ring_size);
 822
 823                // sample part A
 824                auto_ct.iter_rows_mut().take(d_auto).for_each(|ri| {
 825                    RandomFillUniformInModulus::random_fill(
 826                        &mut auto_prng,
 827                        value.parameters.rlwe_q(),
 828                        ri.as_mut(),
 829                    )
 830                });
 831
 832                // Copy over part B
 833                izip!(
 834                    auto_ct.iter_rows_mut().skip(d_auto),
 835                    auto_part_b.iter_rows()
 836                )
 837                .for_each(|(to_ri, from_ri)| to_ri.as_mut().copy_from_slice(from_ri.as_ref()));
 838
 839                // send to evaluation domain
 840                auto_ct
 841                    .iter_rows_mut()
 842                    .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 843
 844                auto_keys.insert(*el, auto_ct);
 845            });
 846
 847            // LWE ksk
 848            // populate pseudo random part of lwe ciphertexts in ksk and copy over part b
 849            // elements
 850            let lwe_ksk_seed = value.cr_seed.lwe_ksk_cts_seed::<Rng>();
 851            let mut lwe_ksk_prng = Rng::new_with_seed(lwe_ksk_seed);
 852            let mut lwe_ksk = M::zeros(
 853                value.parameters.lwe_decomposition_count().0 * ring_size,
 854                value.parameters.lwe_n().0 + 1,
 855            );
 856            lwe_ksk.iter_rows_mut().for_each(|ri| {
 857                // first element is resereved for part b. Only sample a_is in the rest
 858                RandomFillUniformInModulus::random_fill(
 859                    &mut lwe_ksk_prng,
 860                    value.parameters.lwe_q(),
 861                    &mut ri.as_mut()[1..],
 862                )
 863            });
 864            // copy over part bs
 865            assert!(
 866                value.lwe_ksk.as_ref().len()
 867                    == value.parameters.lwe_decomposition_count().0 * ring_size
 868            );
 869            izip!(value.lwe_ksk.as_ref().iter(), lwe_ksk.iter_rows_mut()).for_each(
 870                |(b_el, lwe_ct)| {
 871                    lwe_ct.as_mut()[0] = *b_el;
 872                },
 873            );
 874
 875            // u_i to s ksk
 876            let d_uitos = value
 877                .parameters
 878                .non_interactive_ui_to_s_key_switch_decomposition_count()
 879                .0;
 880            let total_users = *value.ui_to_s_ksks_key_order.iter().max().unwrap();
 881            let ui_to_s_ksks = (0..total_users + 1)
 882                .map(|user_index| {
 883                    let user_i_seed = value.cr_seed.ui_to_s_ks_seed_for_user_i::<Rng>(user_index);
 884                    let mut prng = Rng::new_with_seed(user_i_seed);
 885
 886                    let mut ksk_ct = M::zeros(d_uitos * 2, ring_size);
 887
 888                    ksk_ct.iter_rows_mut().take(d_uitos).for_each(|r| {
 889                        RandomFillUniformInModulus::random_fill(
 890                            &mut prng,
 891                            value.parameters.rlwe_q(),
 892                            r.as_mut(),
 893                        );
 894                    });
 895
 896                    let incoming_ksk_partb_ref =
 897                        &value.ui_to_s_ksks[value.ui_to_s_ksks_key_order[user_index]];
 898                    assert!(incoming_ksk_partb_ref.dimension() == (d_uitos, ring_size));
 899                    izip!(
 900                        ksk_ct.iter_rows_mut().skip(d_uitos),
 901                        incoming_ksk_partb_ref.iter_rows()
 902                    )
 903                    .for_each(|(to_ri, from_ri)| {
 904                        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 905                    });
 906
 907                    ksk_ct
 908                        .iter_rows_mut()
 909                        .for_each(|r| rlwe_nttop.forward(r.as_mut()));
 910                    ksk_ct
 911                })
 912                .collect_vec();
 913
 914            NonInteractiveServerKeyEvaluationDomain {
 915                rgsw_cts,
 916                auto_keys,
 917                lwe_ksk,
 918                ui_to_s_ksks,
 919                parameters: value.parameters.clone(),
 920                _phanton: PhantomData,
 921            }
 922        }
 923    }
 924}
 925
 926pub struct SeededNonInteractiveMultiPartyServerKey<M: Matrix, S, P> {
 927    /// u_i to s key switching keys in random order
 928    ui_to_s_ksks: Vec<M>,
 929    /// Defines order for u_i to s key switchin keys by storing the index of
 930    /// user j's ksk in `ui_to_s_ksks` at index `j`. Find user j's u_i to s ksk
 931    /// at `ui_to_s_ksks[ui_to_s_ksks_key_order[j]]`
 932    ui_to_s_ksks_key_order: Vec<usize>,
 933    /// RGSW ciphertets
 934    rgsw_cts: Vec<M>,
 935    auto_keys: HashMap<usize, M>,
 936    lwe_ksk: M::R,
 937    cr_seed: S,
 938    parameters: P,
 939}
 940
 941impl<M: Matrix, S, P> SeededNonInteractiveMultiPartyServerKey<M, S, P> {
 942    pub(super) fn new(
 943        ui_to_s_ksks: Vec<M>,
 944        ui_to_s_ksks_key_order: Vec<usize>,
 945        rgsw_cts: Vec<M>,
 946        auto_keys: HashMap<usize, M>,
 947        lwe_ksk: M::R,
 948        cr_seed: S,
 949        parameters: P,
 950    ) -> Self {
 951        Self {
 952            ui_to_s_ksks,
 953            ui_to_s_ksks_key_order,
 954            rgsw_cts,
 955            auto_keys,
 956            lwe_ksk,
 957            cr_seed,
 958            parameters,
 959        }
 960    }
 961}
 962
 963pub(crate) struct ShoupNonInteractiveServerKeyEvaluationDomain<M> {
 964    /// RGSW ciphertexts ideal lwe secret key elements under ideal rlwe secret
 965    rgsw_cts: Vec<NormalAndShoup<M>>,
 966    /// Automorphism keys under ideal rlwe secret
 967    auto_keys: HashMap<usize, NormalAndShoup<M>>,
 968    /// LWE key switching key from Q -> Q_{ks}
 969    lwe_ksk: M,
 970    /// Key switching key from user j to ideal secret key s. User j's ksk is at
 971    /// j'th element
 972    ui_to_s_ksks: Vec<NormalAndShoup<M>>,
 973}
 974
 975mod impl_shoup_non_interactive_server_key_eval_domain {
 976    use itertools::Itertools;
 977    use num_traits::{FromPrimitive, PrimInt, ToPrimitive};
 978
 979    use super::*;
 980    use crate::{backend::Modulus, pbs::PbsKey};
 981
 982    impl<M> ShoupNonInteractiveServerKeyEvaluationDomain<M> {
 983        pub(in super::super) fn ui_to_s_ksk(&self, user_id: usize) -> &NormalAndShoup<M> {
 984            &self.ui_to_s_ksks[user_id]
 985        }
 986    }
 987
 988    impl<M: Matrix + ToShoup<Modulus = M::MatElement>, R, N>
 989        From<NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
 990        for ShoupNonInteractiveServerKeyEvaluationDomain<M>
 991    where
 992        M::MatElement: FromPrimitive + ToPrimitive + PrimInt,
 993    {
 994        fn from(
 995            value: NonInteractiveServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>,
 996        ) -> Self {
 997            let rlwe_q = value.parameters.rlwe_q().q().unwrap();
 998
 999            let rgsw_dim = (
1000                value.parameters.rlwe_rgsw_decomposition_count().0 .0 * 2
1001                    + value.parameters.rlwe_rgsw_decomposition_count().1 .0 * 2,
1002                value.parameters.rlwe_n().0,
1003            );
1004            let rgsw_cts = value
1005                .rgsw_cts
1006                .into_iter()
1007                .map(|m| {
1008                    assert!(m.dimension() == rgsw_dim);
1009                    NormalAndShoup::new_with_modulus(m, rlwe_q)
1010                })
1011                .collect_vec();
1012
1013            let auto_dim = (
1014                value.parameters.auto_decomposition_count().0 * 2,
1015                value.parameters.rlwe_n().0,
1016            );
1017            let mut auto_keys = HashMap::new();
1018            value.auto_keys.into_iter().for_each(|(k, v)| {
1019                assert!(v.dimension() == auto_dim);
1020                auto_keys.insert(k, NormalAndShoup::new_with_modulus(v, rlwe_q));
1021            });
1022
1023            let ui_ks_dim = (
1024                value
1025                    .parameters
1026                    .non_interactive_ui_to_s_key_switch_decomposition_count()
1027                    .0
1028                    * 2,
1029                value.parameters.rlwe_n().0,
1030            );
1031            let ui_to_s_ksks = value
1032                .ui_to_s_ksks
1033                .into_iter()
1034                .map(|m| {
1035                    assert!(m.dimension() == ui_ks_dim);
1036                    NormalAndShoup::new_with_modulus(m, rlwe_q)
1037                })
1038                .collect_vec();
1039
1040            assert!(
1041                value.lwe_ksk.dimension()
1042                    == (
1043                        value.parameters.rlwe_n().0 * value.parameters.lwe_decomposition_count().0,
1044                        value.parameters.lwe_n().0 + 1
1045                    )
1046            );
1047
1048            Self {
1049                rgsw_cts,
1050                auto_keys,
1051                lwe_ksk: value.lwe_ksk,
1052                ui_to_s_ksks,
1053            }
1054        }
1055    }
1056
1057    impl<M: Matrix> PbsKey for ShoupNonInteractiveServerKeyEvaluationDomain<M> {
1058        type AutoKey = NormalAndShoup<M>;
1059        type LweKskKey = M;
1060        type RgswCt = NormalAndShoup<M>;
1061
1062        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1063            let d = self.auto_keys.get(&k).unwrap();
1064            d
1065        }
1066        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1067            &self.rgsw_cts[si]
1068        }
1069
1070        fn lwe_ksk(&self) -> &Self::LweKskKey {
1071            &self.lwe_ksk
1072        }
1073    }
1074}
1075
1076/// Server key in evaluation domain with Shoup representations
1077pub(crate) struct ShoupServerKeyEvaluationDomain<M> {
1078    /// Rgsw cts of LWE secret elements
1079    rgsw_cts: Vec<NormalAndShoup<M>>,
1080    /// Auto keys. Key corresponding to g^{k} is at index `k`. Key corresponding
1081    /// to -g is at 0
1082    galois_keys: HashMap<usize, NormalAndShoup<M>>,
1083    /// LWE ksk to key switching LWE ciphertext from RLWE secret to LWE secret
1084    lwe_ksk: M,
1085}
1086
1087mod shoup_server_key_eval_domain {
1088    use itertools::{izip, Itertools};
1089    use num_traits::{FromPrimitive, PrimInt};
1090
1091    use crate::{backend::Modulus, pbs::PbsKey};
1092
1093    use super::*;
1094
1095    impl<M: MatrixMut + MatrixEntity + ToShoup<Modulus = M::MatElement>, R, N>
1096        From<ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>>
1097        for ShoupServerKeyEvaluationDomain<M>
1098    where
1099        <M as Matrix>::R: RowMut,
1100        M::MatElement: PrimInt + FromPrimitive,
1101    {
1102        fn from(value: ServerKeyEvaluationDomain<M, BoolParameters<M::MatElement>, R, N>) -> Self {
1103            let q = value.parameters.rlwe_q().q().unwrap();
1104            // Rgsw ciphertexts
1105            let rgsw_cts = value
1106                .rgsw_cts
1107                .into_iter()
1108                .map(|ct| NormalAndShoup::new_with_modulus(ct, q))
1109                .collect_vec();
1110
1111            let mut auto_keys = HashMap::new();
1112            value.galois_keys.into_iter().for_each(|(index, key)| {
1113                auto_keys.insert(index, NormalAndShoup::new_with_modulus(key, q));
1114            });
1115
1116            Self {
1117                rgsw_cts,
1118                galois_keys: auto_keys,
1119                lwe_ksk: value.lwe_ksk,
1120            }
1121        }
1122    }
1123
1124    impl<M: Matrix> PbsKey for ShoupServerKeyEvaluationDomain<M> {
1125        type AutoKey = NormalAndShoup<M>;
1126        type LweKskKey = M;
1127        type RgswCt = NormalAndShoup<M>;
1128
1129        fn galois_key_for_auto(&self, k: usize) -> &Self::AutoKey {
1130            self.galois_keys.get(&k).unwrap()
1131        }
1132        fn rgsw_ct_lwe_si(&self, si: usize) -> &Self::RgswCt {
1133            &self.rgsw_cts[si]
1134        }
1135
1136        fn lwe_ksk(&self) -> &Self::LweKskKey {
1137            &self.lwe_ksk
1138        }
1139    }
1140}
1141
1142pub struct CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M: Matrix, S> {
1143    /// (ak*si + e + \beta ui, ak*si + e)
1144    ni_rgsw_cts: (Vec<M>, Vec<M>),
1145    ui_to_s_ksk: M,
1146    others_ksk_zero_encs: Vec<M>,
1147
1148    auto_keys_share: HashMap<usize, M>,
1149    lwe_ksk_share: M::R,
1150
1151    user_index: usize,
1152    cr_seed: S,
1153}
1154
1155mod impl_common_ref_non_interactive_multi_party_server_share {
1156    use super::*;
1157
1158    impl<M: Matrix, S> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<M, S> {
1159        pub(in super::super) fn new(
1160            ni_rgsw_cts: (Vec<M>, Vec<M>),
1161            ui_to_s_ksk: M,
1162            others_ksk_zero_encs: Vec<M>,
1163            auto_keys_share: HashMap<usize, M>,
1164            lwe_ksk_share: M::R,
1165            user_index: usize,
1166            cr_seed: S,
1167        ) -> Self {
1168            Self {
1169                ni_rgsw_cts,
1170                ui_to_s_ksk,
1171                others_ksk_zero_encs,
1172                auto_keys_share,
1173                lwe_ksk_share,
1174                user_index,
1175                cr_seed,
1176            }
1177        }
1178
1179        pub(in super::super) fn ni_rgsw_cts(&self) -> &(Vec<M>, Vec<M>) {
1180            &self.ni_rgsw_cts
1181        }
1182
1183        pub(in super::super) fn ui_to_s_ksk(&self) -> &M {
1184            &self.ui_to_s_ksk
1185        }
1186
1187        pub(in super::super) fn user_index(&self) -> usize {
1188            self.user_index
1189        }
1190
1191        pub(in super::super) fn auto_keys_share(&self) -> &HashMap<usize, M> {
1192            &self.auto_keys_share
1193        }
1194
1195        pub(in super::super) fn lwe_ksk_share(&self) -> &M::R {
1196            &self.lwe_ksk_share
1197        }
1198
1199        pub(in super::super) fn ui_to_s_ksk_zero_encs_for_user_i(&self, user_i: usize) -> &M {
1200            assert!(user_i != self.user_index);
1201            if user_i < self.user_index {
1202                &self.others_ksk_zero_encs[user_i]
1203            } else {
1204                &self.others_ksk_zero_encs[user_i - 1]
1205            }
1206        }
1207    }
1208}
1209
1210/// Stores normal and shoup representation of Matrix elements (Normal, Shoup)
1211pub(crate) struct NormalAndShoup<M>(M, M);
1212
1213impl<M: ToShoup> NormalAndShoup<M> {
1214    fn new_with_modulus(value: M, modulus: <M as ToShoup>::Modulus) -> Self {
1215        let value_shoup = M::to_shoup(&value, modulus);
1216        NormalAndShoup(value, value_shoup)
1217    }
1218}
1219
1220impl<M> AsRef<M> for NormalAndShoup<M> {
1221    fn as_ref(&self) -> &M {
1222        &self.0
1223    }
1224}
1225
1226impl<M> WithShoupRepr for NormalAndShoup<M> {
1227    type M = M;
1228    fn shoup_repr(&self) -> &Self::M {
1229        &self.1
1230    }
1231}