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