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