arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/bool/evaluator.rs
src/bool/evaluator.rsRaw
   1use std::{
   2    collections::HashMap,
   3    fmt::{Debug, Display},
   4    marker::PhantomData,
   5    usize,
   6};
   7
   8use itertools::{izip, Itertools};
   9use num_traits::{FromPrimitive, One, PrimInt, ToPrimitive, WrappingAdd, WrappingSub, Zero};
  10use rand_distr::uniform::SampleUniform;
  11
  12use crate::{
  13    backend::{ArithmeticOps, GetModulus, ModInit, Modulus, ShoupMatrixFMA, VectorOps},
  14    bool::parameters::ParameterVariant,
  15    decomposer::{Decomposer, DefaultDecomposer, NumInfo, RlweDecomposer},
  16    lwe::{decrypt_lwe, encrypt_lwe, seeded_lwe_ksk_keygen},
  17    multi_party::{
  18        non_interactive_ksk_gen, non_interactive_ksk_zero_encryptions_for_other_party_i,
  19        public_key_share,
  20    },
  21    ntt::{self, Ntt, NttBackendU64, NttInit},
  22    pbs::{pbs, sample_extract, PbsInfo, PbsKey, WithShoupRepr},
  23    random::{
  24        DefaultSecureRng, NewWithSeed, RandomFill, RandomFillGaussianInModulus,
  25        RandomFillUniformInModulus, RandomGaussianElementInModulus,
  26    },
  27    rgsw::{
  28        decrypt_rlwe, generate_auto_map, public_key_encrypt_rgsw, rgsw_by_rgsw_inplace,
  29        rgsw_x_rgsw_scratch_rows, rlwe_auto, secret_key_encrypt_rgsw, seeded_auto_key_gen,
  30        RgswCiphertext, RgswCiphertextMutRef, RgswCiphertextRef, RuntimeScratchMutRef,
  31    },
  32    utils::{
  33        encode_x_pow_si_with_emebedding_factor, fill_random_ternary_secret_with_hamming_weight,
  34        generate_prime, mod_exponent, puncture_p_rng, Global, TryConvertFrom1, WithLocal,
  35    },
  36    Encoder, Matrix, MatrixEntity, MatrixMut, RowEntity, RowMut,
  37};
  38
  39use super::{
  40    keys::{
  41        ClientKey, CommonReferenceSeededCollectivePublicKeyShare,
  42        CommonReferenceSeededMultiPartyServerKeyShare,
  43        CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare,
  44        InteractiveMultiPartyClientKey, NonInteractiveMultiPartyClientKey,
  45        SeededMultiPartyServerKey, SeededNonInteractiveMultiPartyServerKey,
  46        SeededSinglePartyServerKey, SinglePartyClientKey,
  47    },
  48    parameters::{BoolParameters, CiphertextModulus, DecompositionCount, DoubleDecomposerParams},
  49};
  50
  51/// Common reference seed used for Interactive multi-party,
  52///
  53/// Seeds for public key shares and differents parts of server key shares are
  54/// derived from common reference seed with different puncture rountines.
  55///
  56/// ## Punctures
  57///
  58///     Initial Seed:
  59///         Puncture 1 -> Public key share seed
  60///         Puncture 2 -> Main server key share seed
  61///             Puncture 1 -> Auto keys cipertexts seed
  62///             Puncture 2 -> LWE ksk seed
  63#[derive(Clone, PartialEq)]
  64pub struct MultiPartyCrs<S> {
  65    pub(super) seed: S,
  66}
  67
  68impl MultiPartyCrs<[u8; 32]> {
  69    pub(super) fn random() -> Self {
  70        DefaultSecureRng::with_local_mut(|rng| {
  71            let mut seed = [0u8; 32];
  72            rng.fill_bytes(&mut seed);
  73            Self { seed }
  74        })
  75    }
  76}
  77impl<S: Default + Copy> MultiPartyCrs<S> {
  78    /// Seed to generate public key share
  79    fn public_key_share_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
  80        let mut prng = Rng::new_with_seed(self.seed);
  81        puncture_p_rng(&mut prng, 1)
  82    }
  83
  84    /// Main server key share seed
  85    fn key_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
  86        let mut prng = Rng::new_with_seed(self.seed);
  87        puncture_p_rng(&mut prng, 2)
  88    }
  89
  90    pub(super) fn auto_keys_cts_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
  91        let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
  92        puncture_p_rng(&mut key_prng, 1)
  93    }
  94
  95    pub(super) fn lwe_ksk_cts_seed_seed<Rng: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
  96        let mut key_prng = Rng::new_with_seed(self.key_seed::<Rng>());
  97        puncture_p_rng(&mut key_prng, 2)
  98    }
  99}
 100
 101/// Common reference seed used for non-interactive multi-party.
 102///
 103/// Initial Seed
 104///     Puncture 1 -> Key Seed
 105///         Puncture 1 -> Rgsw ciphertext seed
 106///             Puncture l+1 -> Seed for zero encs and non-interactive
 107///                             multi-party RGSW ciphertexts of
 108///                             l^th LWE index.
 109///         Puncture 2 -> auto keys seed
 110///         Puncture 3 -> Lwe key switching key seed
 111///     Puncture 2 -> user specific seed for u_j to s ksk
 112///         Punture j+1 -> user j's seed    
 113#[derive(Clone)]
 114pub struct NonInteractiveMultiPartyCrs<S> {
 115    pub(super) seed: S,
 116}
 117
 118impl NonInteractiveMultiPartyCrs<[u8; 32]> {
 119    pub(super) fn random() -> Self {
 120        DefaultSecureRng::with_local_mut(|rng| {
 121            let mut seed = [0u8; 32];
 122            rng.fill_bytes(&mut seed);
 123            Self { seed }
 124        })
 125    }
 126}
 127
 128impl<S: Default + Copy> NonInteractiveMultiPartyCrs<S> {
 129    fn key_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
 130        let mut p_rng = R::new_with_seed(self.seed);
 131        puncture_p_rng(&mut p_rng, 1)
 132    }
 133
 134    pub(crate) fn ni_rgsw_cts_main_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
 135        let mut p_rng = R::new_with_seed(self.key_seed::<R>());
 136        puncture_p_rng(&mut p_rng, 1)
 137    }
 138
 139    pub(crate) fn ni_rgsw_ct_seed_for_index<R: NewWithSeed<Seed = S> + RandomFill<S>>(
 140        &self,
 141        lwe_index: usize,
 142    ) -> S {
 143        let mut p_rng = R::new_with_seed(self.ni_rgsw_cts_main_seed::<R>());
 144        puncture_p_rng(&mut p_rng, lwe_index + 1)
 145    }
 146
 147    pub(crate) fn auto_keys_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
 148        let mut p_rng = R::new_with_seed(self.key_seed::<R>());
 149        puncture_p_rng(&mut p_rng, 2)
 150    }
 151
 152    pub(crate) fn lwe_ksk_cts_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
 153        let mut p_rng = R::new_with_seed(self.key_seed::<R>());
 154        puncture_p_rng(&mut p_rng, 3)
 155    }
 156
 157    fn ui_to_s_ks_seed<R: NewWithSeed<Seed = S> + RandomFill<S>>(&self) -> S {
 158        let mut p_rng = R::new_with_seed(self.seed);
 159        puncture_p_rng(&mut p_rng, 2)
 160    }
 161
 162    pub(crate) fn ui_to_s_ks_seed_for_user_i<R: NewWithSeed<Seed = S> + RandomFill<S>>(
 163        &self,
 164        user_i: usize,
 165    ) -> S {
 166        let ks_seed = self.ui_to_s_ks_seed::<R>();
 167        let mut p_rng = R::new_with_seed(ks_seed);
 168
 169        puncture_p_rng(&mut p_rng, user_i + 1)
 170    }
 171}
 172
 173pub(crate) trait BooleanGates {
 174    type Ciphertext: RowEntity;
 175    type Key;
 176
 177    fn and_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
 178    fn nand_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
 179    fn or_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
 180    fn nor_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
 181    fn xor_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
 182    fn xnor_inplace(&mut self, c0: &mut Self::Ciphertext, c1: &Self::Ciphertext, key: &Self::Key);
 183    fn not_inplace(&mut self, c: &mut Self::Ciphertext);
 184
 185    fn and(
 186        &mut self,
 187        c0: &Self::Ciphertext,
 188        c1: &Self::Ciphertext,
 189        key: &Self::Key,
 190    ) -> Self::Ciphertext;
 191    fn nand(
 192        &mut self,
 193        c0: &Self::Ciphertext,
 194        c1: &Self::Ciphertext,
 195        key: &Self::Key,
 196    ) -> Self::Ciphertext;
 197    fn or(
 198        &mut self,
 199        c0: &Self::Ciphertext,
 200        c1: &Self::Ciphertext,
 201        key: &Self::Key,
 202    ) -> Self::Ciphertext;
 203    fn nor(
 204        &mut self,
 205        c0: &Self::Ciphertext,
 206        c1: &Self::Ciphertext,
 207        key: &Self::Key,
 208    ) -> Self::Ciphertext;
 209    fn xor(
 210        &mut self,
 211        c0: &Self::Ciphertext,
 212        c1: &Self::Ciphertext,
 213        key: &Self::Key,
 214    ) -> Self::Ciphertext;
 215    fn xnor(
 216        &mut self,
 217        c0: &Self::Ciphertext,
 218        c1: &Self::Ciphertext,
 219        key: &Self::Key,
 220    ) -> Self::Ciphertext;
 221    fn not(&mut self, c: &Self::Ciphertext) -> Self::Ciphertext;
 222}
 223
 224struct ScratchMemory<M>
 225where
 226    M: Matrix,
 227{
 228    lwe_vector: M::R,
 229    decomposition_matrix: M,
 230}
 231
 232impl<M: MatrixEntity> ScratchMemory<M>
 233where
 234    M::R: RowEntity,
 235{
 236    fn new(parameters: &BoolParameters<M::MatElement>) -> Self {
 237        // Vector to store LWE ciphertext with LWE dimesnion n
 238        let lwe_vector = M::R::zeros(parameters.lwe_n().0 + 1);
 239
 240        // Matrix to store decomposed polynomials
 241        // Max decompistion count + space for temporary RLWE
 242        let d = std::cmp::max(
 243            parameters.auto_decomposition_count().0,
 244            std::cmp::max(
 245                parameters.rlwe_rgsw_decomposition_count().0 .0,
 246                parameters.rlwe_rgsw_decomposition_count().1 .0,
 247            ),
 248        ) + 2;
 249        let decomposition_matrix = M::zeros(d, parameters.rlwe_n().0);
 250
 251        Self {
 252            lwe_vector,
 253            decomposition_matrix,
 254        }
 255    }
 256}
 257
 258pub(super) trait BoolEncoding {
 259    type Element;
 260    fn true_el(&self) -> Self::Element;
 261    fn false_el(&self) -> Self::Element;
 262    fn qby4(&self) -> Self::Element;
 263    fn decode(&self, m: Self::Element) -> bool;
 264}
 265
 266impl<T> BoolEncoding for CiphertextModulus<T>
 267where
 268    CiphertextModulus<T>: Modulus<Element = T>,
 269    T: PrimInt,
 270{
 271    type Element = T;
 272
 273    fn qby4(&self) -> Self::Element {
 274        if self.is_native() {
 275            T::one() << (CiphertextModulus::<T>::_bits() - 2)
 276        } else {
 277            self.q().unwrap() >> 2
 278        }
 279    }
 280    /// Q/8
 281    fn true_el(&self) -> Self::Element {
 282        if self.is_native() {
 283            T::one() << (CiphertextModulus::<T>::_bits() - 3)
 284        } else {
 285            self.q().unwrap() >> 3
 286        }
 287    }
 288    /// -Q/8
 289    fn false_el(&self) -> Self::Element {
 290        self.largest_unsigned_value() - self.true_el() + T::one()
 291    }
 292    fn decode(&self, m: Self::Element) -> bool {
 293        let qby8 = self.true_el();
 294        let m = (((m + qby8).to_f64().unwrap() * 4.0f64) / self.q_as_f64().unwrap()).round()
 295            as usize
 296            % 4usize;
 297
 298        if m == 0 {
 299            return false;
 300        } else if m == 1 {
 301            return true;
 302        } else {
 303            panic!("Incorrect bool decryption. Got m={m} but expected m to be 0 or 1")
 304        }
 305    }
 306}
 307
 308impl<B> Encoder<bool, B::Element> for B
 309where
 310    B: BoolEncoding,
 311{
 312    fn encode(&self, v: bool) -> B::Element {
 313        if v {
 314            self.true_el()
 315        } else {
 316            self.false_el()
 317        }
 318    }
 319}
 320
 321pub(super) struct BoolPbsInfo<M: Matrix, Ntt, RlweModOp, LweModOp> {
 322    auto_decomposer: DefaultDecomposer<M::MatElement>,
 323    rlwe_rgsw_decomposer: (
 324        DefaultDecomposer<M::MatElement>,
 325        DefaultDecomposer<M::MatElement>,
 326    ),
 327    lwe_decomposer: DefaultDecomposer<M::MatElement>,
 328    g_k_dlog_map: Vec<usize>,
 329    rlwe_nttop: Ntt,
 330    rlwe_modop: RlweModOp,
 331    lwe_modop: LweModOp,
 332    embedding_factor: usize,
 333    rlwe_qby4: M::MatElement,
 334    rlwe_auto_maps: Vec<(Vec<usize>, Vec<bool>)>,
 335    parameters: BoolParameters<M::MatElement>,
 336}
 337
 338impl<M: Matrix, NttOp, RlweModOp, LweModOp> PbsInfo for BoolPbsInfo<M, NttOp, RlweModOp, LweModOp>
 339where
 340    M::MatElement: PrimInt
 341        + WrappingSub
 342        + NumInfo
 343        + FromPrimitive
 344        + From<bool>
 345        + Display
 346        + WrappingAdd
 347        + Debug,
 348    RlweModOp: ArithmeticOps<Element = M::MatElement> + ShoupMatrixFMA<M::R>,
 349    LweModOp: ArithmeticOps<Element = M::MatElement> + VectorOps<Element = M::MatElement>,
 350    NttOp: Ntt<Element = M::MatElement>,
 351{
 352    type M = M;
 353    type Modulus = CiphertextModulus<M::MatElement>;
 354    type D = DefaultDecomposer<M::MatElement>;
 355    type RlweModOp = RlweModOp;
 356    type LweModOp = LweModOp;
 357    type NttOp = NttOp;
 358    fn rlwe_auto_map(&self, k: usize) -> &(Vec<usize>, Vec<bool>) {
 359        &self.rlwe_auto_maps[k]
 360    }
 361    fn br_q(&self) -> usize {
 362        *self.parameters.br_q()
 363    }
 364    fn lwe_decomposer(&self) -> &Self::D {
 365        &self.lwe_decomposer
 366    }
 367    fn rlwe_rgsw_decomposer(&self) -> &(Self::D, Self::D) {
 368        &self.rlwe_rgsw_decomposer
 369    }
 370    fn auto_decomposer(&self) -> &Self::D {
 371        &self.auto_decomposer
 372    }
 373    fn embedding_factor(&self) -> usize {
 374        self.embedding_factor
 375    }
 376    fn g(&self) -> isize {
 377        self.parameters.g() as isize
 378    }
 379    fn w(&self) -> usize {
 380        self.parameters.w()
 381    }
 382    fn g_k_dlog_map(&self) -> &[usize] {
 383        &self.g_k_dlog_map
 384    }
 385    fn lwe_n(&self) -> usize {
 386        self.parameters.lwe_n().0
 387    }
 388    fn lwe_q(&self) -> &Self::Modulus {
 389        self.parameters.lwe_q()
 390    }
 391    fn rlwe_n(&self) -> usize {
 392        self.parameters.rlwe_n().0
 393    }
 394    fn rlwe_q(&self) -> &Self::Modulus {
 395        self.parameters.rlwe_q()
 396    }
 397    fn modop_lweq(&self) -> &Self::LweModOp {
 398        &self.lwe_modop
 399    }
 400    fn modop_rlweq(&self) -> &Self::RlweModOp {
 401        &self.rlwe_modop
 402    }
 403    fn nttop_rlweq(&self) -> &Self::NttOp {
 404        &self.rlwe_nttop
 405    }
 406}
 407
 408pub(crate) struct BoolEvaluator<M, Ntt, RlweModOp, LweModOp, SKey>
 409where
 410    M: Matrix,
 411{
 412    pbs_info: BoolPbsInfo<M, Ntt, RlweModOp, LweModOp>,
 413    scratch_memory: ScratchMemory<M>,
 414    nand_test_vec: M::R,
 415    and_test_vec: M::R,
 416    or_test_vec: M::R,
 417    nor_test_vec: M::R,
 418    xor_test_vec: M::R,
 419    xnor_test_vec: M::R,
 420    /// Non-interactive u_i -> s key switch decomposer
 421    ni_ui_to_s_ks_decomposer: Option<DefaultDecomposer<M::MatElement>>,
 422    _phantom: PhantomData<SKey>,
 423}
 424
 425impl<M: Matrix, NttOp, RlweModOp, LweModOp, Skey>
 426    BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
 427{
 428    pub(crate) fn parameters(&self) -> &BoolParameters<M::MatElement> {
 429        &self.pbs_info.parameters
 430    }
 431
 432    pub(super) fn pbs_info(&self) -> &BoolPbsInfo<M, NttOp, RlweModOp, LweModOp> {
 433        &self.pbs_info
 434    }
 435
 436    pub(super) fn ni_ui_to_s_ks_decomposer(&self) -> &Option<DefaultDecomposer<M::MatElement>> {
 437        &self.ni_ui_to_s_ks_decomposer
 438    }
 439}
 440
 441fn trim_rgsw_ct_matrix_from_rgrg_to_rlrg<
 442    M: MatrixMut + MatrixEntity,
 443    D: DoubleDecomposerParams<Count = DecompositionCount>,
 444>(
 445    rgsw_ct_in: M,
 446    rgrg_params: D,
 447    rlrg_params: D,
 448) -> M
 449where
 450    M::R: RowMut,
 451    M::MatElement: Copy,
 452{
 453    let (rgswrgsw_d_a, rgswrgsw_d_b) = (
 454        rgrg_params.decomposition_count_a(),
 455        rgrg_params.decomposition_count_b(),
 456    );
 457    let (rlrg_d_a, rlrg_d_b) = (
 458        rlrg_params.decomposition_count_a(),
 459        rlrg_params.decomposition_count_b(),
 460    );
 461    let rgsw_ct_rows_in = rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 * 2;
 462    let rgsw_ct_rows_out = rlrg_d_a.0 * 2 + rlrg_d_b.0 * 2;
 463    assert!(rgsw_ct_in.dimension().0 == rgsw_ct_rows_in);
 464    assert!(rgswrgsw_d_a.0 >= rlrg_d_a.0, "RGSWxRGSW part A decomposition count {} must be >= RLWExRGSW part A decomposition count {}", rgswrgsw_d_a.0 , rlrg_d_a.0);
 465    assert!(rgswrgsw_d_b.0 >= rlrg_d_b.0, "RGSWxRGSW part B decomposition count {} must be >= RLWExRGSW part B decomposition count {}", rgswrgsw_d_b.0 , rlrg_d_b.0);
 466
 467    let mut reduced_ct_i_out = M::zeros(rgsw_ct_rows_out, rgsw_ct_in.dimension().1);
 468
 469    // RLWE'(-sm) part A
 470    izip!(
 471        reduced_ct_i_out.iter_rows_mut().take(rlrg_d_a.0),
 472        rgsw_ct_in
 473            .iter_rows()
 474            .skip(rgswrgsw_d_a.0 - rlrg_d_a.0)
 475            .take(rlrg_d_a.0)
 476    )
 477    .for_each(|(to_ri, from_ri)| {
 478        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 479    });
 480
 481    // RLWE'(-sm) part B
 482    izip!(
 483        reduced_ct_i_out
 484            .iter_rows_mut()
 485            .skip(rlrg_d_a.0)
 486            .take(rlrg_d_a.0),
 487        rgsw_ct_in
 488            .iter_rows()
 489            .skip(rgswrgsw_d_a.0 + (rgswrgsw_d_a.0 - rlrg_d_a.0))
 490            .take(rlrg_d_a.0)
 491    )
 492    .for_each(|(to_ri, from_ri)| {
 493        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 494    });
 495
 496    // RLWE'(m) Part A
 497    izip!(
 498        reduced_ct_i_out
 499            .iter_rows_mut()
 500            .skip(rlrg_d_a.0 * 2)
 501            .take(rlrg_d_b.0),
 502        rgsw_ct_in
 503            .iter_rows()
 504            .skip(rgswrgsw_d_a.0 * 2 + (rgswrgsw_d_b.0 - rlrg_d_b.0))
 505            .take(rlrg_d_b.0)
 506    )
 507    .for_each(|(to_ri, from_ri)| {
 508        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 509    });
 510
 511    // RLWE'(m) Part B
 512    izip!(
 513        reduced_ct_i_out
 514            .iter_rows_mut()
 515            .skip(rlrg_d_a.0 * 2 + rlrg_d_b.0)
 516            .take(rlrg_d_b.0),
 517        rgsw_ct_in
 518            .iter_rows()
 519            .skip(rgswrgsw_d_a.0 * 2 + rgswrgsw_d_b.0 + (rgswrgsw_d_b.0 - rlrg_d_b.0))
 520            .take(rlrg_d_b.0)
 521    )
 522    .for_each(|(to_ri, from_ri)| {
 523        to_ri.as_mut().copy_from_slice(from_ri.as_ref());
 524    });
 525
 526    reduced_ct_i_out
 527}
 528
 529fn produce_rgsw_ciphertext_from_ni_rgsw<
 530    M: MatrixMut + MatrixEntity,
 531    D: RlweDecomposer,
 532    ModOp: VectorOps<Element = M::MatElement>,
 533    NttOp: Ntt<Element = M::MatElement>,
 534>(
 535    ni_rgsw_ct: &M,
 536    aggregated_decomposed_ni_rgsw_zero_encs: &[M],
 537    decomposed_neg_ais: &[M],
 538    decomposer: &D,
 539    parameters: &BoolParameters<M::MatElement>,
 540    uj_to_s_ksk: (&M, &M),
 541    rlwe_modop: &ModOp,
 542    nttop: &NttOp,
 543    out_eval: bool,
 544) -> M
 545where
 546    <M as Matrix>::R: RowMut + Clone,
 547{
 548    let max_decomposer =
 549        if decomposer.a().decomposition_count() > decomposer.b().decomposition_count() {
 550            decomposer.a()
 551        } else {
 552            decomposer.b()
 553        };
 554
 555    assert!(
 556        ni_rgsw_ct.dimension() == (max_decomposer.decomposition_count(), parameters.rlwe_n().0)
 557    );
 558    assert!(aggregated_decomposed_ni_rgsw_zero_encs.len() == decomposer.a().decomposition_count(),);
 559    assert!(decomposed_neg_ais.len() == decomposer.b().decomposition_count());
 560
 561    let mut rgsw_i = M::zeros(
 562        decomposer.a().decomposition_count() * 2 + decomposer.b().decomposition_count() * 2,
 563        parameters.rlwe_n().0,
 564    );
 565    let (rlwe_dash_nsm, rlwe_dash_m) =
 566        rgsw_i.split_at_row_mut(decomposer.a().decomposition_count() * 2);
 567
 568    // RLWE'_{s}(-sm)
 569    // Key switch `s * a_{i, l} + e` using ksk(u_j -> s) to produce RLWE(s *
 570    // u_{j=user_id} * a_{i, l}).
 571    //
 572    // Then set RLWE_{s}(-s B^i m) = (0, u_{j=user_id} * a_{i, l} + e + B^i m) +
 573    // RLWE(s * u_{j=user_id} * a_{i, l})
 574    {
 575        let (rlwe_dash_nsm_parta, rlwe_dash_nsm_partb) =
 576            rlwe_dash_nsm.split_at_mut(decomposer.a().decomposition_count());
 577        izip!(
 578            rlwe_dash_nsm_parta.iter_mut(),
 579            rlwe_dash_nsm_partb.iter_mut(),
 580            ni_rgsw_ct
 581                .iter_rows()
 582                .skip(max_decomposer.decomposition_count() - decomposer.a().decomposition_count()),
 583            aggregated_decomposed_ni_rgsw_zero_encs.iter()
 584        )
 585        .for_each(|(rlwe_a, rlwe_b, ni_rlwe_ct, decomp_zero_enc)| {
 586            // KS(s * a_{i, l} + e) = RLWE(s * u_j *
 587            // a_{i, l}) using user j's Ksk
 588            izip!(
 589                decomp_zero_enc.iter_rows(),
 590                uj_to_s_ksk.0.iter_rows(),
 591                uj_to_s_ksk.1.iter_rows()
 592            )
 593            .for_each(|(c, pb, pa)| {
 594                rlwe_modop.elwise_fma_mut(rlwe_b.as_mut(), pb.as_ref(), c.as_ref());
 595                rlwe_modop.elwise_fma_mut(rlwe_a.as_mut(), pa.as_ref(), c.as_ref());
 596            });
 597
 598            // RLWE(-s beta^i m) = (0, u_j * a_{j, l} +
 599            // e + beta^i m) + RLWE(s * u_j * a_{i, l})
 600            if out_eval {
 601                let mut ni_rlwe_ct = ni_rlwe_ct.clone();
 602                nttop.forward(ni_rlwe_ct.as_mut());
 603                rlwe_modop.elwise_add_mut(rlwe_a.as_mut(), ni_rlwe_ct.as_ref());
 604            } else {
 605                nttop.backward(rlwe_a.as_mut());
 606                nttop.backward(rlwe_b.as_mut());
 607                rlwe_modop.elwise_add_mut(rlwe_a.as_mut(), ni_rlwe_ct.as_ref());
 608            }
 609        });
 610    }
 611
 612    // RLWE'_{s}(m)
 613    {
 614        let (rlwe_dash_m_parta, rlwe_dash_partb) =
 615            rlwe_dash_m.split_at_mut(decomposer.b().decomposition_count());
 616        izip!(
 617            rlwe_dash_m_parta.iter_mut(),
 618            rlwe_dash_partb.iter_mut(),
 619            ni_rgsw_ct
 620                .iter_rows()
 621                .skip(max_decomposer.decomposition_count() - decomposer.b().decomposition_count()),
 622            decomposed_neg_ais.iter()
 623        )
 624        .for_each(|(rlwe_a, rlwe_b, ni_rlwe_ct, decomp_neg_ai)| {
 625            // KS(-a_{i, l}) = RLWE(u_i * -a_{i,l}) using user j's Ksk
 626            izip!(
 627                decomp_neg_ai.iter_rows(),
 628                uj_to_s_ksk.0.iter_rows(),
 629                uj_to_s_ksk.1.iter_rows()
 630            )
 631            .for_each(|(c, pb, pa)| {
 632                rlwe_modop.elwise_fma_mut(rlwe_b.as_mut(), pb.as_ref(), c.as_ref());
 633                rlwe_modop.elwise_fma_mut(rlwe_a.as_mut(), pa.as_ref(), c.as_ref());
 634            });
 635
 636            // RLWE_{s}(beta^i m) = (u_j * a_{i, l} + e + beta^i m, 0) -
 637            // RLWE(-a_{i, l} u_j)
 638            if out_eval {
 639                let mut ni_rlwe_ct = ni_rlwe_ct.clone();
 640                nttop.forward(ni_rlwe_ct.as_mut());
 641                rlwe_modop.elwise_add_mut(rlwe_b.as_mut(), ni_rlwe_ct.as_ref());
 642            } else {
 643                nttop.backward(rlwe_a.as_mut());
 644                nttop.backward(rlwe_b.as_mut());
 645                rlwe_modop.elwise_add_mut(rlwe_b.as_mut(), ni_rlwe_ct.as_ref());
 646            }
 647        });
 648    }
 649
 650    rgsw_i
 651}
 652
 653/// Assigns user with user_id segement of LWE secret indices for which they
 654/// generate RGSW(X^{s[i]}) as the leader (i.e. for RLWExRGSW). If returned
 655/// tuple is (start, end), user's segment is [start, end)
 656pub(super) fn interactive_mult_party_user_id_lwe_segment(
 657    user_id: usize,
 658    total_users: usize,
 659    lwe_n: usize,
 660) -> (usize, usize) {
 661    let per_user = (lwe_n as f64 / total_users as f64)
 662        .ceil()
 663        .to_usize()
 664        .unwrap();
 665    (
 666        per_user * user_id,
 667        std::cmp::min(per_user * (user_id + 1), lwe_n),
 668    )
 669}
 670
 671impl<M: Matrix, NttOp, RlweModOp, LweModOp, SKey> BoolEvaluator<M, NttOp, RlweModOp, LweModOp, SKey>
 672where
 673    M: MatrixEntity + MatrixMut,
 674    M::MatElement: PrimInt
 675        + Debug
 676        + Display
 677        + NumInfo
 678        + FromPrimitive
 679        + WrappingSub
 680        + WrappingAdd
 681        + SampleUniform
 682        + From<bool>,
 683    NttOp: Ntt<Element = M::MatElement>,
 684    RlweModOp: ArithmeticOps<Element = M::MatElement>
 685        + VectorOps<Element = M::MatElement>
 686        + GetModulus<Element = M::MatElement, M = CiphertextModulus<M::MatElement>>
 687        + ShoupMatrixFMA<M::R>,
 688    LweModOp: ArithmeticOps<Element = M::MatElement>
 689        + VectorOps<Element = M::MatElement>
 690        + GetModulus<Element = M::MatElement, M = CiphertextModulus<M::MatElement>>,
 691    M::R: TryConvertFrom1<[i32], CiphertextModulus<M::MatElement>> + RowEntity + Debug,
 692    <M as Matrix>::R: RowMut,
 693{
 694    pub(super) fn new(parameters: BoolParameters<M::MatElement>) -> Self
 695    where
 696        RlweModOp: ModInit<M = CiphertextModulus<M::MatElement>>,
 697        LweModOp: ModInit<M = CiphertextModulus<M::MatElement>>,
 698        NttOp: NttInit<CiphertextModulus<M::MatElement>>,
 699    {
 700        //TODO(Jay): Run sanity checks for modulus values in parameters
 701
 702        // generates dlog map s.t. (+/-)g^{k} % q = a, for all a \in Z*_{q} and k \in
 703        // [0, q/4). We store the dlog `k` at index `a`. This makes it easier to
 704        // simply look up `k` at runtime as vec[a]. If a = g^{k} then dlog is
 705        // stored as k. If a = -g^{k} then dlog is stored as k = q/4. This is done to
 706        // differentiate sign.
 707        let g = parameters.g();
 708        let q = *parameters.br_q();
 709        let mut g_k_dlog_map = vec![0usize; q];
 710        for i in 0..q / 4 {
 711            let v = mod_exponent(g as u64, i as u64, q as u64) as usize;
 712            // g^i
 713            g_k_dlog_map[v] = i;
 714            // -(g^i)
 715            g_k_dlog_map[q - v] = i + (q / 4);
 716        }
 717
 718        let embedding_factor = (2 * parameters.rlwe_n().0) / q;
 719
 720        let rlwe_nttop = NttOp::new(parameters.rlwe_q(), parameters.rlwe_n().0);
 721        let rlwe_modop = RlweModOp::new(*parameters.rlwe_q());
 722        let lwe_modop = LweModOp::new(*parameters.lwe_q());
 723
 724        let q = *parameters.br_q();
 725        let qby2 = q >> 1;
 726        let qby8 = q >> 3;
 727        // Q/8 (Q: rlwe_q)
 728        let true_m_el = parameters.rlwe_q().true_el();
 729        // -Q/8
 730        let false_m_el = parameters.rlwe_q().false_el();
 731        let (auto_map_index, auto_map_sign) = generate_auto_map(qby2, -(g as isize));
 732
 733        let init_test_vec = |partition_el: usize,
 734                             before_partition_el: M::MatElement,
 735                             after_partition_el: M::MatElement| {
 736            let mut test_vec = M::R::zeros(qby2);
 737            for i in 0..qby2 {
 738                if i < partition_el {
 739                    test_vec.as_mut()[i] = before_partition_el;
 740                } else {
 741                    test_vec.as_mut()[i] = after_partition_el;
 742                }
 743            }
 744
 745            // v(X) -> v(X^{-g})
 746            let mut test_vec_autog = M::R::zeros(qby2);
 747            izip!(
 748                test_vec.as_ref().iter(),
 749                auto_map_index.iter(),
 750                auto_map_sign.iter()
 751            )
 752            .for_each(|(v, to_index, to_sign)| {
 753                if !to_sign {
 754                    // negate
 755                    test_vec_autog.as_mut()[*to_index] = rlwe_modop.neg(v);
 756                } else {
 757                    test_vec_autog.as_mut()[*to_index] = *v;
 758                }
 759            });
 760
 761            return test_vec_autog;
 762        };
 763
 764        let nand_test_vec = init_test_vec(3 * qby8, true_m_el, false_m_el);
 765        let and_test_vec = init_test_vec(3 * qby8, false_m_el, true_m_el);
 766        let or_test_vec = init_test_vec(qby8, false_m_el, true_m_el);
 767        let nor_test_vec = init_test_vec(qby8, true_m_el, false_m_el);
 768        let xor_test_vec = init_test_vec(qby8, false_m_el, true_m_el);
 769        let xnor_test_vec = init_test_vec(qby8, true_m_el, false_m_el);
 770
 771        // auto map indices and sign
 772        // Auto maps are stored as [-g, g^{1}, g^{2}, ..., g^{w}]
 773        let mut rlwe_auto_maps = vec![];
 774        let ring_size = parameters.rlwe_n().0;
 775        let g = parameters.g();
 776        let br_q = parameters.br_q();
 777        let auto_element_dlogs = parameters.auto_element_dlogs();
 778        assert!(auto_element_dlogs[0] == 0);
 779        for i in auto_element_dlogs.into_iter() {
 780            let el = if i == 0 {
 781                -(g as isize)
 782            } else {
 783                (g.pow(i as u32) % br_q) as isize
 784            };
 785            rlwe_auto_maps.push(generate_auto_map(ring_size, el))
 786        }
 787
 788        let rlwe_qby4 = parameters.rlwe_q().qby4();
 789
 790        let scratch_memory = ScratchMemory::new(&parameters);
 791
 792        let ni_ui_to_s_ks_decomposer = if parameters.variant()
 793            == &ParameterVariant::NonInteractiveMultiParty
 794        {
 795            Some(parameters
 796                .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>())
 797        } else {
 798            None
 799        };
 800
 801        let pbs_info = BoolPbsInfo {
 802            auto_decomposer: parameters.auto_decomposer(),
 803            lwe_decomposer: parameters.lwe_decomposer(),
 804            rlwe_rgsw_decomposer: parameters.rlwe_rgsw_decomposer(),
 805            g_k_dlog_map,
 806            embedding_factor,
 807            lwe_modop,
 808            rlwe_modop,
 809            rlwe_nttop,
 810            rlwe_qby4,
 811            rlwe_auto_maps,
 812            parameters: parameters,
 813        };
 814
 815        BoolEvaluator {
 816            pbs_info,
 817            scratch_memory,
 818            nand_test_vec,
 819            and_test_vec,
 820            or_test_vec,
 821            nor_test_vec,
 822            xnor_test_vec,
 823            xor_test_vec,
 824            ni_ui_to_s_ks_decomposer,
 825            _phantom: PhantomData,
 826        }
 827    }
 828
 829    pub(crate) fn client_key(
 830        &self,
 831    ) -> ClientKey<<DefaultSecureRng as NewWithSeed>::Seed, M::MatElement> {
 832        ClientKey::new(self.parameters().clone())
 833    }
 834
 835    pub(super) fn single_party_server_key<K: SinglePartyClientKey<Element = i32>>(
 836        &self,
 837        client_key: &K,
 838    ) -> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, [u8; 32]> {
 839        assert_eq!(self.parameters().variant(), &ParameterVariant::SingleParty);
 840
 841        DefaultSecureRng::with_local_mut(|rng| {
 842            let mut main_seed = [0u8; 32];
 843            rng.fill_bytes(&mut main_seed);
 844
 845            let mut main_prng = DefaultSecureRng::new_seeded(main_seed);
 846
 847            let rlwe_n = self.pbs_info.parameters.rlwe_n().0;
 848            let sk_rlwe = client_key.sk_rlwe();
 849            let sk_lwe = client_key.sk_lwe();
 850
 851            // generate auto keys
 852            let mut auto_keys = HashMap::new();
 853            let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
 854            let g = self.pbs_info.parameters.g();
 855            let br_q = self.pbs_info.parameters.br_q();
 856            let auto_els = self.pbs_info.parameters.auto_element_dlogs();
 857            for i in auto_els.into_iter() {
 858                let g_pow = if i == 0 {
 859                    -(g as isize)
 860                } else {
 861                    (g.pow(i as u32) % br_q) as isize
 862                };
 863                let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n);
 864                seeded_auto_key_gen(
 865                    &mut gk,
 866                    &sk_rlwe,
 867                    g_pow,
 868                    &auto_gadget,
 869                    &self.pbs_info.rlwe_modop,
 870                    &self.pbs_info.rlwe_nttop,
 871                    &mut main_prng,
 872                    rng,
 873                );
 874                auto_keys.insert(i, gk);
 875            }
 876
 877            // generate rgsw ciphertexts RGSW(si) where si is i^th LWE secret element
 878            let ring_size = self.pbs_info.parameters.rlwe_n().0;
 879            let rlwe_q = self.pbs_info.parameters.rlwe_q();
 880            let (rlrg_d_a, rlrg_d_b) = (
 881                self.pbs_info.rlwe_rgsw_decomposer.0.decomposition_count(),
 882                self.pbs_info.rlwe_rgsw_decomposer.1.decomposition_count(),
 883            );
 884            let rlrg_gadget_a = self.pbs_info.rlwe_rgsw_decomposer.0.gadget_vector();
 885            let rlrg_gadget_b = self.pbs_info.rlwe_rgsw_decomposer.1.gadget_vector();
 886            let rgsw_cts = sk_lwe
 887                .iter()
 888                .map(|si| {
 889                    // X^{si}; assume |emebedding_factor * si| < N
 890                    let mut m = M::R::zeros(ring_size);
 891                    let si = (self.pbs_info.embedding_factor as i32) * si;
 892                    // dbg!(si);
 893                    if si < 0 {
 894                        // X^{-i} = X^{2N - i} = -X^{N-i}
 895                        m.as_mut()[ring_size - (si.abs() as usize)] = rlwe_q.neg_one();
 896                    } else {
 897                        // X^{i}
 898                        m.as_mut()[si.abs() as usize] = M::MatElement::one();
 899                    }
 900
 901                    let mut rgsw_si = M::zeros(rlrg_d_a * 2 + rlrg_d_b, ring_size);
 902                    secret_key_encrypt_rgsw(
 903                        &mut rgsw_si,
 904                        m.as_ref(),
 905                        &rlrg_gadget_a,
 906                        &rlrg_gadget_b,
 907                        &sk_rlwe,
 908                        &self.pbs_info.rlwe_modop,
 909                        &self.pbs_info.rlwe_nttop,
 910                        &mut main_prng,
 911                        rng,
 912                    );
 913
 914                    rgsw_si
 915                })
 916                .collect_vec();
 917
 918            // LWE KSK from RLWE secret s -> LWE secret z
 919            let d_lwe_gadget = self.pbs_info.lwe_decomposer.gadget_vector();
 920            let lwe_ksk = seeded_lwe_ksk_keygen(
 921                &sk_rlwe,
 922                &sk_lwe,
 923                &d_lwe_gadget,
 924                &self.pbs_info.lwe_modop,
 925                &mut main_prng,
 926                rng,
 927            );
 928
 929            SeededSinglePartyServerKey::from_raw(
 930                auto_keys,
 931                rgsw_cts,
 932                lwe_ksk,
 933                self.pbs_info.parameters.clone(),
 934                main_seed,
 935            )
 936        })
 937    }
 938
 939    pub(super) fn multi_party_server_key_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
 940        &self,
 941        user_id: usize,
 942        total_users: usize,
 943        cr_seed: &MultiPartyCrs<[u8; 32]>,
 944        collective_pk: &M,
 945        client_key: &K,
 946    ) -> CommonReferenceSeededMultiPartyServerKeyShare<
 947        M,
 948        BoolParameters<M::MatElement>,
 949        MultiPartyCrs<[u8; 32]>,
 950    > {
 951        assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
 952        assert!(user_id < total_users);
 953
 954        let sk_rlwe = client_key.sk_rlwe();
 955        let sk_lwe = client_key.sk_lwe();
 956
 957        let g = self.pbs_info.parameters.g();
 958        let ring_size = self.pbs_info.parameters.rlwe_n().0;
 959        let rlwe_q = self.pbs_info.parameters.rlwe_q();
 960        let lwe_q = self.pbs_info.parameters.lwe_q();
 961
 962        let rlweq_modop = &self.pbs_info.rlwe_modop;
 963        let rlweq_nttop = &self.pbs_info.rlwe_nttop;
 964
 965        // sanity check
 966        assert!(sk_rlwe.len() == ring_size);
 967        assert!(sk_lwe.len() == self.pbs_info.parameters.lwe_n().0);
 968
 969        // auto keys
 970        let auto_keys = self._common_rountine_multi_party_auto_keys_share_gen(
 971            cr_seed.auto_keys_cts_seed::<DefaultSecureRng>(),
 972            &sk_rlwe,
 973        );
 974
 975        // rgsw ciphertexts of lwe secret elements
 976        let (self_leader_rgsws, not_self_leader_rgsws) = DefaultSecureRng::with_local_mut(|rng| {
 977            let mut self_leader_rgsw = vec![];
 978            let mut not_self_leader_rgsws = vec![];
 979
 980            let (segment_start, segment_end) = interactive_mult_party_user_id_lwe_segment(
 981                user_id,
 982                total_users,
 983                self.pbs_info().lwe_n(),
 984            );
 985
 986            // self LWE secret indices
 987            {
 988                // LWE secret indices for which user is the leader they need to send RGSW(m) for
 989                // RLWE x RGSW multiplication
 990                let rlrg_decomposer = self.pbs_info().rlwe_rgsw_decomposer();
 991                let (rlrg_d_a, rlrg_d_b) = (
 992                    rlrg_decomposer.a().decomposition_count(),
 993                    rlrg_decomposer.b().decomposition_count(),
 994                );
 995                let (gadget_a, gadget_b) = (
 996                    rlrg_decomposer.a().gadget_vector(),
 997                    rlrg_decomposer.b().gadget_vector(),
 998                );
 999                for s_index in segment_start..segment_end {
1000                    let mut out_rgsw = M::zeros(rlrg_d_a * 2 + rlrg_d_b * 2, ring_size);
1001                    public_key_encrypt_rgsw(
1002                        &mut out_rgsw,
1003                        &encode_x_pow_si_with_emebedding_factor::<
1004                            M::R,
1005                            CiphertextModulus<M::MatElement>,
1006                        >(
1007                            sk_lwe[s_index],
1008                            self.pbs_info().embedding_factor(),
1009                            ring_size,
1010                            self.pbs_info().rlwe_q(),
1011                        )
1012                        .as_ref(),
1013                        collective_pk,
1014                        &gadget_a,
1015                        &gadget_b,
1016                        rlweq_modop,
1017                        rlweq_nttop,
1018                        rng,
1019                    );
1020                    self_leader_rgsw.push(out_rgsw);
1021                }
1022            }
1023
1024            // not self LWE secret indices
1025            {
1026                // LWE secret indices for which user isn't the leader, they need to send RGSW(m)
1027                // for RGSW x RGSW multiplcation
1028                let rgsw_rgsw_decomposer = self
1029                    .pbs_info
1030                    .parameters
1031                    .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1032                let (rgrg_d_a, rgrg_d_b) = (
1033                    rgsw_rgsw_decomposer.a().decomposition_count(),
1034                    rgsw_rgsw_decomposer.b().decomposition_count(),
1035                );
1036                let (rgrg_gadget_a, rgrg_gadget_b) = (
1037                    rgsw_rgsw_decomposer.a().gadget_vector(),
1038                    rgsw_rgsw_decomposer.b().gadget_vector(),
1039                );
1040
1041                for s_index in (0..segment_start).chain(segment_end..self.parameters().lwe_n().0) {
1042                    let mut out_rgsw = M::zeros(rgrg_d_a * 2 + rgrg_d_b * 2, ring_size);
1043                    public_key_encrypt_rgsw(
1044                        &mut out_rgsw,
1045                        &encode_x_pow_si_with_emebedding_factor::<
1046                            M::R,
1047                            CiphertextModulus<M::MatElement>,
1048                        >(
1049                            sk_lwe[s_index],
1050                            self.pbs_info().embedding_factor(),
1051                            ring_size,
1052                            self.pbs_info().rlwe_q(),
1053                        )
1054                        .as_ref(),
1055                        collective_pk,
1056                        &rgrg_gadget_a,
1057                        &rgrg_gadget_b,
1058                        rlweq_modop,
1059                        rlweq_nttop,
1060                        rng,
1061                    );
1062
1063                    not_self_leader_rgsws.push(out_rgsw);
1064                }
1065            }
1066
1067            (self_leader_rgsw, not_self_leader_rgsws)
1068        });
1069
1070        // LWE Ksk
1071        let lwe_ksk = self._common_rountine_multi_party_lwe_ksk_share_gen(
1072            cr_seed.lwe_ksk_cts_seed_seed::<DefaultSecureRng>(),
1073            &sk_rlwe,
1074            &sk_lwe,
1075        );
1076
1077        CommonReferenceSeededMultiPartyServerKeyShare::new(
1078            self_leader_rgsws,
1079            not_self_leader_rgsws,
1080            auto_keys,
1081            lwe_ksk,
1082            cr_seed.clone(),
1083            self.pbs_info.parameters.clone(),
1084            user_id,
1085        )
1086    }
1087
1088    pub(super) fn aggregate_multi_party_server_key_shares<S>(
1089        &self,
1090        shares: &[CommonReferenceSeededMultiPartyServerKeyShare<
1091            M,
1092            BoolParameters<M::MatElement>,
1093            MultiPartyCrs<S>,
1094        >],
1095    ) -> SeededMultiPartyServerKey<M, MultiPartyCrs<S>, BoolParameters<M::MatElement>>
1096    where
1097        S: PartialEq + Clone,
1098        M: Clone,
1099    {
1100        assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
1101        assert!(shares.len() > 0);
1102
1103        let total_users = shares.len();
1104
1105        let parameters = shares[0].parameters().clone();
1106        let cr_seed = shares[0].cr_seed();
1107
1108        let rlwe_n = parameters.rlwe_n().0;
1109        let g = parameters.g() as isize;
1110        let rlwe_q = parameters.rlwe_q();
1111        let lwe_q = parameters.lwe_q();
1112
1113        // sanity checks
1114        shares.iter().skip(1).for_each(|s| {
1115            assert!(s.parameters() == &parameters);
1116            assert!(s.cr_seed() == cr_seed);
1117        });
1118
1119        let rlweq_modop = &self.pbs_info.rlwe_modop;
1120        let rlweq_nttop = &self.pbs_info.rlwe_nttop;
1121
1122        // auto keys
1123        let mut auto_keys = HashMap::new();
1124        let auto_elements_dlog = parameters.auto_element_dlogs();
1125        for i in auto_elements_dlog.into_iter() {
1126            let mut key = M::zeros(parameters.auto_decomposition_count().0, rlwe_n);
1127
1128            shares.iter().for_each(|s| {
1129                let auto_key_share_i = s.auto_keys().get(&i).expect("Auto key {i} missing");
1130                assert!(
1131                    auto_key_share_i.dimension()
1132                        == (parameters.auto_decomposition_count().0, rlwe_n)
1133                );
1134                izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
1135                    |(partb_out, partb_share)| {
1136                        rlweq_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
1137                    },
1138                );
1139            });
1140
1141            auto_keys.insert(i, key);
1142        }
1143
1144        // rgsw ciphertext (most expensive part!)
1145        let rgsw_cts = {
1146            let rgsw_x_rgsw_decomposer =
1147                parameters.rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1148            let rlwe_x_rgsw_decomposer = self.pbs_info().rlwe_rgsw_decomposer();
1149            let rgsw_x_rgsw_dimension = (
1150                rgsw_x_rgsw_decomposer.a().decomposition_count() * 2
1151                    + rgsw_x_rgsw_decomposer.b().decomposition_count() * 2,
1152                rlwe_n,
1153            );
1154            let rlwe_x_rgsw_dimension = (
1155                rlwe_x_rgsw_decomposer.a().decomposition_count() * 2
1156                    + rlwe_x_rgsw_decomposer.b().decomposition_count() * 2,
1157                rlwe_n,
1158            );
1159
1160            let mut rgsw_x_rgsw_scratch = M::zeros(
1161                rgsw_x_rgsw_scratch_rows(rlwe_x_rgsw_decomposer, &rgsw_x_rgsw_decomposer),
1162                rlwe_n,
1163            );
1164
1165            let shares_in_correct_order = (0..total_users)
1166                .map(|i| shares.iter().find(|s| s.user_id() == i).unwrap())
1167                .collect_vec();
1168
1169            let lwe_n = self.parameters().lwe_n().0;
1170            let (users_segments, users_segments_sizes): (Vec<(usize, usize)>, Vec<usize>) = (0
1171                ..total_users)
1172                .map(|(user_id)| {
1173                    let (start_index, end_index) =
1174                        interactive_mult_party_user_id_lwe_segment(user_id, total_users, lwe_n);
1175                    ((start_index, end_index), end_index - start_index)
1176                })
1177                .unzip();
1178
1179            let mut rgsw_cts = Vec::with_capacity(lwe_n);
1180            users_segments
1181                .iter()
1182                .enumerate()
1183                .for_each(|(user_id, user_segment)| {
1184                    let share = shares_in_correct_order[user_id];
1185                    for secret_index in user_segment.0..user_segment.1 {
1186                        let mut rgsw_i =
1187                            share.self_leader_rgsws()[secret_index - user_segment.0].clone();
1188                        // assert already exists in RGSW x RGSW rountine
1189                        assert!(rgsw_i.dimension() == rlwe_x_rgsw_dimension);
1190
1191                        // multiply leader's RGSW ct at `secret_index` with RGSW cts of other users
1192                        // for lwe index `secret_index`
1193                        (0..total_users)
1194                            .filter(|i| i != &user_id)
1195                            .for_each(|other_user_id| {
1196                                let mut offset = 0;
1197                                if other_user_id < user_id {
1198                                    offset = users_segments_sizes[other_user_id];
1199                                }
1200
1201                                let mut other_rgsw_i = shares_in_correct_order[other_user_id]
1202                                    .not_self_leader_rgsws()
1203                                    [secret_index.checked_sub(offset).unwrap()]
1204                                .clone();
1205                                // assert already exists in RGSW x RGSW rountine
1206                                assert!(other_rgsw_i.dimension() == rgsw_x_rgsw_dimension);
1207
1208                                // send to evaluation domain for RGSwxRGSW mul
1209                                other_rgsw_i
1210                                    .iter_rows_mut()
1211                                    .for_each(|r| rlweq_nttop.forward(r.as_mut()));
1212
1213                                rgsw_by_rgsw_inplace(
1214                                    &mut RgswCiphertextMutRef::new(
1215                                        rgsw_i.as_mut(),
1216                                        rlwe_x_rgsw_decomposer.a().decomposition_count(),
1217                                        rlwe_x_rgsw_decomposer.b().decomposition_count(),
1218                                    ),
1219                                    &RgswCiphertextRef::new(
1220                                        other_rgsw_i.as_ref(),
1221                                        rgsw_x_rgsw_decomposer.a().decomposition_count(),
1222                                        rgsw_x_rgsw_decomposer.b().decomposition_count(),
1223                                    ),
1224                                    rlwe_x_rgsw_decomposer,
1225                                    &rgsw_x_rgsw_decomposer,
1226                                    &mut RuntimeScratchMutRef::new(rgsw_x_rgsw_scratch.as_mut()),
1227                                    rlweq_nttop,
1228                                    rlweq_modop,
1229                                );
1230                            });
1231
1232                        rgsw_cts.push(rgsw_i);
1233                    }
1234                });
1235
1236            rgsw_cts
1237        };
1238
1239        // LWE ksks
1240        let mut lwe_ksk = M::R::zeros(rlwe_n * parameters.lwe_decomposition_count().0);
1241        let lweq_modop = &self.pbs_info.lwe_modop;
1242        shares.iter().for_each(|si| {
1243            assert!(si.lwe_ksk().as_ref().len() == rlwe_n * parameters.lwe_decomposition_count().0);
1244            lweq_modop.elwise_add_mut(lwe_ksk.as_mut(), si.lwe_ksk().as_ref())
1245        });
1246
1247        SeededMultiPartyServerKey::new(rgsw_cts, auto_keys, lwe_ksk, cr_seed.clone(), parameters)
1248    }
1249
1250    pub(super) fn aggregate_non_interactive_multi_party_key_share(
1251        &self,
1252        cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
1253        total_users: usize,
1254        key_shares: &[CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
1255            M,
1256            NonInteractiveMultiPartyCrs<[u8; 32]>,
1257        >],
1258    ) -> SeededNonInteractiveMultiPartyServerKey<
1259        M,
1260        NonInteractiveMultiPartyCrs<[u8; 32]>,
1261        BoolParameters<M::MatElement>,
1262    >
1263    where
1264        M: Clone + Debug,
1265        <M as Matrix>::R: RowMut + Clone,
1266    {
1267        assert_eq!(
1268            self.parameters().variant(),
1269            &ParameterVariant::NonInteractiveMultiParty
1270        );
1271
1272        let total_users = key_shares.len();
1273        let key_shares = (0..total_users)
1274            .map(|user_id| {
1275                // find share of user_id
1276                key_shares
1277                    .iter()
1278                    .find(|share| share.user_index() == user_id)
1279                    .expect(&format!("Key Share for user_id={user_id} missing"))
1280            })
1281            .collect_vec();
1282
1283        let rlwe_modop = &self.pbs_info().rlwe_modop;
1284        let nttop = &self.pbs_info().rlwe_nttop;
1285        let ring_size = self.parameters().rlwe_n().0;
1286        let rlwe_q = self.parameters().rlwe_q();
1287        let lwe_modop = self.pbs_info().modop_lweq();
1288
1289        // Generate Key switching key from u_j to s, where u_j user j's RLWE secret and
1290        // s is the ideal RLWE secret.
1291        //
1292        // User j gives [s_j * a_{i, j}  + e  + \beta^i u_j] where a_{i, j} is user j
1293        // specific publicly know polynomial sampled from user j's pseudo random seed
1294        // defined in the protocol.
1295        //
1296        // User k, k != j, gives [s_k * a_{i, j} + e].
1297        //
1298        // We set Ksk(u_j -> s) = [s_j * a_{i, j}  + e  + \beta^i u_j + \sum_{k \in P, k
1299        // != j} s_k * a_{i, j} + e]
1300        let ni_uj_to_s_decomposer = self
1301            .parameters()
1302            .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>();
1303        let mut uj_to_s_ksks = key_shares
1304            .iter()
1305            .map(|share| {
1306                let mut useri_ui_to_s_ksk = share.ui_to_s_ksk().clone();
1307                assert!(
1308                    useri_ui_to_s_ksk.dimension()
1309                        == (ni_uj_to_s_decomposer.decomposition_count(), ring_size)
1310                );
1311                key_shares
1312                    .iter()
1313                    .filter(|x| x.user_index() != share.user_index())
1314                    .for_each(|other_share| {
1315                        let op2 = other_share.ui_to_s_ksk_zero_encs_for_user_i(share.user_index());
1316                        assert!(
1317                            op2.dimension()
1318                                == (ni_uj_to_s_decomposer.decomposition_count(), ring_size)
1319                        );
1320                        izip!(useri_ui_to_s_ksk.iter_rows_mut(), op2.iter_rows()).for_each(
1321                            |(add_to, add_from)| {
1322                                rlwe_modop.elwise_add_mut(add_to.as_mut(), add_from.as_ref())
1323                            },
1324                        );
1325                    });
1326                useri_ui_to_s_ksk
1327            })
1328            .collect_vec();
1329
1330        let rgsw_cts = {
1331            // Send u_j -> s ksk in evaluation domain and sample corresponding a's using
1332            // user j's ksk seed to prepare for upcoming key switches
1333            uj_to_s_ksks.iter_mut().for_each(|ksk_i| {
1334                ksk_i
1335                    .iter_rows_mut()
1336                    .for_each(|r| nttop.forward(r.as_mut()))
1337            });
1338            let uj_to_s_ksks_part_a_eval = key_shares
1339                .iter()
1340                .map(|share| {
1341                    let mut ksk_prng = DefaultSecureRng::new_seeded(
1342                        cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(share.user_index()),
1343                    );
1344                    let mut ais = M::zeros(ni_uj_to_s_decomposer.decomposition_count(), ring_size);
1345
1346                    ais.iter_rows_mut().for_each(|r_ai| {
1347                        RandomFillUniformInModulus::random_fill(
1348                            &mut ksk_prng,
1349                            rlwe_q,
1350                            r_ai.as_mut(),
1351                        );
1352
1353                        nttop.forward(r_ai.as_mut())
1354                    });
1355                    ais
1356                })
1357                .collect_vec();
1358
1359            let rgsw_x_rgsw_decomposer = self
1360                .parameters()
1361                .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1362            let rlwe_x_rgsw_decomposer = self
1363                .parameters()
1364                .rlwe_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1365
1366            let d_max = if rgsw_x_rgsw_decomposer.a().decomposition_count()
1367                > rgsw_x_rgsw_decomposer.b().decomposition_count()
1368            {
1369                rgsw_x_rgsw_decomposer.a().decomposition_count()
1370            } else {
1371                rgsw_x_rgsw_decomposer.b().decomposition_count()
1372            };
1373
1374            let mut scratch_rgsw_x_rgsw = M::zeros(
1375                rgsw_x_rgsw_scratch_rows(&rlwe_x_rgsw_decomposer, &rgsw_x_rgsw_decomposer),
1376                self.parameters().rlwe_n().0,
1377            );
1378
1379            // Recall that given u_j * a_{i, l} + e + \beta^i X^{s_j[l]} from user j
1380            //
1381            // We generate:
1382            //
1383            // - RLWE(-s \beta^i X^{s_j[l]}) = KS_{u_j -> s}(a_{i, l} * s + e) + (0 , u_j *
1384            //   a_{i, l} + e + \beta^i X^{s_j[l]}), where KS_{u_j -> s}(a_{i, l} * s + e) =
1385            //   RLWE_s(a_{i, l} * u_j)
1386            // - RLWE(\beta^i X^{s_j[l]}) = KS_{u_j -> s}(-a_{i,l}) + (u_j * a_{i, l} + e +
1387            //   \beta^i X^{s_j[l]}, 0), where KS_{u_j -> s}(-a_{i,l}) = RLWE_s(-a_{i,l} *
1388            //   u_j)
1389            //
1390            // a_{i, l} * s + e = \sum_{j \in P} a_{i, l} * s_{j} + e
1391            let user_segments = (0..total_users)
1392                .map(|user_id| {
1393                    interactive_mult_party_user_id_lwe_segment(
1394                        user_id,
1395                        total_users,
1396                        self.parameters().lwe_n().0,
1397                    )
1398                })
1399                .collect_vec();
1400            // Note: Each user is assigned a contigous LWE segement and the LWE dimension is
1401            // split approximately uniformly across all users. Hence, concatenation of all
1402            // user specific lwe segments will give LWE dimension.
1403            let rgsw_cts = user_segments
1404                .into_iter()
1405                .enumerate()
1406                .flat_map(|(user_id, lwe_segment)| {
1407                    (lwe_segment.0..lwe_segment.1)
1408                        .into_iter()
1409                        .map(|lwe_index| {
1410                            // We sample d_b `-a_i`s to key switch and generate RLWE'(m). But before
1411                            // we sampling we need to puncture a_prng d_max - d_b times to align
1412                            // a_i's. After sampling we decompose `-a_i`s and send them to
1413                            // evaluation domain for upcoming key switches.
1414                            let mut a_prng = DefaultSecureRng::new_seeded(
1415                                cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1416                            );
1417
1418                            let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1419                            (0..d_max - rgsw_x_rgsw_decomposer.b().decomposition_count()).for_each(
1420                                |_| {
1421                                    RandomFillUniformInModulus::random_fill(
1422                                        &mut a_prng,
1423                                        rlwe_q,
1424                                        scratch.as_mut(),
1425                                    );
1426                                },
1427                            );
1428
1429                            let decomp_neg_ais = (0..rgsw_x_rgsw_decomposer
1430                                .b()
1431                                .decomposition_count())
1432                                .map(|_| {
1433                                    RandomFillUniformInModulus::random_fill(
1434                                        &mut a_prng,
1435                                        rlwe_q,
1436                                        scratch.as_mut(),
1437                                    );
1438                                    rlwe_modop.elwise_neg_mut(scratch.as_mut());
1439
1440                                    let mut decomp_neg_ai = M::zeros(
1441                                        ni_uj_to_s_decomposer.decomposition_count(),
1442                                        self.parameters().rlwe_n().0,
1443                                    );
1444                                    scratch.as_ref().iter().enumerate().for_each(|(index, el)| {
1445                                        ni_uj_to_s_decomposer
1446                                            .decompose_iter(el)
1447                                            .enumerate()
1448                                            .for_each(|(row_j, d_el)| {
1449                                                (decomp_neg_ai.as_mut()[row_j]).as_mut()[index] =
1450                                                    d_el;
1451                                            });
1452                                    });
1453
1454                                    decomp_neg_ai
1455                                        .iter_rows_mut()
1456                                        .for_each(|ri| nttop.forward(ri.as_mut()));
1457
1458                                    decomp_neg_ai
1459                                })
1460                                .collect_vec();
1461
1462                            // Aggregate zero encryptions to produce a_{i, l} * s + e =
1463                            // \sum_{k in P} a_{i, l} * s_{k} + e where s is the ideal RLWE
1464                            // secret. Aggregated  a_{i, l} * s + e are key switched using
1465                            // Ksk(u_j -> s) to produce RLWE_{s}(a_{i, l} * s) which are
1466                            // then use to produce RLWE'(-sX^{s_{lwe}[l]}).
1467                            // Hence, after aggregation we decompose a_{i, l} * s + e to
1468                            // prepare for key switching
1469                            let ni_rgsw_zero_encs = (0..rgsw_x_rgsw_decomposer
1470                                .a()
1471                                .decomposition_count())
1472                                .map(|i| {
1473                                    let mut sum = M::R::zeros(self.parameters().rlwe_n().0);
1474                                    key_shares.iter().for_each(|k| {
1475                                        let to_add_ref = k
1476                                            .ni_rgsw_zero_enc_for_lwe_index(lwe_index)
1477                                            .get_row_slice(i);
1478                                        assert!(to_add_ref.len() == self.parameters().rlwe_n().0);
1479                                        rlwe_modop.elwise_add_mut(sum.as_mut(), to_add_ref);
1480                                    });
1481
1482                                    // decompose
1483                                    let mut decomp_sum = M::zeros(
1484                                        ni_uj_to_s_decomposer.decomposition_count(),
1485                                        self.parameters().rlwe_n().0,
1486                                    );
1487                                    sum.as_ref().iter().enumerate().for_each(|(index, el)| {
1488                                        ni_uj_to_s_decomposer
1489                                            .decompose_iter(el)
1490                                            .enumerate()
1491                                            .for_each(|(row_j, d_el)| {
1492                                                (decomp_sum.as_mut()[row_j]).as_mut()[index] = d_el;
1493                                            });
1494                                    });
1495
1496                                    decomp_sum
1497                                        .iter_rows_mut()
1498                                        .for_each(|r| nttop.forward(r.as_mut()));
1499
1500                                    decomp_sum
1501                                })
1502                                .collect_vec();
1503
1504                            // Produce RGSW(X^{s_{j=user_id, lwe}[l]}) for the
1505                            // leader, ie user's id = user_id.
1506                            // Recall leader's RGSW ciphertext must be constructed
1507                            // for RLWE x RGSW multiplication, and is then used
1508                            // to accumulate, using RGSW x RGSW multiplication,
1509                            // X^{s_{j != user_id, lwe}[l]} from other users.
1510                            let mut rgsw_i = produce_rgsw_ciphertext_from_ni_rgsw(
1511                                key_shares[user_id]
1512                                    .ni_rgsw_cts_for_self_leader_lwe_index(lwe_index),
1513                                &ni_rgsw_zero_encs[rgsw_x_rgsw_decomposer
1514                                    .a()
1515                                    .decomposition_count()
1516                                    - rlwe_x_rgsw_decomposer.a().decomposition_count()..],
1517                                &decomp_neg_ais[rgsw_x_rgsw_decomposer.b().decomposition_count()
1518                                    - rlwe_x_rgsw_decomposer.b().decomposition_count()..],
1519                                &rlwe_x_rgsw_decomposer,
1520                                self.parameters(),
1521                                (&uj_to_s_ksks[user_id], &uj_to_s_ksks_part_a_eval[user_id]),
1522                                rlwe_modop,
1523                                nttop,
1524                                false,
1525                            );
1526
1527                            // RGSW for lwe_index of users that are not leader.
1528                            //
1529                            // Recall that for users that are not leader for the
1530                            // lwe_index we require to produce RGSW ciphertext for
1531                            // RGSW x RGSW product
1532                            (0..total_users)
1533                                .filter(|i| *i != user_id)
1534                                .for_each(|other_user_id| {
1535                                    let mut other_rgsw_i = produce_rgsw_ciphertext_from_ni_rgsw(
1536                                        key_shares[other_user_id]
1537                                            .ni_rgsw_cts_for_self_not_leader_lwe_index(lwe_index),
1538                                        &ni_rgsw_zero_encs,
1539                                        &decomp_neg_ais,
1540                                        &rgsw_x_rgsw_decomposer,
1541                                        self.parameters(),
1542                                        (
1543                                            &uj_to_s_ksks[other_user_id],
1544                                            &uj_to_s_ksks_part_a_eval[other_user_id],
1545                                        ),
1546                                        rlwe_modop,
1547                                        nttop,
1548                                        true,
1549                                    );
1550
1551                                    rgsw_by_rgsw_inplace(
1552                                        &mut RgswCiphertextMutRef::new(
1553                                            rgsw_i.as_mut(),
1554                                            rlwe_x_rgsw_decomposer.a().decomposition_count(),
1555                                            rlwe_x_rgsw_decomposer.b().decomposition_count(),
1556                                        ),
1557                                        &RgswCiphertextRef::new(
1558                                            other_rgsw_i.as_ref(),
1559                                            rgsw_x_rgsw_decomposer.a().decomposition_count(),
1560                                            rgsw_x_rgsw_decomposer.b().decomposition_count(),
1561                                        ),
1562                                        &rlwe_x_rgsw_decomposer,
1563                                        &rgsw_x_rgsw_decomposer,
1564                                        &mut RuntimeScratchMutRef::new(
1565                                            scratch_rgsw_x_rgsw.as_mut(),
1566                                        ),
1567                                        nttop,
1568                                        rlwe_modop,
1569                                    )
1570                                });
1571
1572                            rgsw_i
1573                        })
1574                        .collect_vec()
1575                })
1576                .collect_vec();
1577
1578            // put u_j to s ksk in coefficient domain
1579            uj_to_s_ksks.iter_mut().for_each(|ksk_i| {
1580                ksk_i
1581                    .iter_rows_mut()
1582                    .for_each(|r| nttop.backward(r.as_mut()))
1583            });
1584
1585            rgsw_cts
1586        };
1587
1588        // auto keys
1589        let auto_keys = {
1590            let mut auto_keys = HashMap::new();
1591            let auto_elements_dlog = self.parameters().auto_element_dlogs();
1592            for i in auto_elements_dlog.into_iter() {
1593                let mut key = M::zeros(self.parameters().auto_decomposition_count().0, ring_size);
1594
1595                key_shares.iter().for_each(|s| {
1596                    let auto_key_share_i =
1597                        s.auto_keys_share().get(&i).expect("Auto key {i} missing");
1598                    assert!(
1599                        auto_key_share_i.dimension()
1600                            == (self.parameters().auto_decomposition_count().0, ring_size)
1601                    );
1602                    izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
1603                        |(partb_out, partb_share)| {
1604                            rlwe_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
1605                        },
1606                    );
1607                });
1608
1609                auto_keys.insert(i, key);
1610            }
1611            auto_keys
1612        };
1613
1614        // LWE ksk
1615        let lwe_ksk = {
1616            let mut lwe_ksk =
1617                M::R::zeros(self.parameters().lwe_decomposition_count().0 * ring_size);
1618            key_shares.iter().for_each(|s| {
1619                assert!(
1620                    s.lwe_ksk_share().as_ref().len()
1621                        == self.parameters().lwe_decomposition_count().0 * ring_size
1622                );
1623                lwe_modop.elwise_add_mut(lwe_ksk.as_mut(), s.lwe_ksk_share().as_ref());
1624            });
1625            lwe_ksk
1626        };
1627
1628        SeededNonInteractiveMultiPartyServerKey::new(
1629            uj_to_s_ksks,
1630            rgsw_cts,
1631            auto_keys,
1632            lwe_ksk,
1633            cr_seed.clone(),
1634            self.parameters().clone(),
1635        )
1636    }
1637
1638    pub(super) fn non_interactive_multi_party_key_share<
1639        K: NonInteractiveMultiPartyClientKey<Element = i32>,
1640    >(
1641        &self,
1642        cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
1643        self_index: usize,
1644        total_users: usize,
1645        client_key: &K,
1646    ) -> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
1647        M,
1648        NonInteractiveMultiPartyCrs<[u8; 32]>,
1649    > {
1650        assert_eq!(
1651            self.parameters().variant(),
1652            &ParameterVariant::NonInteractiveMultiParty
1653        );
1654
1655        // TODO:  check whether parameters support `total_users`
1656        let nttop = self.pbs_info().nttop_rlweq();
1657        let rlwe_modop = self.pbs_info().modop_rlweq();
1658        let ring_size = self.pbs_info().rlwe_n();
1659        let rlwe_q = self.parameters().rlwe_q();
1660
1661        let sk_rlwe = client_key.sk_rlwe();
1662        let sk_u_rlwe = client_key.sk_u_rlwe();
1663        let sk_lwe = client_key.sk_lwe();
1664
1665        let (ui_to_s_ksk, ksk_zero_encs_for_others) = DefaultSecureRng::with_local_mut(|rng| {
1666            // ui_to_s_ksk
1667            let non_interactive_decomposer = self
1668                .parameters()
1669                .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>(
1670                );
1671            let non_interactive_gadget_vec = non_interactive_decomposer.gadget_vector();
1672            let ui_to_s_ksk = {
1673                let mut p_rng = DefaultSecureRng::new_seeded(
1674                    cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(self_index),
1675                );
1676
1677                non_interactive_ksk_gen::<M, _, _, _, _, _>(
1678                    &sk_rlwe,
1679                    &sk_u_rlwe,
1680                    &non_interactive_gadget_vec,
1681                    &mut p_rng,
1682                    rng,
1683                    nttop,
1684                    rlwe_modop,
1685                )
1686            };
1687
1688            // zero encryptions for others uj_to_s ksk
1689            let all_users_except_self = (0..total_users).filter(|x| *x != self_index);
1690            let zero_encs_for_others = all_users_except_self
1691                .map(|other_user_index| {
1692                    let mut p_rng = DefaultSecureRng::new_seeded(
1693                        cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(other_user_index),
1694                    );
1695                    let zero_encs =
1696                        non_interactive_ksk_zero_encryptions_for_other_party_i::<M, _, _, _, _, _>(
1697                            &sk_rlwe,
1698                            &non_interactive_gadget_vec,
1699                            &mut p_rng,
1700                            rng,
1701                            nttop,
1702                            rlwe_modop,
1703                        );
1704                    zero_encs
1705                })
1706                .collect_vec();
1707
1708            (ui_to_s_ksk, zero_encs_for_others)
1709        });
1710
1711        // Non-interactive RGSW cts
1712        let (ni_rgsw_zero_encs, self_leader_ni_rgsw_cts, not_self_leader_rgsw_cts) = {
1713            let rgsw_x_rgsw_decomposer = self
1714                .parameters()
1715                .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1716            let rlwe_x_rgsw_decomposer = self
1717                .parameters()
1718                .rlwe_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1719
1720            // We assume that d_{a/b} for RGSW x RGSW are always < d'_{a/b} for RLWE x RGSW
1721            assert!(
1722                rlwe_x_rgsw_decomposer.a().decomposition_count()
1723                    < rgsw_x_rgsw_decomposer.a().decomposition_count()
1724            );
1725            assert!(
1726                rlwe_x_rgsw_decomposer.b().decomposition_count()
1727                    < rgsw_x_rgsw_decomposer.b().decomposition_count()
1728            );
1729
1730            let sj_poly_eval = {
1731                let mut s = M::R::try_convert_from(&sk_rlwe, rlwe_q);
1732                nttop.forward(s.as_mut());
1733                s
1734            };
1735
1736            let d_rgsw_a = rgsw_x_rgsw_decomposer.a().decomposition_count();
1737            let d_rgsw_b = rgsw_x_rgsw_decomposer.b().decomposition_count();
1738            let d_max = std::cmp::max(d_rgsw_a, d_rgsw_b);
1739
1740            // Zero encyptions for each LWE index. We generate d_a zero encryptions for each
1741            // LWE index using a_{i, l} with i \in {d_max - d_a , d_max) and l = lwe_index
1742            let zero_encs = {
1743                (0..self.parameters().lwe_n().0)
1744                    .map(|lwe_index| {
1745                        let mut p_rng = DefaultSecureRng::new_seeded(
1746                            cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1747                        );
1748
1749                        let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1750
1751                        // puncture seeded prng d_max - d_a times
1752                        (0..(d_max - d_rgsw_a)).into_iter().for_each(|_| {
1753                            RandomFillUniformInModulus::random_fill(
1754                                &mut p_rng,
1755                                rlwe_q,
1756                                scratch.as_mut(),
1757                            );
1758                        });
1759
1760                        let mut zero_enc = M::zeros(d_rgsw_a, self.parameters().rlwe_n().0);
1761                        zero_enc.iter_rows_mut().for_each(|out| {
1762                            // sample a_i
1763                            RandomFillUniformInModulus::random_fill(
1764                                &mut p_rng,
1765                                rlwe_q,
1766                                out.as_mut(),
1767                            );
1768
1769                            // a_i * s_j
1770                            nttop.forward(out.as_mut());
1771                            rlwe_modop.elwise_mul_mut(out.as_mut(), sj_poly_eval.as_ref());
1772                            nttop.backward(out.as_mut());
1773
1774                            // a_j * s_j + e
1775                            DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1776                                RandomFillGaussianInModulus::random_fill(
1777                                    rng,
1778                                    rlwe_q,
1779                                    scratch.as_mut(),
1780                                );
1781                            });
1782
1783                            rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1784                        });
1785
1786                        zero_enc
1787                    })
1788                    .collect_vec()
1789            };
1790
1791            let uj_poly_eval = {
1792                let mut u = M::R::try_convert_from(&sk_u_rlwe, rlwe_q);
1793                nttop.forward(u.as_mut());
1794                u
1795            };
1796
1797            // Generate non-interactive RGSW ciphertexts a_{i, l} u_j + e + \beta X^{s_j[l]}
1798            // for i \in (0, d_max]
1799            let (self_start_index, self_end_index) = interactive_mult_party_user_id_lwe_segment(
1800                self_index,
1801                total_users,
1802                self.parameters().lwe_n().0,
1803            );
1804
1805            // For LWE indices [self_start_index, self_end_index) user generates
1806            // non-interactive RGSW cts for RLWE x RGSW product. We refer to
1807            // such indices as where user is the leader. For the rest of
1808            // the indices user generates non-interactive RGWS cts for RGSW x
1809            // RGSW multiplication. We refer to such indices as where user is
1810            // not the leader.
1811            let self_leader_ni_rgsw_cts = {
1812                let max_rlwe_x_rgsw_decomposer = if rlwe_x_rgsw_decomposer.a().decomposition_count()
1813                    > rlwe_x_rgsw_decomposer.b().decomposition_count()
1814                {
1815                    rlwe_x_rgsw_decomposer.a()
1816                } else {
1817                    rlwe_x_rgsw_decomposer.b()
1818                };
1819
1820                let gadget_vec = max_rlwe_x_rgsw_decomposer.gadget_vector();
1821
1822                (self_start_index..self_end_index)
1823                    .map(|lwe_index| {
1824                        let mut p_rng = DefaultSecureRng::new_seeded(
1825                            cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1826                        );
1827
1828                        // puncture p_rng d_max - d'_max time to align with `a_{i, l}`s used to
1829                        // produce RGSW cts for RGSW x RGSW
1830                        let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1831                        (0..(d_max - max_rlwe_x_rgsw_decomposer.decomposition_count()))
1832                            .into_iter()
1833                            .for_each(|_| {
1834                                RandomFillUniformInModulus::random_fill(
1835                                    &mut p_rng,
1836                                    rlwe_q,
1837                                    scratch.as_mut(),
1838                                );
1839                            });
1840
1841                        let mut ni_rgsw_cts = M::zeros(
1842                            max_rlwe_x_rgsw_decomposer.decomposition_count(),
1843                            self.parameters().rlwe_n().0,
1844                        );
1845
1846                        // X^{s_{j, lwe}[l]}
1847                        let m_poly = encode_x_pow_si_with_emebedding_factor::<M::R, _>(
1848                            sk_lwe[lwe_index],
1849                            self.pbs_info().embedding_factor(),
1850                            self.parameters().rlwe_n().0,
1851                            rlwe_q,
1852                        );
1853
1854                        izip!(ni_rgsw_cts.iter_rows_mut(), gadget_vec.iter()).for_each(
1855                            |(out, beta)| {
1856                                // sample a_i
1857                                RandomFillUniformInModulus::random_fill(
1858                                    &mut p_rng,
1859                                    rlwe_q,
1860                                    out.as_mut(),
1861                                );
1862
1863                                // u_j * a_i
1864                                nttop.forward(out.as_mut());
1865                                rlwe_modop.elwise_mul_mut(out.as_mut(), uj_poly_eval.as_ref());
1866                                nttop.backward(out.as_mut());
1867
1868                                // u_j + a_i + e
1869                                DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1870                                    RandomFillGaussianInModulus::random_fill(
1871                                        rng,
1872                                        rlwe_q,
1873                                        scratch.as_mut(),
1874                                    );
1875                                });
1876                                rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1877
1878                                // u_j + a_i + e + beta m
1879                                rlwe_modop.elwise_scalar_mul(
1880                                    scratch.as_mut(),
1881                                    m_poly.as_ref(),
1882                                    beta,
1883                                );
1884                                rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1885                            },
1886                        );
1887
1888                        ni_rgsw_cts
1889                    })
1890                    .collect_vec()
1891            };
1892
1893            let not_self_leader_rgsw_cts = {
1894                let max_rgsw_x_rgsw_decomposer = if rgsw_x_rgsw_decomposer.a().decomposition_count()
1895                    > rgsw_x_rgsw_decomposer.b().decomposition_count()
1896                {
1897                    rgsw_x_rgsw_decomposer.a()
1898                } else {
1899                    rgsw_x_rgsw_decomposer.b()
1900                };
1901                let gadget_vec = max_rgsw_x_rgsw_decomposer.gadget_vector();
1902
1903                ((0..self_start_index).chain(self_end_index..self.parameters().lwe_n().0))
1904                    .map(|lwe_index| {
1905                        let mut p_rng = DefaultSecureRng::new_seeded(
1906                            cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1907                        );
1908                        let mut ni_rgsw_cts = M::zeros(
1909                            max_rgsw_x_rgsw_decomposer.decomposition_count(),
1910                            self.parameters().rlwe_n().0,
1911                        );
1912                        let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1913
1914                        // X^{s_{j, lwe}[l]}
1915                        let m_poly = encode_x_pow_si_with_emebedding_factor::<M::R, _>(
1916                            sk_lwe[lwe_index],
1917                            self.pbs_info().embedding_factor(),
1918                            self.parameters().rlwe_n().0,
1919                            rlwe_q,
1920                        );
1921
1922                        izip!(ni_rgsw_cts.iter_rows_mut(), gadget_vec.iter()).for_each(
1923                            |(out, beta)| {
1924                                // sample a_i
1925                                RandomFillUniformInModulus::random_fill(
1926                                    &mut p_rng,
1927                                    rlwe_q,
1928                                    out.as_mut(),
1929                                );
1930
1931                                // u_j * a_i
1932                                nttop.forward(out.as_mut());
1933                                rlwe_modop.elwise_mul_mut(out.as_mut(), uj_poly_eval.as_ref());
1934                                nttop.backward(out.as_mut());
1935
1936                                // u_j + a_i + e
1937                                DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1938                                    RandomFillGaussianInModulus::random_fill(
1939                                        rng,
1940                                        rlwe_q,
1941                                        scratch.as_mut(),
1942                                    );
1943                                });
1944                                rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1945
1946                                // u_j * a_i + e + beta m
1947                                rlwe_modop.elwise_scalar_mul(
1948                                    scratch.as_mut(),
1949                                    m_poly.as_ref(),
1950                                    beta,
1951                                );
1952                                rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1953                            },
1954                        );
1955
1956                        ni_rgsw_cts
1957                    })
1958                    .collect_vec()
1959            };
1960
1961            (zero_encs, self_leader_ni_rgsw_cts, not_self_leader_rgsw_cts)
1962        };
1963
1964        // Auto key share
1965        let auto_keys_share = {
1966            let auto_seed = cr_seed.auto_keys_cts_seed::<DefaultSecureRng>();
1967            self._common_rountine_multi_party_auto_keys_share_gen(auto_seed, &sk_rlwe)
1968        };
1969
1970        // Lwe Ksk share
1971        let lwe_ksk_share = {
1972            let lwe_ksk_seed = cr_seed.lwe_ksk_cts_seed::<DefaultSecureRng>();
1973            self._common_rountine_multi_party_lwe_ksk_share_gen(lwe_ksk_seed, &sk_rlwe, &sk_lwe)
1974        };
1975
1976        CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare::new(
1977            self_leader_ni_rgsw_cts,
1978            not_self_leader_rgsw_cts,
1979            ni_rgsw_zero_encs,
1980            ui_to_s_ksk,
1981            ksk_zero_encs_for_others,
1982            auto_keys_share,
1983            lwe_ksk_share,
1984            self_index,
1985            total_users,
1986            self.parameters().lwe_n().0,
1987            cr_seed.clone(),
1988        )
1989    }
1990
1991    fn _common_rountine_multi_party_auto_keys_share_gen(
1992        &self,
1993        auto_seed: <DefaultSecureRng as NewWithSeed>::Seed,
1994        sk_rlwe: &[i32],
1995    ) -> HashMap<usize, M> {
1996        let g = self.pbs_info.parameters.g();
1997        let ring_size = self.pbs_info.parameters.rlwe_n().0;
1998        let br_q = self.pbs_info.parameters.br_q();
1999        let rlweq_modop = &self.pbs_info.rlwe_modop;
2000        let rlweq_nttop = &self.pbs_info.rlwe_nttop;
2001
2002        DefaultSecureRng::with_local_mut(|rng| {
2003            let mut p_rng = DefaultSecureRng::new_seeded(auto_seed);
2004
2005            let mut auto_keys = HashMap::new();
2006            let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
2007            let auto_element_dlogs = self.pbs_info.parameters.auto_element_dlogs();
2008
2009            for i in auto_element_dlogs.into_iter() {
2010                let g_pow = if i == 0 {
2011                    -(g as isize)
2012                } else {
2013                    (g.pow(i as u32) % br_q) as isize
2014                };
2015
2016                let mut ksk_out = M::zeros(
2017                    self.pbs_info.auto_decomposer.decomposition_count(),
2018                    ring_size,
2019                );
2020                seeded_auto_key_gen(
2021                    &mut ksk_out,
2022                    sk_rlwe,
2023                    g_pow,
2024                    &auto_gadget,
2025                    rlweq_modop,
2026                    rlweq_nttop,
2027                    &mut p_rng,
2028                    rng,
2029                );
2030                auto_keys.insert(i, ksk_out);
2031            }
2032
2033            auto_keys
2034        })
2035    }
2036
2037    fn _common_rountine_multi_party_lwe_ksk_share_gen(
2038        &self,
2039        lwe_ksk_seed: <DefaultSecureRng as NewWithSeed>::Seed,
2040        sk_rlwe: &[i32],
2041        sk_lwe: &[i32],
2042    ) -> M::R {
2043        DefaultSecureRng::with_local_mut(|rng| {
2044            let mut p_rng = DefaultSecureRng::new_seeded(lwe_ksk_seed);
2045            let lwe_modop = &self.pbs_info.lwe_modop;
2046            let d_lwe_gadget_vec = self.pbs_info.lwe_decomposer.gadget_vector();
2047            seeded_lwe_ksk_keygen(
2048                sk_rlwe,
2049                sk_lwe,
2050                &d_lwe_gadget_vec,
2051                lwe_modop,
2052                &mut p_rng,
2053                rng,
2054            )
2055        })
2056    }
2057
2058    pub(super) fn multi_party_public_key_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
2059        &self,
2060        cr_seed: &MultiPartyCrs<[u8; 32]>,
2061        client_key: &K,
2062    ) -> CommonReferenceSeededCollectivePublicKeyShare<
2063        <M as Matrix>::R,
2064        [u8; 32],
2065        BoolParameters<<M as Matrix>::MatElement>,
2066    > {
2067        DefaultSecureRng::with_local_mut(|rng| {
2068            let mut share_out = M::R::zeros(self.pbs_info.parameters.rlwe_n().0);
2069            let modop = &self.pbs_info.rlwe_modop;
2070            let nttop = &self.pbs_info.rlwe_nttop;
2071            let pk_seed = cr_seed.public_key_share_seed::<DefaultSecureRng>();
2072            let mut main_prng = DefaultSecureRng::new_seeded(pk_seed);
2073            public_key_share(
2074                &mut share_out,
2075                &client_key.sk_rlwe(),
2076                modop,
2077                nttop,
2078                &mut main_prng,
2079                rng,
2080            );
2081            CommonReferenceSeededCollectivePublicKeyShare::new(
2082                share_out,
2083                pk_seed,
2084                self.pbs_info.parameters.clone(),
2085            )
2086        })
2087    }
2088
2089    pub(super) fn multi_party_decryption_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
2090        &self,
2091        lwe_ct: &M::R,
2092        client_key: &K,
2093    ) -> <M as Matrix>::MatElement {
2094        assert!(lwe_ct.as_ref().len() == self.pbs_info.parameters.rlwe_n().0 + 1);
2095        let modop = &self.pbs_info.rlwe_modop;
2096        let mut neg_s =
2097            M::R::try_convert_from(&client_key.sk_rlwe(), &self.pbs_info.parameters.rlwe_q());
2098        modop.elwise_neg_mut(neg_s.as_mut());
2099
2100        let mut neg_sa = M::MatElement::zero();
2101        izip!(lwe_ct.as_ref().iter().skip(1), neg_s.as_ref().iter()).for_each(|(ai, nsi)| {
2102            neg_sa = modop.add(&neg_sa, &modop.mul(ai, nsi));
2103        });
2104
2105        let e = DefaultSecureRng::with_local_mut(|rng| {
2106            RandomGaussianElementInModulus::random(rng, self.pbs_info.parameters.rlwe_q())
2107        });
2108        let share = modop.add(&neg_sa, &e);
2109
2110        share
2111    }
2112
2113    pub(crate) fn multi_party_decrypt(&self, shares: &[M::MatElement], lwe_ct: &M::R) -> bool {
2114        let modop = &self.pbs_info.rlwe_modop;
2115        let mut sum_a = M::MatElement::zero();
2116        shares
2117            .iter()
2118            .for_each(|share_i| sum_a = modop.add(&sum_a, &share_i));
2119
2120        let encoded_m = modop.add(&lwe_ct.as_ref()[0], &sum_a);
2121        self.pbs_info.parameters.rlwe_q().decode(encoded_m)
2122    }
2123
2124    pub(crate) fn pk_encrypt(&self, pk: &M, m: bool) -> M::R {
2125        self.pk_encrypt_batched(pk, &vec![m]).remove(0)
2126    }
2127
2128    /// Encrypts a batch booleans as multiple LWE ciphertexts.
2129    ///
2130    /// For public key encryption we first encrypt `m` as a RLWE ciphertext and
2131    /// then sample extract LWE samples at required indices.
2132    ///
2133    /// - TODO(Jay:) Communication can be improved by not sample exctracting and
2134    ///   instead just truncate degree 0 values (part Bs)
2135    pub(crate) fn pk_encrypt_batched(&self, pk: &M, m: &[bool]) -> Vec<M::R> {
2136        DefaultSecureRng::with_local_mut(|rng| {
2137            let ring_size = self.pbs_info.parameters.rlwe_n().0;
2138            assert!(
2139                m.len() <= ring_size,
2140                "Cannot batch encrypt > ring_size{ring_size} elements at once"
2141            );
2142
2143            let modop = &self.pbs_info.rlwe_modop;
2144            let nttop = &self.pbs_info.rlwe_nttop;
2145
2146            // RLWE(0)
2147            // sample ephemeral key u
2148            let mut u = vec![0i32; ring_size];
2149            fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
2150            let mut u = M::R::try_convert_from(&u, &self.pbs_info.parameters.rlwe_q());
2151            nttop.forward(u.as_mut());
2152
2153            let mut ua = M::R::zeros(ring_size);
2154            ua.as_mut().copy_from_slice(pk.get_row_slice(0));
2155            let mut ub = M::R::zeros(ring_size);
2156            ub.as_mut().copy_from_slice(pk.get_row_slice(1));
2157
2158            // a*u
2159            nttop.forward(ua.as_mut());
2160            modop.elwise_mul_mut(ua.as_mut(), u.as_ref());
2161            nttop.backward(ua.as_mut());
2162
2163            // b*u
2164            nttop.forward(ub.as_mut());
2165            modop.elwise_mul_mut(ub.as_mut(), u.as_ref());
2166            nttop.backward(ub.as_mut());
2167
2168            let mut rlwe = M::zeros(2, ring_size);
2169            // sample error
2170            rlwe.iter_rows_mut().for_each(|ri| {
2171                RandomFillGaussianInModulus::<[M::MatElement], CiphertextModulus<M::MatElement>>::random_fill(
2172                    rng,
2173                    &self.pbs_info.parameters.rlwe_q(),
2174                    ri.as_mut(),
2175                );
2176            });
2177
2178            // a*u + e0
2179            modop.elwise_add_mut(rlwe.get_row_mut(0), ua.as_ref());
2180            // b*u + e1
2181            modop.elwise_add_mut(rlwe.get_row_mut(1), ub.as_ref());
2182
2183            //FIXME(Jay): Figure out a way to get Q/8 form modulus
2184            let mut m_vec = M::R::zeros(ring_size);
2185            izip!(m_vec.as_mut().iter_mut(), m.iter()).for_each(|(m_el, m_bool)| {
2186                if *m_bool {
2187                    // Q/8
2188                    *m_el = self.pbs_info.rlwe_q().true_el()
2189                } else {
2190                    // -Q/8
2191                    *m_el = self.pbs_info.rlwe_q().false_el()
2192                }
2193            });
2194
2195            // b*u + e1 + m
2196            modop.elwise_add_mut(rlwe.get_row_mut(1), m_vec.as_ref());
2197            // rlwe.set(1, 0, modop.add(rlwe.get(1, 0), &m));
2198
2199            // sample extract index required indices
2200            let samples = m.len();
2201            (0..samples)
2202                .into_iter()
2203                .map(|i| {
2204                    let mut lwe_out = M::R::zeros(ring_size + 1);
2205                    sample_extract(&mut lwe_out, &rlwe, modop, i);
2206                    lwe_out
2207                })
2208                .collect_vec()
2209        })
2210    }
2211
2212    pub fn sk_encrypt<K: SinglePartyClientKey<Element = i32>>(
2213        &self,
2214        m: bool,
2215        client_key: &K,
2216    ) -> M::R {
2217        //FIXME(Jay): Figure out a way to get Q/8 form modulus
2218        let m = if m {
2219            // Q/8
2220            self.pbs_info.rlwe_q().true_el()
2221        } else {
2222            // -Q/8
2223            self.pbs_info.rlwe_q().false_el()
2224        };
2225
2226        DefaultSecureRng::with_local_mut(|rng| {
2227            encrypt_lwe(&m, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop, rng)
2228        })
2229    }
2230
2231    pub fn sk_decrypt<K: SinglePartyClientKey<Element = i32>>(
2232        &self,
2233        lwe_ct: &M::R,
2234        client_key: &K,
2235    ) -> bool {
2236        let m = decrypt_lwe(lwe_ct, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop);
2237        self.pbs_info.rlwe_q().decode(m)
2238    }
2239}
2240
2241impl<M, NttOp, RlweModOp, LweModOp, Skey> BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
2242where
2243    M: MatrixMut + MatrixEntity,
2244    M::R: RowMut + RowEntity,
2245    M::MatElement: PrimInt + FromPrimitive + One + Copy + Zero + Display + WrappingSub + NumInfo,
2246    RlweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2247    LweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2248    NttOp: Ntt<Element = M::MatElement>,
2249{
2250    /// Returns c0 + c1 + Q/4
2251    fn _add_and_shift_lwe_cts(&self, c0: &mut M::R, c1: &M::R) {
2252        let modop = &self.pbs_info.rlwe_modop;
2253        modop.elwise_add_mut(c0.as_mut(), c1.as_ref());
2254        // +Q/4
2255        c0.as_mut()[0] = modop.add(&c0.as_ref()[0], &self.pbs_info.rlwe_qby4);
2256    }
2257
2258    /// Returns 2(c0 - c1) + Q/4
2259    fn _subtract_double_lwe_cts(&self, c0: &mut M::R, c1: &M::R) {
2260        let modop = &self.pbs_info.rlwe_modop;
2261        // c0 - c1
2262        modop.elwise_sub_mut(c0.as_mut(), c1.as_ref());
2263
2264        // double
2265        c0.as_mut().iter_mut().for_each(|v| *v = modop.add(v, v));
2266    }
2267}
2268
2269impl<M, NttOp, RlweModOp, LweModOp, Skey> BooleanGates
2270    for BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
2271where
2272    M: MatrixMut + MatrixEntity,
2273    M::R: RowMut + RowEntity + Clone,
2274    M::MatElement: PrimInt
2275        + FromPrimitive
2276        + One
2277        + Copy
2278        + Zero
2279        + Display
2280        + WrappingSub
2281        + NumInfo
2282        + From<bool>
2283        + WrappingAdd
2284        + Debug,
2285    RlweModOp: VectorOps<Element = M::MatElement>
2286        + ArithmeticOps<Element = M::MatElement>
2287        + ShoupMatrixFMA<M::R>,
2288    LweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2289    NttOp: Ntt<Element = M::MatElement>,
2290    Skey: PbsKey<AutoKey = <Skey as PbsKey>::RgswCt, LweKskKey = M>,
2291    <Skey as PbsKey>::RgswCt: WithShoupRepr<M = M>,
2292{
2293    type Ciphertext = M::R;
2294    type Key = Skey;
2295
2296    fn nand_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2297        self._add_and_shift_lwe_cts(c0, c1);
2298
2299        // PBS
2300        pbs(
2301            &self.pbs_info,
2302            &self.nand_test_vec,
2303            c0,
2304            server_key,
2305            &mut self.scratch_memory.lwe_vector,
2306            &mut self.scratch_memory.decomposition_matrix,
2307        );
2308    }
2309
2310    fn and_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2311        self._add_and_shift_lwe_cts(c0, c1);
2312
2313        // PBS
2314        pbs(
2315            &self.pbs_info,
2316            &self.and_test_vec,
2317            c0,
2318            server_key,
2319            &mut self.scratch_memory.lwe_vector,
2320            &mut self.scratch_memory.decomposition_matrix,
2321        );
2322    }
2323
2324    fn or_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2325        self._add_and_shift_lwe_cts(c0, c1);
2326
2327        // PBS
2328        pbs(
2329            &self.pbs_info,
2330            &self.or_test_vec,
2331            c0,
2332            server_key,
2333            &mut self.scratch_memory.lwe_vector,
2334            &mut self.scratch_memory.decomposition_matrix,
2335        );
2336    }
2337
2338    fn nor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2339        self._add_and_shift_lwe_cts(c0, c1);
2340
2341        // PBS
2342        pbs(
2343            &self.pbs_info,
2344            &self.nor_test_vec,
2345            c0,
2346            server_key,
2347            &mut self.scratch_memory.lwe_vector,
2348            &mut self.scratch_memory.decomposition_matrix,
2349        )
2350    }
2351
2352    fn xor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2353        self._subtract_double_lwe_cts(c0, c1);
2354
2355        // PBS
2356        pbs(
2357            &self.pbs_info,
2358            &self.xor_test_vec,
2359            c0,
2360            server_key,
2361            &mut self.scratch_memory.lwe_vector,
2362            &mut self.scratch_memory.decomposition_matrix,
2363        );
2364    }
2365
2366    fn xnor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2367        self._subtract_double_lwe_cts(c0, c1);
2368
2369        // PBS
2370        pbs(
2371            &self.pbs_info,
2372            &self.xnor_test_vec,
2373            c0,
2374            server_key,
2375            &mut self.scratch_memory.lwe_vector,
2376            &mut self.scratch_memory.decomposition_matrix,
2377        );
2378    }
2379
2380    fn not_inplace(&mut self, c0: &mut M::R) {
2381        let modop = &self.pbs_info.rlwe_modop;
2382        c0.as_mut().iter_mut().for_each(|v| *v = modop.neg(v));
2383    }
2384
2385    fn and(
2386        &mut self,
2387        c0: &Self::Ciphertext,
2388        c1: &Self::Ciphertext,
2389        key: &Self::Key,
2390    ) -> Self::Ciphertext {
2391        let mut out = c0.clone();
2392        self.and_inplace(&mut out, c1, key);
2393        out
2394    }
2395
2396    fn nand(
2397        &mut self,
2398        c0: &Self::Ciphertext,
2399        c1: &Self::Ciphertext,
2400        key: &Self::Key,
2401    ) -> Self::Ciphertext {
2402        let mut out = c0.clone();
2403        self.nand_inplace(&mut out, c1, key);
2404        out
2405    }
2406
2407    fn or(
2408        &mut self,
2409        c0: &Self::Ciphertext,
2410        c1: &Self::Ciphertext,
2411        key: &Self::Key,
2412    ) -> Self::Ciphertext {
2413        let mut out = c0.clone();
2414        self.or_inplace(&mut out, c1, key);
2415        out
2416    }
2417
2418    fn nor(
2419        &mut self,
2420        c0: &Self::Ciphertext,
2421        c1: &Self::Ciphertext,
2422        key: &Self::Key,
2423    ) -> Self::Ciphertext {
2424        let mut out = c0.clone();
2425        self.nor_inplace(&mut out, c1, key);
2426        out
2427    }
2428
2429    fn xnor(
2430        &mut self,
2431        c0: &Self::Ciphertext,
2432        c1: &Self::Ciphertext,
2433        key: &Self::Key,
2434    ) -> Self::Ciphertext {
2435        let mut out = c0.clone();
2436        self.xnor_inplace(&mut out, c1, key);
2437        out
2438    }
2439
2440    fn xor(
2441        &mut self,
2442        c0: &Self::Ciphertext,
2443        c1: &Self::Ciphertext,
2444        key: &Self::Key,
2445    ) -> Self::Ciphertext {
2446        let mut out = c0.clone();
2447        self.xor_inplace(&mut out, c1, key);
2448        out
2449    }
2450
2451    fn not(&mut self, c: &Self::Ciphertext) -> Self::Ciphertext {
2452        let mut out = c.clone();
2453        self.not_inplace(&mut out);
2454        out
2455    }
2456}