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