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