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