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
 543/// Assigns user with user_id segement of LWE secret indices for which they
 544/// generate RGSW(X^{s[i]}) as the leader (i.e. for RLWExRGSW). If returned
 545/// tuple is (start, end), user's segment is [start, end)
 546pub(super) fn interactive_mult_party_user_id_lwe_segment(
 547    user_id: usize,
 548    total_users: usize,
 549    lwe_n: usize,
 550) -> (usize, usize) {
 551    let per_user = (lwe_n as f64 / total_users as f64)
 552        .ceil()
 553        .to_usize()
 554        .unwrap();
 555    (
 556        per_user * user_id,
 557        std::cmp::min(per_user * (user_id + 1), lwe_n),
 558    )
 559}
 560
 561impl<M: Matrix, NttOp, RlweModOp, LweModOp, SKey> BoolEvaluator<M, NttOp, RlweModOp, LweModOp, SKey>
 562where
 563    M: MatrixEntity + MatrixMut,
 564    M::MatElement: PrimInt
 565        + Debug
 566        + Display
 567        + NumInfo
 568        + FromPrimitive
 569        + WrappingSub
 570        + WrappingAdd
 571        + SampleUniform
 572        + From<bool>,
 573    NttOp: Ntt<Element = M::MatElement>,
 574    RlweModOp: ArithmeticOps<Element = M::MatElement>
 575        + VectorOps<Element = M::MatElement>
 576        + GetModulus<Element = M::MatElement, M = CiphertextModulus<M::MatElement>>
 577        + ShoupMatrixFMA<M::R>,
 578    LweModOp: ArithmeticOps<Element = M::MatElement>
 579        + VectorOps<Element = M::MatElement>
 580        + GetModulus<Element = M::MatElement, M = CiphertextModulus<M::MatElement>>,
 581    M::R: TryConvertFrom1<[i32], CiphertextModulus<M::MatElement>> + RowEntity + Debug,
 582    <M as Matrix>::R: RowMut,
 583{
 584    pub(super) fn new(parameters: BoolParameters<M::MatElement>) -> Self
 585    where
 586        RlweModOp: ModInit<M = CiphertextModulus<M::MatElement>>,
 587        LweModOp: ModInit<M = CiphertextModulus<M::MatElement>>,
 588        NttOp: NttInit<CiphertextModulus<M::MatElement>>,
 589    {
 590        //TODO(Jay): Run sanity checks for modulus values in parameters
 591
 592        // generates dlog map s.t. (+/-)g^{k} % q = a, for all a \in Z*_{q} and k \in
 593        // [0, q/4). We store the dlog `k` at index `a`. This makes it easier to
 594        // simply look up `k` at runtime as vec[a]. If a = g^{k} then dlog is
 595        // stored as k. If a = -g^{k} then dlog is stored as k = q/4. This is done to
 596        // differentiate sign.
 597        let g = parameters.g();
 598        let q = *parameters.br_q();
 599        let mut g_k_dlog_map = vec![0usize; q];
 600        for i in 0..q / 4 {
 601            let v = mod_exponent(g as u64, i as u64, q as u64) as usize;
 602            // g^i
 603            g_k_dlog_map[v] = i;
 604            // -(g^i)
 605            g_k_dlog_map[q - v] = i + (q / 4);
 606        }
 607
 608        let embedding_factor = (2 * parameters.rlwe_n().0) / q;
 609
 610        let rlwe_nttop = NttOp::new(parameters.rlwe_q(), parameters.rlwe_n().0);
 611        let rlwe_modop = RlweModOp::new(*parameters.rlwe_q());
 612        let lwe_modop = LweModOp::new(*parameters.lwe_q());
 613
 614        let q = *parameters.br_q();
 615        let qby2 = q >> 1;
 616        let qby8 = q >> 3;
 617        // Q/8 (Q: rlwe_q)
 618        let true_m_el = parameters.rlwe_q().true_el();
 619        // -Q/8
 620        let false_m_el = parameters.rlwe_q().false_el();
 621        let (auto_map_index, auto_map_sign) = generate_auto_map(qby2, -(g as isize));
 622
 623        let init_test_vec = |partition_el: usize,
 624                             before_partition_el: M::MatElement,
 625                             after_partition_el: M::MatElement| {
 626            let mut test_vec = M::R::zeros(qby2);
 627            for i in 0..qby2 {
 628                if i < partition_el {
 629                    test_vec.as_mut()[i] = before_partition_el;
 630                } else {
 631                    test_vec.as_mut()[i] = after_partition_el;
 632                }
 633            }
 634
 635            // v(X) -> v(X^{-g})
 636            let mut test_vec_autog = M::R::zeros(qby2);
 637            izip!(
 638                test_vec.as_ref().iter(),
 639                auto_map_index.iter(),
 640                auto_map_sign.iter()
 641            )
 642            .for_each(|(v, to_index, to_sign)| {
 643                if !to_sign {
 644                    // negate
 645                    test_vec_autog.as_mut()[*to_index] = rlwe_modop.neg(v);
 646                } else {
 647                    test_vec_autog.as_mut()[*to_index] = *v;
 648                }
 649            });
 650
 651            return test_vec_autog;
 652        };
 653
 654        let nand_test_vec = init_test_vec(3 * qby8, true_m_el, false_m_el);
 655        let and_test_vec = init_test_vec(3 * qby8, false_m_el, true_m_el);
 656        let or_test_vec = init_test_vec(qby8, false_m_el, true_m_el);
 657        let nor_test_vec = init_test_vec(qby8, true_m_el, false_m_el);
 658        let xor_test_vec = init_test_vec(qby8, false_m_el, true_m_el);
 659        let xnor_test_vec = init_test_vec(qby8, true_m_el, false_m_el);
 660
 661        // auto map indices and sign
 662        // Auto maps are stored as [-g, g^{1}, g^{2}, ..., g^{w}]
 663        let mut rlwe_auto_maps = vec![];
 664        let ring_size = parameters.rlwe_n().0;
 665        let g = parameters.g();
 666        let br_q = parameters.br_q();
 667        let auto_element_dlogs = parameters.auto_element_dlogs();
 668        assert!(auto_element_dlogs[0] == 0);
 669        for i in auto_element_dlogs.into_iter() {
 670            let el = if i == 0 {
 671                -(g as isize)
 672            } else {
 673                (g.pow(i as u32) % br_q) as isize
 674            };
 675            rlwe_auto_maps.push(generate_auto_map(ring_size, el))
 676        }
 677
 678        let rlwe_qby4 = parameters.rlwe_q().qby4();
 679
 680        let scratch_memory = ScratchMemory::new(&parameters);
 681
 682        let ni_ui_to_s_ks_decomposer = if parameters.variant()
 683            == &ParameterVariant::NonInteractiveMultiParty
 684        {
 685            Some(parameters
 686                .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>())
 687        } else {
 688            None
 689        };
 690
 691        let pbs_info = BoolPbsInfo {
 692            auto_decomposer: parameters.auto_decomposer(),
 693            lwe_decomposer: parameters.lwe_decomposer(),
 694            rlwe_rgsw_decomposer: parameters.rlwe_rgsw_decomposer(),
 695            g_k_dlog_map,
 696            embedding_factor,
 697            lwe_modop,
 698            rlwe_modop,
 699            rlwe_nttop,
 700            rlwe_qby4,
 701            rlwe_auto_maps,
 702            parameters: parameters,
 703        };
 704
 705        BoolEvaluator {
 706            pbs_info,
 707            scratch_memory,
 708            nand_test_vec,
 709            and_test_vec,
 710            or_test_vec,
 711            nor_test_vec,
 712            xnor_test_vec,
 713            xor_test_vec,
 714            ni_ui_to_s_ks_decomposer,
 715            _phantom: PhantomData,
 716        }
 717    }
 718
 719    pub(crate) fn client_key(
 720        &self,
 721    ) -> ClientKey<<DefaultSecureRng as NewWithSeed>::Seed, M::MatElement> {
 722        ClientKey::new(self.parameters().clone())
 723    }
 724
 725    pub(super) fn single_party_server_key<K: SinglePartyClientKey<Element = i32>>(
 726        &self,
 727        client_key: &K,
 728    ) -> SeededSinglePartyServerKey<M, BoolParameters<M::MatElement>, [u8; 32]> {
 729        assert_eq!(self.parameters().variant(), &ParameterVariant::SingleParty);
 730
 731        DefaultSecureRng::with_local_mut(|rng| {
 732            let mut main_seed = [0u8; 32];
 733            rng.fill_bytes(&mut main_seed);
 734
 735            let mut main_prng = DefaultSecureRng::new_seeded(main_seed);
 736
 737            let rlwe_n = self.pbs_info.parameters.rlwe_n().0;
 738            let sk_rlwe = client_key.sk_rlwe();
 739            let sk_lwe = client_key.sk_lwe();
 740
 741            // generate auto keys
 742            let mut auto_keys = HashMap::new();
 743            let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
 744            let g = self.pbs_info.parameters.g();
 745            let br_q = self.pbs_info.parameters.br_q();
 746            let auto_els = self.pbs_info.parameters.auto_element_dlogs();
 747            for i in auto_els.into_iter() {
 748                let g_pow = if i == 0 {
 749                    -(g as isize)
 750                } else {
 751                    (g.pow(i as u32) % br_q) as isize
 752                };
 753                let mut gk = M::zeros(self.pbs_info.auto_decomposer.decomposition_count(), rlwe_n);
 754                galois_key_gen(
 755                    &mut gk,
 756                    &sk_rlwe,
 757                    g_pow,
 758                    &auto_gadget,
 759                    &self.pbs_info.rlwe_modop,
 760                    &self.pbs_info.rlwe_nttop,
 761                    &mut main_prng,
 762                    rng,
 763                );
 764                auto_keys.insert(i, gk);
 765            }
 766
 767            // generate rgsw ciphertexts RGSW(si) where si is i^th LWE secret element
 768            let ring_size = self.pbs_info.parameters.rlwe_n().0;
 769            let rlwe_q = self.pbs_info.parameters.rlwe_q();
 770            let (rlrg_d_a, rlrg_d_b) = (
 771                self.pbs_info.rlwe_rgsw_decomposer.0.decomposition_count(),
 772                self.pbs_info.rlwe_rgsw_decomposer.1.decomposition_count(),
 773            );
 774            let rlrg_gadget_a = self.pbs_info.rlwe_rgsw_decomposer.0.gadget_vector();
 775            let rlrg_gadget_b = self.pbs_info.rlwe_rgsw_decomposer.1.gadget_vector();
 776            let rgsw_cts = sk_lwe
 777                .iter()
 778                .map(|si| {
 779                    // X^{si}; assume |emebedding_factor * si| < N
 780                    let mut m = M::R::zeros(ring_size);
 781                    let si = (self.pbs_info.embedding_factor as i32) * si;
 782                    // dbg!(si);
 783                    if si < 0 {
 784                        // X^{-i} = X^{2N - i} = -X^{N-i}
 785                        m.as_mut()[ring_size - (si.abs() as usize)] = rlwe_q.neg_one();
 786                    } else {
 787                        // X^{i}
 788                        m.as_mut()[si.abs() as usize] = M::MatElement::one();
 789                    }
 790
 791                    let mut rgsw_si = M::zeros(rlrg_d_a * 2 + rlrg_d_b, ring_size);
 792                    secret_key_encrypt_rgsw(
 793                        &mut rgsw_si,
 794                        m.as_ref(),
 795                        &rlrg_gadget_a,
 796                        &rlrg_gadget_b,
 797                        &sk_rlwe,
 798                        &self.pbs_info.rlwe_modop,
 799                        &self.pbs_info.rlwe_nttop,
 800                        &mut main_prng,
 801                        rng,
 802                    );
 803
 804                    rgsw_si
 805                })
 806                .collect_vec();
 807
 808            // LWE KSK from RLWE secret s -> LWE secret z
 809            let d_lwe_gadget = self.pbs_info.lwe_decomposer.gadget_vector();
 810            let mut lwe_ksk =
 811                M::R::zeros(self.pbs_info.lwe_decomposer.decomposition_count() * ring_size);
 812            lwe_ksk_keygen(
 813                &sk_rlwe,
 814                &sk_lwe,
 815                &mut lwe_ksk,
 816                &d_lwe_gadget,
 817                &self.pbs_info.lwe_modop,
 818                &mut main_prng,
 819                rng,
 820            );
 821
 822            SeededSinglePartyServerKey::from_raw(
 823                auto_keys,
 824                rgsw_cts,
 825                lwe_ksk,
 826                self.pbs_info.parameters.clone(),
 827                main_seed,
 828            )
 829        })
 830    }
 831
 832    pub(super) fn multi_party_server_key_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
 833        &self,
 834        user_id: usize,
 835        total_users: usize,
 836        cr_seed: &MultiPartyCrs<[u8; 32]>,
 837        collective_pk: &M,
 838        client_key: &K,
 839    ) -> CommonReferenceSeededMultiPartyServerKeyShare<
 840        M,
 841        BoolParameters<M::MatElement>,
 842        MultiPartyCrs<[u8; 32]>,
 843    > {
 844        assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
 845        assert!(user_id < total_users);
 846
 847        let sk_rlwe = client_key.sk_rlwe();
 848        let sk_lwe = client_key.sk_lwe();
 849
 850        let g = self.pbs_info.parameters.g();
 851        let ring_size = self.pbs_info.parameters.rlwe_n().0;
 852        let rlwe_q = self.pbs_info.parameters.rlwe_q();
 853        let lwe_q = self.pbs_info.parameters.lwe_q();
 854
 855        let rlweq_modop = &self.pbs_info.rlwe_modop;
 856        let rlweq_nttop = &self.pbs_info.rlwe_nttop;
 857
 858        // sanity check
 859        assert!(sk_rlwe.len() == ring_size);
 860        assert!(sk_lwe.len() == self.pbs_info.parameters.lwe_n().0);
 861
 862        // auto keys
 863        let auto_keys = self._common_rountine_multi_party_auto_keys_share_gen(
 864            cr_seed.auto_keys_cts_seed::<DefaultSecureRng>(),
 865            &sk_rlwe,
 866        );
 867
 868        // rgsw ciphertexts of lwe secret elements
 869        let (self_leader_rgsws, not_self_leader_rgsws) = DefaultSecureRng::with_local_mut(|rng| {
 870            let mut self_leader_rgsw = vec![];
 871            let mut not_self_leader_rgsws = vec![];
 872
 873            let (segment_start, segment_end) = interactive_mult_party_user_id_lwe_segment(
 874                user_id,
 875                total_users,
 876                self.pbs_info().lwe_n(),
 877            );
 878
 879            // self LWE secret indices
 880            {
 881                // LWE secret indices for which user is the leader they need to send RGSW(m) for
 882                // RLWE x RGSW multiplication
 883                let rlrg_decomposer = self.pbs_info().rlwe_rgsw_decomposer();
 884                let (rlrg_d_a, rlrg_d_b) = (
 885                    rlrg_decomposer.a().decomposition_count(),
 886                    rlrg_decomposer.b().decomposition_count(),
 887                );
 888                let (gadget_a, gadget_b) = (
 889                    rlrg_decomposer.a().gadget_vector(),
 890                    rlrg_decomposer.b().gadget_vector(),
 891                );
 892                for s_index in segment_start..segment_end {
 893                    let mut out_rgsw = M::zeros(rlrg_d_a * 2 + rlrg_d_b * 2, ring_size);
 894                    public_key_encrypt_rgsw(
 895                        &mut out_rgsw,
 896                        &encode_x_pow_si_with_emebedding_factor::<
 897                            M::R,
 898                            CiphertextModulus<M::MatElement>,
 899                        >(
 900                            sk_lwe[s_index],
 901                            self.pbs_info().embedding_factor(),
 902                            ring_size,
 903                            self.pbs_info().rlwe_q(),
 904                        )
 905                        .as_ref(),
 906                        collective_pk,
 907                        &gadget_a,
 908                        &gadget_b,
 909                        rlweq_modop,
 910                        rlweq_nttop,
 911                        rng,
 912                    );
 913                    self_leader_rgsw.push(out_rgsw);
 914                }
 915            }
 916
 917            // not self LWE secret indices
 918            {
 919                // LWE secret indices for which user isn't the leader, they need to send RGSW(m)
 920                // for RGSW x RGSW multiplcation
 921                let rgsw_rgsw_decomposer = self
 922                    .pbs_info
 923                    .parameters
 924                    .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
 925                let (rgrg_d_a, rgrg_d_b) = (
 926                    rgsw_rgsw_decomposer.a().decomposition_count(),
 927                    rgsw_rgsw_decomposer.b().decomposition_count(),
 928                );
 929                let (rgrg_gadget_a, rgrg_gadget_b) = (
 930                    rgsw_rgsw_decomposer.a().gadget_vector(),
 931                    rgsw_rgsw_decomposer.b().gadget_vector(),
 932                );
 933
 934                for s_index in (0..segment_start).chain(segment_end..self.parameters().lwe_n().0) {
 935                    let mut out_rgsw = M::zeros(rgrg_d_a * 2 + rgrg_d_b * 2, ring_size);
 936                    public_key_encrypt_rgsw(
 937                        &mut out_rgsw,
 938                        &encode_x_pow_si_with_emebedding_factor::<
 939                            M::R,
 940                            CiphertextModulus<M::MatElement>,
 941                        >(
 942                            sk_lwe[s_index],
 943                            self.pbs_info().embedding_factor(),
 944                            ring_size,
 945                            self.pbs_info().rlwe_q(),
 946                        )
 947                        .as_ref(),
 948                        collective_pk,
 949                        &rgrg_gadget_a,
 950                        &rgrg_gadget_b,
 951                        rlweq_modop,
 952                        rlweq_nttop,
 953                        rng,
 954                    );
 955
 956                    not_self_leader_rgsws.push(out_rgsw);
 957                }
 958            }
 959
 960            (self_leader_rgsw, not_self_leader_rgsws)
 961        });
 962
 963        // LWE Ksk
 964        let lwe_ksk = self._common_rountine_multi_party_lwe_ksk_share_gen(
 965            cr_seed.lwe_ksk_cts_seed_seed::<DefaultSecureRng>(),
 966            &sk_rlwe,
 967            &sk_lwe,
 968        );
 969
 970        CommonReferenceSeededMultiPartyServerKeyShare::new(
 971            self_leader_rgsws,
 972            not_self_leader_rgsws,
 973            auto_keys,
 974            lwe_ksk,
 975            cr_seed.clone(),
 976            self.pbs_info.parameters.clone(),
 977            user_id,
 978        )
 979    }
 980
 981    pub(super) fn aggregate_multi_party_server_key_shares<S>(
 982        &self,
 983        shares: &[CommonReferenceSeededMultiPartyServerKeyShare<
 984            M,
 985            BoolParameters<M::MatElement>,
 986            MultiPartyCrs<S>,
 987        >],
 988    ) -> SeededMultiPartyServerKey<M, MultiPartyCrs<S>, BoolParameters<M::MatElement>>
 989    where
 990        S: PartialEq + Clone,
 991        M: Clone,
 992    {
 993        assert_eq!(self.parameters().variant(), &ParameterVariant::MultiParty);
 994        assert!(shares.len() > 0);
 995
 996        let total_users = shares.len();
 997
 998        let parameters = shares[0].parameters().clone();
 999        let cr_seed = shares[0].cr_seed();
1000
1001        let rlwe_n = parameters.rlwe_n().0;
1002        let g = parameters.g() as isize;
1003        let rlwe_q = parameters.rlwe_q();
1004        let lwe_q = parameters.lwe_q();
1005
1006        // sanity checks
1007        shares.iter().skip(1).for_each(|s| {
1008            assert!(s.parameters() == &parameters);
1009            assert!(s.cr_seed() == cr_seed);
1010        });
1011
1012        let rlweq_modop = &self.pbs_info.rlwe_modop;
1013        let rlweq_nttop = &self.pbs_info.rlwe_nttop;
1014
1015        // auto keys
1016        let mut auto_keys = HashMap::new();
1017        let auto_elements_dlog = parameters.auto_element_dlogs();
1018        for i in auto_elements_dlog.into_iter() {
1019            let mut key = M::zeros(parameters.auto_decomposition_count().0, rlwe_n);
1020
1021            shares.iter().for_each(|s| {
1022                let auto_key_share_i = s.auto_keys().get(&i).expect("Auto key {i} missing");
1023                assert!(
1024                    auto_key_share_i.dimension()
1025                        == (parameters.auto_decomposition_count().0, rlwe_n)
1026                );
1027                izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
1028                    |(partb_out, partb_share)| {
1029                        rlweq_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
1030                    },
1031                );
1032            });
1033
1034            auto_keys.insert(i, key);
1035        }
1036
1037        // rgsw ciphertext (most expensive part!)
1038        let rgsw_cts = {
1039            let rgsw_by_rgsw_decomposer =
1040                parameters.rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1041            let rlwe_x_rgsw_decomposer = self.pbs_info().rlwe_rgsw_decomposer();
1042            let rgsw_x_rgsw_dimension = (
1043                rgsw_by_rgsw_decomposer.a().decomposition_count() * 2
1044                    + rgsw_by_rgsw_decomposer.b().decomposition_count() * 2,
1045                rlwe_n,
1046            );
1047            let rlwe_x_rgsw_dimension = (
1048                rlwe_x_rgsw_decomposer.a().decomposition_count() * 2
1049                    + rlwe_x_rgsw_decomposer.b().decomposition_count() * 2,
1050                rlwe_n,
1051            );
1052            let mut rgsw_x_rgsw_scratch_mat = M::zeros(
1053                std::cmp::max(
1054                    rgsw_by_rgsw_decomposer.a().decomposition_count(),
1055                    rgsw_by_rgsw_decomposer.b().decomposition_count(),
1056                ) + rlwe_x_rgsw_dimension.0,
1057                rlwe_n,
1058            );
1059
1060            let shares_in_correct_order = (0..total_users)
1061                .map(|i| shares.iter().find(|s| s.user_id() == i).unwrap())
1062                .collect_vec();
1063
1064            let lwe_n = self.parameters().lwe_n().0;
1065            let (users_segments, users_segments_sizes): (Vec<(usize, usize)>, Vec<usize>) = (0
1066                ..total_users)
1067                .map(|(user_id)| {
1068                    let (start_index, end_index) =
1069                        interactive_mult_party_user_id_lwe_segment(user_id, total_users, lwe_n);
1070                    ((start_index, end_index), end_index - start_index)
1071                })
1072                .unzip();
1073
1074            let mut rgsw_cts = Vec::with_capacity(lwe_n);
1075            users_segments
1076                .iter()
1077                .enumerate()
1078                .for_each(|(user_id, user_segment)| {
1079                    let share = shares_in_correct_order[user_id];
1080                    for secret_index in user_segment.0..user_segment.1 {
1081                        let mut rgsw_i =
1082                            share.self_leader_rgsws()[secret_index - user_segment.0].clone();
1083                        // assert already exists in RGSW x RGSW rountine
1084                        assert!(rgsw_i.dimension() == rlwe_x_rgsw_dimension);
1085
1086                        // multiply leader's RGSW ct at `secret_index` with RGSW cts of other users
1087                        // for lwe index `secret_index`
1088                        (0..total_users)
1089                            .filter(|i| i != &user_id)
1090                            .for_each(|other_user_id| {
1091                                let mut offset = 0;
1092                                if other_user_id < user_id {
1093                                    offset = users_segments_sizes[other_user_id];
1094                                }
1095
1096                                let mut other_rgsw_i = shares_in_correct_order[other_user_id]
1097                                    .not_self_leader_rgsws()
1098                                    [secret_index.checked_sub(offset).unwrap()]
1099                                .clone();
1100                                // assert already exists in RGSW x RGSW rountine
1101                                assert!(other_rgsw_i.dimension() == rgsw_x_rgsw_dimension);
1102
1103                                // send to evaluation domain for RGSwxRGSW mul
1104                                other_rgsw_i
1105                                    .iter_rows_mut()
1106                                    .for_each(|r| rlweq_nttop.forward(r.as_mut()));
1107
1108                                rgsw_by_rgsw_inplace(
1109                                    &mut rgsw_i,
1110                                    rlwe_x_rgsw_decomposer.a().decomposition_count(),
1111                                    rlwe_x_rgsw_decomposer.b().decomposition_count(),
1112                                    &other_rgsw_i,
1113                                    &rgsw_by_rgsw_decomposer,
1114                                    &mut rgsw_x_rgsw_scratch_mat,
1115                                    rlweq_nttop,
1116                                    rlweq_modop,
1117                                )
1118                            });
1119
1120                        rgsw_cts.push(rgsw_i);
1121                    }
1122                });
1123
1124            rgsw_cts
1125        };
1126
1127        // LWE ksks
1128        let mut lwe_ksk = M::R::zeros(rlwe_n * parameters.lwe_decomposition_count().0);
1129        let lweq_modop = &self.pbs_info.lwe_modop;
1130        shares.iter().for_each(|si| {
1131            assert!(si.lwe_ksk().as_ref().len() == rlwe_n * parameters.lwe_decomposition_count().0);
1132            lweq_modop.elwise_add_mut(lwe_ksk.as_mut(), si.lwe_ksk().as_ref())
1133        });
1134
1135        SeededMultiPartyServerKey::new(rgsw_cts, auto_keys, lwe_ksk, cr_seed.clone(), parameters)
1136    }
1137
1138    pub(super) fn aggregate_non_interactive_multi_party_key_share(
1139        &self,
1140        cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
1141        total_users: usize,
1142        key_shares: &[CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
1143            M,
1144            NonInteractiveMultiPartyCrs<[u8; 32]>,
1145        >],
1146    ) -> SeededNonInteractiveMultiPartyServerKey<
1147        M,
1148        NonInteractiveMultiPartyCrs<[u8; 32]>,
1149        BoolParameters<M::MatElement>,
1150    >
1151    where
1152        M: Clone + Debug,
1153    {
1154        assert_eq!(
1155            self.parameters().variant(),
1156            &ParameterVariant::NonInteractiveMultiParty
1157        );
1158
1159        // sanity checks
1160        let key_order = {
1161            let existing_key_order = key_shares.iter().map(|s| s.user_index()).collect_vec();
1162
1163            // record the order s.t. key_order[i] stores the position of i^th
1164            // users key share in existing order
1165            let mut key_order = Vec::with_capacity(existing_key_order.len());
1166            (0..total_users).for_each(|i| {
1167                // find i
1168                let index = existing_key_order
1169                    .iter()
1170                    .position(|x| x == &i)
1171                    .expect(&format!("Missing user {i}'s key!"));
1172                key_order.push(index);
1173            });
1174
1175            key_order
1176        };
1177
1178        let rlwe_modop = &self.pbs_info().rlwe_modop;
1179        let nttop = &self.pbs_info().rlwe_nttop;
1180        let ring_size = self.parameters().rlwe_n().0;
1181        let rlwe_q = self.parameters().rlwe_q();
1182        let lwe_modop = self.pbs_info().modop_lweq();
1183
1184        // genrate key switching key from u_i to s
1185        let ui_to_s_ksk_decomposition_count = self
1186            .parameters()
1187            .non_interactive_ui_to_s_key_switch_decomposition_count();
1188        let mut ui_to_s_ksks = key_shares
1189            .iter()
1190            .map(|share| {
1191                let mut useri_ui_to_s_ksk = share.ui_to_s_ksk().clone();
1192                assert!(
1193                    useri_ui_to_s_ksk.dimension() == (ui_to_s_ksk_decomposition_count.0, ring_size)
1194                );
1195                key_shares
1196                    .iter()
1197                    .filter(|x| x.user_index() != share.user_index())
1198                    .for_each(|(other_share)| {
1199                        let op2 = other_share.ui_to_s_ksk_zero_encs_for_user_i(share.user_index());
1200                        assert!(op2.dimension() == (ui_to_s_ksk_decomposition_count.0, ring_size));
1201                        izip!(useri_ui_to_s_ksk.iter_rows_mut(), op2.iter_rows()).for_each(
1202                            |(add_to, add_from)| {
1203                                rlwe_modop.elwise_add_mut(add_to.as_mut(), add_from.as_ref())
1204                            },
1205                        );
1206                    });
1207                useri_ui_to_s_ksk
1208            })
1209            .collect_vec();
1210
1211        let rgsw_cts = {
1212            let mut rgsw_prng =
1213                DefaultSecureRng::new_seeded(cr_seed.ni_rgsw_cts_main_seed::<DefaultSecureRng>());
1214
1215            let rgsw_by_rgsw_decomposer = self
1216                .parameters()
1217                .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1218
1219            // Generate RGSW Cts
1220            let rgsw_cts_all_users_eval = {
1221                // temporarily put ui_to_s in evaluation domain and sample a_i's for u_i to s
1222                // ksk for upcomong key switches
1223                ui_to_s_ksks.iter_mut().for_each(|ksk_i| {
1224                    ksk_i
1225                        .iter_rows_mut()
1226                        .for_each(|r| nttop.forward(r.as_mut()))
1227                });
1228                let ui_to_s_ksks_part_a_eval = key_shares
1229                    .iter()
1230                    .map(|share| {
1231                        let mut ksk_prng = DefaultSecureRng::new_seeded(
1232                            cr_seed
1233                                .ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(share.user_index()),
1234                        );
1235                        let mut ais = M::zeros(ui_to_s_ksk_decomposition_count.0, ring_size);
1236
1237                        ais.iter_rows_mut().for_each(|r_ai| {
1238                            RandomFillUniformInModulus::random_fill(
1239                                &mut ksk_prng,
1240                                rlwe_q,
1241                                r_ai.as_mut(),
1242                            );
1243
1244                            nttop.forward(r_ai.as_mut())
1245                        });
1246                        ais
1247                    })
1248                    .collect_vec();
1249
1250                let max_rgrg_deocmposer = if rgsw_by_rgsw_decomposer.a().decomposition_count()
1251                    > rgsw_by_rgsw_decomposer.b().decomposition_count()
1252                {
1253                    rgsw_by_rgsw_decomposer.a()
1254                } else {
1255                    rgsw_by_rgsw_decomposer.b()
1256                };
1257
1258                let ui_to_s_ksk_decomposer = self
1259                .parameters()
1260                .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>(
1261                );
1262
1263                // Generate a_i*s + E = \sum_{j \in P} a_i*s_j + e for all rlwes in each
1264                // non-interactive rgsws. Then decompose and put decompositions in evaluation
1265                // for u_i -> s key switch.
1266                let decomp_ni_rgsws_part_1_acc = {
1267                    let mut tmp_space = M::R::zeros(ring_size);
1268
1269                    (0..self.parameters().lwe_n().0)
1270                        .into_iter()
1271                        .map(|lwe_index| {
1272                            (0..max_rgrg_deocmposer.decomposition_count())
1273                                .into_iter()
1274                                .map(|d_index| {
1275                                    let mut sum = M::zeros(
1276                                        ui_to_s_ksk_decomposer.decomposition_count(),
1277                                        ring_size,
1278                                    );
1279
1280                                    // set temp_space to all zeros
1281                                    tmp_space.as_mut().fill(M::MatElement::zero());
1282
1283                                    // a_i*s + E
1284                                    key_shares.iter().for_each(|s| {
1285                                        rlwe_modop.elwise_add_mut(
1286                                            tmp_space.as_mut(),
1287                                            s.ni_rgsw_cts().1[lwe_index].get_row_slice(d_index),
1288                                        );
1289                                    });
1290
1291                                    tmp_space.as_ref().iter().enumerate().for_each(|(ri, el)| {
1292                                        ui_to_s_ksk_decomposer
1293                                            .decompose_iter(el)
1294                                            .enumerate()
1295                                            .for_each(|(row_j, d_el)| {
1296                                                (sum.as_mut()[row_j]).as_mut()[ri] = d_el;
1297                                            });
1298                                    });
1299
1300                                    sum.iter_rows_mut().for_each(|r| nttop.forward(r.as_mut()));
1301
1302                                    sum
1303                                })
1304                                .collect_vec()
1305                        })
1306                        .collect_vec()
1307                };
1308
1309                // Sample a_i's are used to generate non-interactive rgsw cts for all lwe
1310                // indices. Since a_i are just needed for key switches , decompose them
1311                // and put them in evaluation domain
1312                // Decomposition count used for RGSW ct in non-interactive key share gen equals
1313                // max of A and B decomposition required in RGSWxRGSW. This is because same
1314                // polynomials are used to generate RLWE'(m) and RLWE'(-sm)
1315                let decomp_ni_rgsw_neg_ais = {
1316                    let mut tmp_space = M::R::zeros(ring_size);
1317                    (0..self.parameters().lwe_n().0)
1318                        .into_iter()
1319                        .map(|_| {
1320                            // FIXME(Jay): well well, ais are only required for key switching to
1321                            // generate RLWE'(m) and RLWE'(m) itself
1322                            // requires RLWE(\beta^i m) for i \in RGSWxRGSW
1323                            // part B decomposition count. However, we still need to puncture prng
1324                            // for ais corresponding to ignored limbs.
1325                            // Probably it will be nice idea to
1326                            // avoid decomposition after punturing for a_i's corresponding to
1327                            // ignored limbs. Moreover, note that, for
1328                            // RGSWxRGSW often times decompostion count for part A
1329                            // > part B. Hence, it's very likely that we are doing
1330                            // unecesary decompositions for ignored limbs all the time.
1331                            (0..max_rgrg_deocmposer.decomposition_count())
1332                                .map(|_| {
1333                                    RandomFillUniformInModulus::random_fill(
1334                                        &mut rgsw_prng,
1335                                        rlwe_q,
1336                                        tmp_space.as_mut(),
1337                                    );
1338
1339                                    // negate
1340                                    rlwe_modop.elwise_neg_mut(tmp_space.as_mut());
1341
1342                                    // decomposer a_i for ui -> s key switch
1343                                    let mut decomp_neg_ai = M::zeros(
1344                                        ui_to_s_ksk_decomposer.decomposition_count(),
1345                                        ring_size,
1346                                    );
1347                                    tmp_space.as_ref().iter().enumerate().for_each(
1348                                        |(index, el)| {
1349                                            ui_to_s_ksk_decomposer
1350                                                .decompose_iter(el)
1351                                                .enumerate()
1352                                                .for_each(|(row_j, d_el)| {
1353                                                    (decomp_neg_ai.as_mut()[row_j]).as_mut()
1354                                                        [index] = d_el;
1355                                                });
1356                                        },
1357                                    );
1358
1359                                    // put in evaluation domain
1360                                    decomp_neg_ai
1361                                        .iter_rows_mut()
1362                                        .for_each(|r| nttop.forward(r.as_mut()));
1363
1364                                    decomp_neg_ai
1365                                })
1366                                .collect_vec()
1367                        })
1368                        .collect_vec()
1369                };
1370
1371                // genrate RGSW cts
1372                let rgsw_cts_all_users_eval = izip!(
1373                    key_shares.iter(),
1374                    ui_to_s_ksks.iter(),
1375                    ui_to_s_ksks_part_a_eval.iter()
1376                )
1377                .map(
1378                    |(share, user_uitos_ksk_partb_eval, user_uitos_ksk_parta_eval)| {
1379                        // RGSW_s(X^{s[i]})
1380                        let rgsw_cts_user_i_eval = izip!(
1381                            share.ni_rgsw_cts().0.iter(),
1382                            decomp_ni_rgsw_neg_ais.iter(),
1383                            decomp_ni_rgsws_part_1_acc.iter()
1384                        )
1385                        .map(
1386                            |(
1387                                m_encs_under_ui,
1388                                decomposed_rgsw_i_neg_ais,
1389                                decomposed_acc_rgsw_part1,
1390                            )| {
1391                                let d_a = rgsw_by_rgsw_decomposer.a().decomposition_count();
1392                                let d_b = rgsw_by_rgsw_decomposer.b().decomposition_count();
1393                                let max_d = std::cmp::max(d_a, d_b);
1394
1395                                assert!(decomposed_rgsw_i_neg_ais.len() == max_d);
1396
1397                                // To be RGSW(X^{s[i]}) = [RLWE'(-sm), RLWE'(m)]
1398                                let mut rgsw_ct_eval = M::zeros(d_a * 2 + d_b * 2, ring_size);
1399                                let (rlwe_dash_nsm, rlwe_dash_m) =
1400                                    rgsw_ct_eval.split_at_row_mut(d_a * 2);
1401
1402                                let mut scratch_row = M::R::zeros(ring_size);
1403
1404                                let mut m_encs_under_ui_eval = m_encs_under_ui.clone();
1405                                m_encs_under_ui_eval
1406                                    .iter_rows_mut()
1407                                    .for_each(|r| nttop.forward(r.as_mut()));
1408
1409                                // RLWE(-sm)
1410                                {
1411                                    // Recall that we have RLWE(a_i * s + e). We key
1412                                    // switch RLWE(a_i * s + e) using ksk(u_i -> s) to
1413                                    // get RLWE(a_i*s*u_i + e*u_i).
1414                                    // Given (u_i * a_i + e + \beta m), we obtain
1415                                    // RLWE(-sm) = RLWE(a_i*s*u_i + e*u_i) + (0, (u_i *
1416                                    // a_i + e + \beta m))
1417                                    //
1418                                    // Again RLWE'(-sm) only cares for RLWE(\beta -sm)
1419                                    // with scaling factor \beta corresponding to most
1420                                    // signficant d_a limbs. Hence, we skip (d_max -
1421                                    // d_a) least signficant limbs
1422
1423                                    let (rlwe_dash_neg_sm_part_a, rlwe_dash_neg_sm_part_b) =
1424                                        rlwe_dash_nsm.split_at_mut(d_a);
1425
1426                                    izip!(
1427                                        rlwe_dash_neg_sm_part_a.iter_mut(),
1428                                        rlwe_dash_neg_sm_part_b.iter_mut(),
1429                                        decomposed_acc_rgsw_part1.iter().skip(max_d - d_a),
1430                                        m_encs_under_ui_eval.iter_rows().skip(max_d - d_a)
1431                                    )
1432                                    .for_each(
1433                                        |(rlwe_a, rlwe_b, decomp_ai_s, beta_m_enc_ui)| {
1434                                            // RLWE_s(a_i * s * u_i + u_i * e) = decomp<a_i * s + e>
1435                                            // * ksk(u_i
1436                                            // -> s)
1437                                            izip!(
1438                                                decomp_ai_s.iter_rows(),
1439                                                user_uitos_ksk_partb_eval.iter_rows(),
1440                                                user_uitos_ksk_parta_eval.iter_rows()
1441                                            )
1442                                            .for_each(
1443                                                |(a0, part_b, part_a)| {
1444                                                    // rlwe_b += decomp<a_i * s + e>[i] * ksk
1445                                                    // part_b[i]
1446                                                    rlwe_modop.elwise_mul(
1447                                                        scratch_row.as_mut(),
1448                                                        a0.as_ref(),
1449                                                        part_b.as_ref(),
1450                                                    );
1451                                                    rlwe_modop.elwise_add_mut(
1452                                                        rlwe_b.as_mut(),
1453                                                        scratch_row.as_ref(),
1454                                                    );
1455
1456                                                    // rlwe_a += decomp<a_i * s + e>[i] * ksk
1457                                                    // part_a[i]
1458                                                    rlwe_modop.elwise_mul(
1459                                                        scratch_row.as_mut(),
1460                                                        a0.as_ref(),
1461                                                        part_a.as_ref(),
1462                                                    );
1463                                                    rlwe_modop.elwise_add_mut(
1464                                                        rlwe_a.as_mut(),
1465                                                        scratch_row.as_ref(),
1466                                                    );
1467                                                },
1468                                            );
1469
1470                                            // RLWE_s(-sm) = RLWE_s(a_i * s * u_i + u_i
1471                                            // * e) + (0, a_i * u + e + m)
1472                                            rlwe_modop.elwise_add_mut(
1473                                                rlwe_a.as_mut(),
1474                                                beta_m_enc_ui.as_ref(),
1475                                            );
1476                                        },
1477                                    );
1478                                }
1479
1480                                // RLWE(m)
1481                                {
1482                                    // Routine:
1483                                    // Let RLWE(-a_i * u_i) = (decomp<-a_i> \cdot ksk(u_i -> s)),
1484                                    // then RLWE(m) = RLWE(a'*s + e + m) = (a_i
1485                                    // * u_i + e + m, 0) + RLWE(-a_i * u_i)
1486                                    //
1487                                    // Since RLWE'(m) only cares for RLWE ciphertexts corresponding
1488                                    // to higher d_b limbs, we skip routine 1 for lower max(d_a,
1489                                    // d_b) - d_b limbs
1490                                    let (rlwe_dash_m_part_a, rlwe_dash_m_part_b) =
1491                                        rlwe_dash_m.split_at_mut(d_b);
1492
1493                                    izip!(
1494                                        rlwe_dash_m_part_a.iter_mut(),
1495                                        rlwe_dash_m_part_b.iter_mut(),
1496                                        decomposed_rgsw_i_neg_ais.iter().skip(max_d - d_b),
1497                                        m_encs_under_ui_eval.iter_rows().skip(max_d - d_b)
1498                                    )
1499                                    .for_each(
1500                                        |(rlwe_a, rlwe_b, decomp_neg_ai, beta_m_enc_ui)| {
1501                                            // RLWE_s(-a_i * ui) = decomp<-a_i> \cdot ksk(ui -> s)
1502                                            izip!(
1503                                                decomp_neg_ai.iter_rows(),
1504                                                user_uitos_ksk_partb_eval.iter_rows(),
1505                                                user_uitos_ksk_parta_eval.iter_rows()
1506                                            )
1507                                            .for_each(
1508                                                |(a0, part_b, part_a)| {
1509                                                    // rlwe_b += decomp<a>[i] * ksk part_b[i]
1510                                                    rlwe_modop.elwise_mul(
1511                                                        scratch_row.as_mut(),
1512                                                        a0.as_ref(),
1513                                                        part_b.as_ref(),
1514                                                    );
1515                                                    rlwe_modop.elwise_add_mut(
1516                                                        rlwe_b.as_mut(),
1517                                                        scratch_row.as_ref(),
1518                                                    );
1519
1520                                                    // rlwe_a += decomp<a>[i] * ksk
1521                                                    // part_a[i]
1522                                                    rlwe_modop.elwise_mul(
1523                                                        scratch_row.as_mut(),
1524                                                        a0.as_ref(),
1525                                                        part_a.as_ref(),
1526                                                    );
1527                                                    rlwe_modop.elwise_add_mut(
1528                                                        rlwe_a.as_mut(),
1529                                                        scratch_row.as_ref(),
1530                                                    );
1531                                                },
1532                                            );
1533
1534                                            // RLWE_s(m) = (a_i * ui + e +  \beta m, 0)
1535                                            // +
1536                                            // RLWE_s(-a_i * ui)
1537                                            rlwe_modop.elwise_add_mut(
1538                                                rlwe_b.as_mut(),
1539                                                beta_m_enc_ui.as_ref(),
1540                                            );
1541                                        },
1542                                    );
1543                                }
1544
1545                                rgsw_ct_eval
1546                            },
1547                        )
1548                        .collect_vec();
1549                        rgsw_cts_user_i_eval
1550                    },
1551                )
1552                .collect_vec();
1553
1554                // put u_i -> s ksks back in coefficient domain
1555                ui_to_s_ksks.iter_mut().for_each(|ksk_i| {
1556                    ksk_i
1557                        .iter_rows_mut()
1558                        .for_each(|r| nttop.backward(r.as_mut()))
1559                });
1560
1561                rgsw_cts_all_users_eval
1562            };
1563
1564            // RGSW x RGSW
1565            let lwe_n = self.parameters().lwe_n().0;
1566            let mut scratch_matrix = M::zeros(
1567                std::cmp::max(
1568                    rgsw_by_rgsw_decomposer.a().decomposition_count(),
1569                    rgsw_by_rgsw_decomposer.b().decomposition_count(),
1570                ) + (rgsw_by_rgsw_decomposer.a().decomposition_count() * 2
1571                    + rgsw_by_rgsw_decomposer.b().decomposition_count() * 2),
1572                ring_size,
1573            );
1574            let rgsw_cts_untrimmed = (0..lwe_n).map(|s_index| {
1575                // copy over s_index^th rgsw ct of user 0. Use it to accumulate RGSW products of
1576                // all RGSW ciphertexts at s_index
1577                let mut rgsw_i = rgsw_cts_all_users_eval[0][s_index].clone();
1578                rgsw_i
1579                    .iter_rows_mut()
1580                    .for_each(|r| nttop.backward(r.as_mut()));
1581
1582                rgsw_cts_all_users_eval
1583                    .iter()
1584                    .skip(1)
1585                    .for_each(|user_i_rgsws| {
1586                        rgsw_by_rgsw_inplace(
1587                            &mut rgsw_i,
1588                            rgsw_by_rgsw_decomposer.a().decomposition_count(),
1589                            rgsw_by_rgsw_decomposer.b().decomposition_count(),
1590                            &user_i_rgsws[s_index],
1591                            &rgsw_by_rgsw_decomposer,
1592                            &mut scratch_matrix,
1593                            nttop,
1594                            rlwe_modop,
1595                        );
1596                    });
1597
1598                rgsw_i
1599            });
1600
1601            // After this point we don't require RGSW cts for RGSWxRGSW
1602            // multiplicaiton anymore. So we trim them to suit RLWExRGSW require  for PBS
1603            let rgsw_cts = rgsw_cts_untrimmed
1604                .map(|rgsw_ct| {
1605                    trim_rgsw_ct_matrix_from_rgrg_to_rlrg(
1606                        rgsw_ct,
1607                        self.parameters().rgsw_by_rgsw_decomposition_params(),
1608                        self.parameters().rlwe_by_rgsw_decomposition_params(),
1609                    )
1610                })
1611                .collect_vec();
1612            rgsw_cts
1613        };
1614
1615        // auto keys
1616        let auto_keys = {
1617            let mut auto_keys = HashMap::new();
1618            let auto_elements_dlog = self.parameters().auto_element_dlogs();
1619            for i in auto_elements_dlog.into_iter() {
1620                let mut key = M::zeros(self.parameters().auto_decomposition_count().0, ring_size);
1621
1622                key_shares.iter().for_each(|s| {
1623                    let auto_key_share_i =
1624                        s.auto_keys_share().get(&i).expect("Auto key {i} missing");
1625                    assert!(
1626                        auto_key_share_i.dimension()
1627                            == (self.parameters().auto_decomposition_count().0, ring_size)
1628                    );
1629                    izip!(key.iter_rows_mut(), auto_key_share_i.iter_rows()).for_each(
1630                        |(partb_out, partb_share)| {
1631                            rlwe_modop.elwise_add_mut(partb_out.as_mut(), partb_share.as_ref());
1632                        },
1633                    );
1634                });
1635
1636                auto_keys.insert(i, key);
1637            }
1638            auto_keys
1639        };
1640
1641        // LWE ksk
1642        let lwe_ksk = {
1643            let mut lwe_ksk =
1644                M::R::zeros(self.parameters().lwe_decomposition_count().0 * ring_size);
1645            key_shares.iter().for_each(|s| {
1646                assert!(
1647                    s.lwe_ksk_share().as_ref().len()
1648                        == self.parameters().lwe_decomposition_count().0 * ring_size
1649                );
1650                lwe_modop.elwise_add_mut(lwe_ksk.as_mut(), s.lwe_ksk_share().as_ref());
1651            });
1652            lwe_ksk
1653        };
1654
1655        SeededNonInteractiveMultiPartyServerKey::new(
1656            ui_to_s_ksks,
1657            key_order,
1658            rgsw_cts,
1659            auto_keys,
1660            lwe_ksk,
1661            cr_seed.clone(),
1662            self.parameters().clone(),
1663        )
1664    }
1665
1666    pub(super) fn non_interactive_multi_party_key_share<
1667        K: NonInteractiveMultiPartyClientKey<Element = i32>,
1668    >(
1669        &self,
1670        cr_seed: &NonInteractiveMultiPartyCrs<[u8; 32]>,
1671        self_index: usize,
1672        total_users: usize,
1673        client_key: &K,
1674    ) -> CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare<
1675        M,
1676        NonInteractiveMultiPartyCrs<[u8; 32]>,
1677    > {
1678        assert_eq!(
1679            self.parameters().variant(),
1680            &ParameterVariant::NonInteractiveMultiParty
1681        );
1682
1683        // TODO:  check whether parameters support `total_users`
1684        let nttop = self.pbs_info().nttop_rlweq();
1685        let rlwe_modop = self.pbs_info().modop_rlweq();
1686        let ring_size = self.pbs_info().rlwe_n();
1687        let rlwe_q = self.parameters().rlwe_q();
1688
1689        let sk_rlwe = client_key.sk_rlwe();
1690        let sk_u_rlwe = client_key.sk_u_rlwe();
1691        let sk_lwe = client_key.sk_lwe();
1692
1693        let (ui_to_s_ksk, ksk_zero_encs_for_others) = DefaultSecureRng::with_local_mut(|rng| {
1694            // ui_to_s_ksk
1695            let non_interactive_decomposer = self
1696                .parameters()
1697                .non_interactive_ui_to_s_key_switch_decomposer::<DefaultDecomposer<M::MatElement>>(
1698                );
1699            let non_interactive_gadget_vec = non_interactive_decomposer.gadget_vector();
1700            let ui_to_s_ksk = {
1701                let mut p_rng = DefaultSecureRng::new_seeded(
1702                    cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(self_index),
1703                );
1704
1705                non_interactive_ksk_gen::<M, _, _, _, _, _>(
1706                    &sk_rlwe,
1707                    &sk_u_rlwe,
1708                    &non_interactive_gadget_vec,
1709                    &mut p_rng,
1710                    rng,
1711                    nttop,
1712                    rlwe_modop,
1713                )
1714            };
1715
1716            // zero encryptions for others uj_to_s ksk
1717            let all_users_except_self = (0..total_users).filter(|x| *x != self_index);
1718            let zero_encs_for_others = all_users_except_self
1719                .map(|other_user_index| {
1720                    let mut p_rng = DefaultSecureRng::new_seeded(
1721                        cr_seed.ui_to_s_ks_seed_for_user_i::<DefaultSecureRng>(other_user_index),
1722                    );
1723                    let zero_encs =
1724                        non_interactive_ksk_zero_encryptions_for_other_party_i::<M, _, _, _, _, _>(
1725                            &sk_rlwe,
1726                            &non_interactive_gadget_vec,
1727                            &mut p_rng,
1728                            rng,
1729                            nttop,
1730                            rlwe_modop,
1731                        );
1732                    zero_encs
1733                })
1734                .collect_vec();
1735
1736            (ui_to_s_ksk, zero_encs_for_others)
1737        });
1738
1739        // Non-interactive RGSW cts
1740        let (ni_rgsw_zero_encs, self_leader_ni_rgsw_cts, not_self_leader_rgsw_cts) = {
1741            // Warning: Below we assume that max(d_a, d_b) for RLWE x RGSW are always
1742            // smaller than max(d_a, d_b) for RGSW x RGSW. The assumption is reasonable
1743            // since RGSW x RGSW multiplication always precede RLWE x RGSW multiplication,
1744            // hence require greater room.
1745            let rgsw_x_rgsw_decomposer = self
1746                .parameters()
1747                .rgsw_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1748            let rlwe_x_rgsw_decomposer = self
1749                .parameters()
1750                .rlwe_rgsw_decomposer::<DefaultDecomposer<M::MatElement>>();
1751
1752            let sj_poly_eval = {
1753                let mut s = M::R::try_convert_from(&sk_rlwe, rlwe_q);
1754                nttop.forward(s.as_mut());
1755                s
1756            };
1757
1758            let d_rgsw_a = rgsw_x_rgsw_decomposer.a().decomposition_count();
1759
1760            // Zero encyptions for each LWE index.
1761            // Zero encryptions are needed to generate RLWE(-sm) from a_i * u_j + e. Hence,
1762            // zero encryptions are only required for first `d_a` a's where d_a
1763            // is decomposition count `a` in RGSW x RGSW.
1764            let zero_encs = {
1765                (0..self.parameters().lwe_n().0)
1766                    .map(|lwe_index| {
1767                        let mut p_rng = DefaultSecureRng::new_seeded(
1768                            cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1769                        );
1770
1771                        let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1772
1773                        let mut zero_enc = M::zeros(d_rgsw_a, self.parameters().rlwe_n().0);
1774                        zero_enc.iter_rows_mut().for_each(|out| {
1775                            // sample a_i
1776                            RandomFillUniformInModulus::random_fill(
1777                                &mut p_rng,
1778                                rlwe_q,
1779                                out.as_mut(),
1780                            );
1781
1782                            // a_i * s_j
1783                            nttop.forward(out.as_mut());
1784                            rlwe_modop.elwise_mul_mut(out.as_mut(), sj_poly_eval.as_ref());
1785                            nttop.backward(out.as_mut());
1786
1787                            // a_j * s_j + e
1788                            DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1789                                RandomFillGaussianInModulus::random_fill(
1790                                    rng,
1791                                    rlwe_q,
1792                                    scratch.as_mut(),
1793                                );
1794                            });
1795
1796                            rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1797                        });
1798
1799                        zero_enc
1800                    })
1801                    .collect_vec()
1802            };
1803
1804            let uj_poly_eval = {
1805                let mut u = M::R::try_convert_from(&sk_u_rlwe, rlwe_q);
1806                nttop.forward(u.as_mut());
1807                u
1808            };
1809
1810            // Non-interactive RGSW ciphertexts: a_i u_j + e + \beta X^{s_j[l]}
1811            // Non-interactive RGSW ciphertexts are needed for both RLWE'(-sm)
1812            // and RLWE'(m). Hence, we should generate them a_i's with i \in [0,
1813            // max(d_a, d_b)) where d_{a/b} are either decomposition counts for
1814            // RGSW x RGSW (if self is not leader for l^th) or RLWE x RGSW (if
1815            // self is leader for l^th index)
1816            let (self_start_index, self_end_index) = interactive_mult_party_user_id_lwe_segment(
1817                self_index,
1818                total_users,
1819                self.parameters().lwe_n().0,
1820            );
1821
1822            // For LWE indices [self_start_index, self_end_index) user generates
1823            // non-interactive RGSW cts for RLWE x RGSW product. We refer to
1824            // such indices where user is the leader. For the rest of
1825            // the indices user generates non-interactive RGWS cts for RGSW x
1826            // RGSW multiplication. We refer to such indices as where user is
1827            // not the leader.
1828
1829            let self_leader_ni_rgsw_cts = {
1830                let max_rlwe_x_rgsw_d = std::cmp::max(
1831                    rlwe_x_rgsw_decomposer.a().decomposition_count(),
1832                    rlwe_x_rgsw_decomposer.b().decomposition_count(),
1833                );
1834                (self_start_index..self_end_index)
1835                    .map(|lwe_index| {
1836                        let mut p_rng = DefaultSecureRng::new_seeded(
1837                            cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1838                        );
1839                        let mut ni_rgsw_cts =
1840                            M::zeros(max_rlwe_x_rgsw_d, self.parameters().rlwe_n().0);
1841                        let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1842                        ni_rgsw_cts.iter_rows_mut().for_each(|out| {
1843                            // sample a_i
1844                            RandomFillUniformInModulus::random_fill(
1845                                &mut p_rng,
1846                                rlwe_q,
1847                                out.as_mut(),
1848                            );
1849
1850                            // u_j * a_i
1851                            nttop.forward(out.as_mut());
1852                            rlwe_modop.elwise_mul_mut(out.as_mut(), uj_poly_eval.as_ref());
1853                            nttop.backward(out.as_mut());
1854
1855                            // u_j + a_i + e
1856                            DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1857                                RandomFillGaussianInModulus::random_fill(
1858                                    rng,
1859                                    rlwe_q,
1860                                    scratch.as_mut(),
1861                                );
1862                            });
1863                            rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1864                        });
1865
1866                        ni_rgsw_cts
1867                    })
1868                    .collect_vec()
1869            };
1870
1871            let not_self_leader_rgsw_cts = {
1872                let max_rgsw_x_rgsw_d = std::cmp::max(
1873                    rgsw_x_rgsw_decomposer.a().decomposition_count(),
1874                    rgsw_x_rgsw_decomposer.b().decomposition_count(),
1875                );
1876                ((0..self_start_index).chain(self_end_index..self.parameters().lwe_n().0))
1877                    .map(|lwe_index| {
1878                        let mut p_rng = DefaultSecureRng::new_seeded(
1879                            cr_seed.ni_rgsw_ct_seed_for_index::<DefaultSecureRng>(lwe_index),
1880                        );
1881                        let mut ni_rgsw_cts =
1882                            M::zeros(max_rgsw_x_rgsw_d, self.parameters().rlwe_n().0);
1883                        let mut scratch = M::R::zeros(self.parameters().rlwe_n().0);
1884                        ni_rgsw_cts.iter_rows_mut().for_each(|out| {
1885                            // sample a_i
1886                            RandomFillUniformInModulus::random_fill(
1887                                &mut p_rng,
1888                                rlwe_q,
1889                                out.as_mut(),
1890                            );
1891
1892                            // u_j * a_i
1893                            nttop.forward(out.as_mut());
1894                            rlwe_modop.elwise_mul_mut(out.as_mut(), uj_poly_eval.as_ref());
1895                            nttop.backward(out.as_mut());
1896
1897                            // u_j + a_i + e
1898                            DefaultSecureRng::with_local_mut_mut(&mut |rng| {
1899                                RandomFillGaussianInModulus::random_fill(
1900                                    rng,
1901                                    rlwe_q,
1902                                    scratch.as_mut(),
1903                                );
1904                            });
1905                            rlwe_modop.elwise_add_mut(out.as_mut(), scratch.as_ref());
1906                        });
1907
1908                        ni_rgsw_cts
1909                    })
1910                    .collect_vec()
1911            };
1912
1913            (zero_encs, self_leader_ni_rgsw_cts, not_self_leader_rgsw_cts)
1914        };
1915
1916        // Auto key share
1917        let auto_keys_share = {
1918            let auto_seed = cr_seed.auto_keys_cts_seed::<DefaultSecureRng>();
1919            self._common_rountine_multi_party_auto_keys_share_gen(auto_seed, &sk_rlwe)
1920        };
1921
1922        // Lwe Ksk share
1923        let lwe_ksk_share = {
1924            let lwe_ksk_seed = cr_seed.lwe_ksk_cts_seed::<DefaultSecureRng>();
1925            self._common_rountine_multi_party_lwe_ksk_share_gen(lwe_ksk_seed, &sk_rlwe, &sk_lwe)
1926        };
1927
1928        CommonReferenceSeededNonInteractiveMultiPartyServerKeyShare::new(
1929            self_leader_ni_rgsw_cts,
1930            not_self_leader_rgsw_cts,
1931            ni_rgsw_zero_encs,
1932            ui_to_s_ksk,
1933            ksk_zero_encs_for_others,
1934            auto_keys_share,
1935            lwe_ksk_share,
1936            self_index,
1937            cr_seed.clone(),
1938        )
1939    }
1940
1941    fn _common_rountine_multi_party_auto_keys_share_gen(
1942        &self,
1943        auto_seed: <DefaultSecureRng as NewWithSeed>::Seed,
1944        sk_rlwe: &[i32],
1945    ) -> HashMap<usize, M> {
1946        let g = self.pbs_info.parameters.g();
1947        let ring_size = self.pbs_info.parameters.rlwe_n().0;
1948        let br_q = self.pbs_info.parameters.br_q();
1949        let rlweq_modop = &self.pbs_info.rlwe_modop;
1950        let rlweq_nttop = &self.pbs_info.rlwe_nttop;
1951
1952        DefaultSecureRng::with_local_mut(|rng| {
1953            let mut p_rng = DefaultSecureRng::new_seeded(auto_seed);
1954
1955            let mut auto_keys = HashMap::new();
1956            let auto_gadget = self.pbs_info.auto_decomposer.gadget_vector();
1957            let auto_element_dlogs = self.pbs_info.parameters.auto_element_dlogs();
1958
1959            for i in auto_element_dlogs.into_iter() {
1960                let g_pow = if i == 0 {
1961                    -(g as isize)
1962                } else {
1963                    (g.pow(i as u32) % br_q) as isize
1964                };
1965
1966                let mut ksk_out = M::zeros(
1967                    self.pbs_info.auto_decomposer.decomposition_count(),
1968                    ring_size,
1969                );
1970                galois_key_gen(
1971                    &mut ksk_out,
1972                    sk_rlwe,
1973                    g_pow,
1974                    &auto_gadget,
1975                    rlweq_modop,
1976                    rlweq_nttop,
1977                    &mut p_rng,
1978                    rng,
1979                );
1980                auto_keys.insert(i, ksk_out);
1981            }
1982
1983            auto_keys
1984        })
1985    }
1986
1987    fn _common_rountine_multi_party_lwe_ksk_share_gen(
1988        &self,
1989        lwe_ksk_seed: <DefaultSecureRng as NewWithSeed>::Seed,
1990        sk_rlwe: &[i32],
1991        sk_lwe: &[i32],
1992    ) -> M::R {
1993        DefaultSecureRng::with_local_mut(|rng| {
1994            let mut p_rng = DefaultSecureRng::new_seeded(lwe_ksk_seed);
1995            let mut lwe_ksk = M::R::zeros(
1996                self.pbs_info.lwe_decomposer.decomposition_count() * self.parameters().rlwe_n().0,
1997            );
1998            let lwe_modop = &self.pbs_info.lwe_modop;
1999            let d_lwe_gadget_vec = self.pbs_info.lwe_decomposer.gadget_vector();
2000            lwe_ksk_keygen(
2001                sk_rlwe,
2002                sk_lwe,
2003                &mut lwe_ksk,
2004                &d_lwe_gadget_vec,
2005                lwe_modop,
2006                &mut p_rng,
2007                rng,
2008            );
2009            lwe_ksk
2010        })
2011    }
2012
2013    pub(super) fn multi_party_public_key_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
2014        &self,
2015        cr_seed: &MultiPartyCrs<[u8; 32]>,
2016        client_key: &K,
2017    ) -> CommonReferenceSeededCollectivePublicKeyShare<
2018        <M as Matrix>::R,
2019        [u8; 32],
2020        BoolParameters<<M as Matrix>::MatElement>,
2021    > {
2022        DefaultSecureRng::with_local_mut(|rng| {
2023            let mut share_out = M::R::zeros(self.pbs_info.parameters.rlwe_n().0);
2024            let modop = &self.pbs_info.rlwe_modop;
2025            let nttop = &self.pbs_info.rlwe_nttop;
2026            let pk_seed = cr_seed.public_key_share_seed::<DefaultSecureRng>();
2027            let mut main_prng = DefaultSecureRng::new_seeded(pk_seed);
2028            public_key_share(
2029                &mut share_out,
2030                &client_key.sk_rlwe(),
2031                modop,
2032                nttop,
2033                &mut main_prng,
2034                rng,
2035            );
2036            CommonReferenceSeededCollectivePublicKeyShare::new(
2037                share_out,
2038                pk_seed,
2039                self.pbs_info.parameters.clone(),
2040            )
2041        })
2042    }
2043
2044    pub(super) fn multi_party_decryption_share<K: InteractiveMultiPartyClientKey<Element = i32>>(
2045        &self,
2046        lwe_ct: &M::R,
2047        client_key: &K,
2048    ) -> <M as Matrix>::MatElement {
2049        assert!(lwe_ct.as_ref().len() == self.pbs_info.parameters.rlwe_n().0 + 1);
2050        let modop = &self.pbs_info.rlwe_modop;
2051        let mut neg_s =
2052            M::R::try_convert_from(&client_key.sk_rlwe(), &self.pbs_info.parameters.rlwe_q());
2053        modop.elwise_neg_mut(neg_s.as_mut());
2054
2055        let mut neg_sa = M::MatElement::zero();
2056        izip!(lwe_ct.as_ref().iter().skip(1), neg_s.as_ref().iter()).for_each(|(ai, nsi)| {
2057            neg_sa = modop.add(&neg_sa, &modop.mul(ai, nsi));
2058        });
2059
2060        let e = DefaultSecureRng::with_local_mut(|rng| {
2061            let mut e =
2062                RandomGaussianElementInModulus::random(rng, self.pbs_info.parameters.rlwe_q());
2063            e
2064        });
2065        let share = modop.add(&neg_sa, &e);
2066
2067        share
2068    }
2069
2070    pub(crate) fn multi_party_decrypt(&self, shares: &[M::MatElement], lwe_ct: &M::R) -> bool {
2071        let modop = &self.pbs_info.rlwe_modop;
2072        let mut sum_a = M::MatElement::zero();
2073        shares
2074            .iter()
2075            .for_each(|share_i| sum_a = modop.add(&sum_a, &share_i));
2076
2077        let encoded_m = modop.add(&lwe_ct.as_ref()[0], &sum_a);
2078        self.pbs_info.parameters.rlwe_q().decode(encoded_m)
2079    }
2080
2081    pub(crate) fn pk_encrypt(&self, pk: &M, m: bool) -> M::R {
2082        self.pk_encrypt_batched(pk, &vec![m]).remove(0)
2083    }
2084
2085    /// Encrypts a batch booleans as multiple LWE ciphertexts.
2086    ///
2087    /// For public key encryption we first encrypt `m` as a RLWE ciphertext and
2088    /// then sample extract LWE samples at required indices.
2089    ///
2090    /// - TODO(Jay:) Communication can be improved by not sample exctracting and
2091    ///   instead just truncate degree 0 values (part Bs)
2092    pub(crate) fn pk_encrypt_batched(&self, pk: &M, m: &[bool]) -> Vec<M::R> {
2093        DefaultSecureRng::with_local_mut(|rng| {
2094            let ring_size = self.pbs_info.parameters.rlwe_n().0;
2095            assert!(
2096                m.len() <= ring_size,
2097                "Cannot batch encrypt > ring_size{ring_size} elements at once"
2098            );
2099
2100            let modop = &self.pbs_info.rlwe_modop;
2101            let nttop = &self.pbs_info.rlwe_nttop;
2102
2103            // RLWE(0)
2104            // sample ephemeral key u
2105            let mut u = vec![0i32; ring_size];
2106            fill_random_ternary_secret_with_hamming_weight(u.as_mut(), ring_size >> 1, rng);
2107            let mut u = M::R::try_convert_from(&u, &self.pbs_info.parameters.rlwe_q());
2108            nttop.forward(u.as_mut());
2109
2110            let mut ua = M::R::zeros(ring_size);
2111            ua.as_mut().copy_from_slice(pk.get_row_slice(0));
2112            let mut ub = M::R::zeros(ring_size);
2113            ub.as_mut().copy_from_slice(pk.get_row_slice(1));
2114
2115            // a*u
2116            nttop.forward(ua.as_mut());
2117            modop.elwise_mul_mut(ua.as_mut(), u.as_ref());
2118            nttop.backward(ua.as_mut());
2119
2120            // b*u
2121            nttop.forward(ub.as_mut());
2122            modop.elwise_mul_mut(ub.as_mut(), u.as_ref());
2123            nttop.backward(ub.as_mut());
2124
2125            let mut rlwe = M::zeros(2, ring_size);
2126            // sample error
2127            rlwe.iter_rows_mut().for_each(|ri| {
2128                RandomFillGaussianInModulus::<[M::MatElement], CiphertextModulus<M::MatElement>>::random_fill(
2129                    rng,
2130                    &self.pbs_info.parameters.rlwe_q(),
2131                    ri.as_mut(),
2132                );
2133            });
2134
2135            // a*u + e0
2136            modop.elwise_add_mut(rlwe.get_row_mut(0), ua.as_ref());
2137            // b*u + e1
2138            modop.elwise_add_mut(rlwe.get_row_mut(1), ub.as_ref());
2139
2140            //FIXME(Jay): Figure out a way to get Q/8 form modulus
2141            let mut m_vec = M::R::zeros(ring_size);
2142            izip!(m_vec.as_mut().iter_mut(), m.iter()).for_each(|(m_el, m_bool)| {
2143                if *m_bool {
2144                    // Q/8
2145                    *m_el = self.pbs_info.rlwe_q().true_el()
2146                } else {
2147                    // -Q/8
2148                    *m_el = self.pbs_info.rlwe_q().false_el()
2149                }
2150            });
2151
2152            // b*u + e1 + m
2153            modop.elwise_add_mut(rlwe.get_row_mut(1), m_vec.as_ref());
2154            // rlwe.set(1, 0, modop.add(rlwe.get(1, 0), &m));
2155
2156            // sample extract index required indices
2157            let samples = m.len();
2158            (0..samples)
2159                .into_iter()
2160                .map(|i| {
2161                    let mut lwe_out = M::R::zeros(ring_size + 1);
2162                    sample_extract(&mut lwe_out, &rlwe, modop, i);
2163                    lwe_out
2164                })
2165                .collect_vec()
2166        })
2167    }
2168
2169    /// TODO(Jay): Fetch client key from thread local
2170    pub fn sk_encrypt<K: SinglePartyClientKey<Element = i32>>(
2171        &self,
2172        m: bool,
2173        client_key: &K,
2174    ) -> M::R {
2175        //FIXME(Jay): Figure out a way to get Q/8 form modulus
2176        let m = if m {
2177            // Q/8
2178            self.pbs_info.rlwe_q().true_el()
2179        } else {
2180            // -Q/8
2181            self.pbs_info.rlwe_q().false_el()
2182        };
2183
2184        DefaultSecureRng::with_local_mut(|rng| {
2185            let mut lwe_out = M::R::zeros(self.pbs_info.parameters.rlwe_n().0 + 1);
2186            encrypt_lwe(
2187                &mut lwe_out,
2188                &m,
2189                &client_key.sk_rlwe(),
2190                &self.pbs_info.rlwe_modop,
2191                rng,
2192            );
2193            lwe_out
2194        })
2195    }
2196
2197    pub fn sk_decrypt<K: SinglePartyClientKey<Element = i32>>(
2198        &self,
2199        lwe_ct: &M::R,
2200        client_key: &K,
2201    ) -> bool {
2202        let m = decrypt_lwe(lwe_ct, &client_key.sk_rlwe(), &self.pbs_info.rlwe_modop);
2203        self.pbs_info.rlwe_q().decode(m)
2204    }
2205}
2206
2207impl<M, NttOp, RlweModOp, LweModOp, Skey> BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
2208where
2209    M: MatrixMut + MatrixEntity,
2210    M::R: RowMut + RowEntity,
2211    M::MatElement: PrimInt + FromPrimitive + One + Copy + Zero + Display + WrappingSub + NumInfo,
2212    RlweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2213    LweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2214    NttOp: Ntt<Element = M::MatElement>,
2215{
2216    /// Returns c0 + c1 + Q/4
2217    fn _add_and_shift_lwe_cts(&self, c0: &mut M::R, c1: &M::R) {
2218        let modop = &self.pbs_info.rlwe_modop;
2219        modop.elwise_add_mut(c0.as_mut(), c1.as_ref());
2220        // +Q/4
2221        c0.as_mut()[0] = modop.add(&c0.as_ref()[0], &self.pbs_info.rlwe_qby4);
2222    }
2223
2224    /// Returns 2(c0 - c1) + Q/4
2225    fn _subtract_double_lwe_cts(&self, c0: &mut M::R, c1: &M::R) {
2226        let modop = &self.pbs_info.rlwe_modop;
2227        // c0 - c1
2228        modop.elwise_sub_mut(c0.as_mut(), c1.as_ref());
2229
2230        // double
2231        c0.as_mut().iter_mut().for_each(|v| *v = modop.add(v, v));
2232    }
2233}
2234
2235impl<M, NttOp, RlweModOp, LweModOp, Skey> BooleanGates
2236    for BoolEvaluator<M, NttOp, RlweModOp, LweModOp, Skey>
2237where
2238    M: MatrixMut + MatrixEntity,
2239    M::R: RowMut + RowEntity + Clone,
2240    M::MatElement: PrimInt
2241        + FromPrimitive
2242        + One
2243        + Copy
2244        + Zero
2245        + Display
2246        + WrappingSub
2247        + NumInfo
2248        + From<bool>
2249        + WrappingAdd
2250        + Debug,
2251    RlweModOp: VectorOps<Element = M::MatElement>
2252        + ArithmeticOps<Element = M::MatElement>
2253        + ShoupMatrixFMA<M::R>,
2254    LweModOp: VectorOps<Element = M::MatElement> + ArithmeticOps<Element = M::MatElement>,
2255    NttOp: Ntt<Element = M::MatElement>,
2256    Skey: PbsKey<AutoKey = <Skey as PbsKey>::RgswCt, LweKskKey = M>,
2257    <Skey as PbsKey>::RgswCt: WithShoupRepr<M = M>,
2258{
2259    type Ciphertext = M::R;
2260    type Key = Skey;
2261
2262    fn nand_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2263        self._add_and_shift_lwe_cts(c0, c1);
2264
2265        // PBS
2266        pbs(
2267            &self.pbs_info,
2268            &self.nand_test_vec,
2269            c0,
2270            server_key,
2271            &mut self.scratch_memory.lwe_vector,
2272            &mut self.scratch_memory.decomposition_matrix,
2273        );
2274    }
2275
2276    fn and_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2277        self._add_and_shift_lwe_cts(c0, c1);
2278
2279        // PBS
2280        pbs(
2281            &self.pbs_info,
2282            &self.and_test_vec,
2283            c0,
2284            server_key,
2285            &mut self.scratch_memory.lwe_vector,
2286            &mut self.scratch_memory.decomposition_matrix,
2287        );
2288    }
2289
2290    fn or_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2291        self._add_and_shift_lwe_cts(c0, c1);
2292
2293        // PBS
2294        pbs(
2295            &self.pbs_info,
2296            &self.or_test_vec,
2297            c0,
2298            server_key,
2299            &mut self.scratch_memory.lwe_vector,
2300            &mut self.scratch_memory.decomposition_matrix,
2301        );
2302    }
2303
2304    fn nor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2305        self._add_and_shift_lwe_cts(c0, c1);
2306
2307        // PBS
2308        pbs(
2309            &self.pbs_info,
2310            &self.nor_test_vec,
2311            c0,
2312            server_key,
2313            &mut self.scratch_memory.lwe_vector,
2314            &mut self.scratch_memory.decomposition_matrix,
2315        )
2316    }
2317
2318    fn xor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2319        self._subtract_double_lwe_cts(c0, c1);
2320
2321        // PBS
2322        pbs(
2323            &self.pbs_info,
2324            &self.xor_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 xnor_inplace(&mut self, c0: &mut M::R, c1: &M::R, server_key: &Self::Key) {
2333        self._subtract_double_lwe_cts(c0, c1);
2334
2335        // PBS
2336        pbs(
2337            &self.pbs_info,
2338            &self.xnor_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 not_inplace(&mut self, c0: &mut M::R) {
2347        let modop = &self.pbs_info.rlwe_modop;
2348        c0.as_mut().iter_mut().for_each(|v| *v = modop.neg(v));
2349    }
2350
2351    fn and(
2352        &mut self,
2353        c0: &Self::Ciphertext,
2354        c1: &Self::Ciphertext,
2355        key: &Self::Key,
2356    ) -> Self::Ciphertext {
2357        let mut out = c0.clone();
2358        self.and_inplace(&mut out, c1, key);
2359        out
2360    }
2361
2362    fn nand(
2363        &mut self,
2364        c0: &Self::Ciphertext,
2365        c1: &Self::Ciphertext,
2366        key: &Self::Key,
2367    ) -> Self::Ciphertext {
2368        let mut out = c0.clone();
2369        self.nand_inplace(&mut out, c1, key);
2370        out
2371    }
2372
2373    fn or(
2374        &mut self,
2375        c0: &Self::Ciphertext,
2376        c1: &Self::Ciphertext,
2377        key: &Self::Key,
2378    ) -> Self::Ciphertext {
2379        let mut out = c0.clone();
2380        self.or_inplace(&mut out, c1, key);
2381        out
2382    }
2383
2384    fn nor(
2385        &mut self,
2386        c0: &Self::Ciphertext,
2387        c1: &Self::Ciphertext,
2388        key: &Self::Key,
2389    ) -> Self::Ciphertext {
2390        let mut out = c0.clone();
2391        self.nor_inplace(&mut out, c1, key);
2392        out
2393    }
2394
2395    fn xnor(
2396        &mut self,
2397        c0: &Self::Ciphertext,
2398        c1: &Self::Ciphertext,
2399        key: &Self::Key,
2400    ) -> Self::Ciphertext {
2401        let mut out = c0.clone();
2402        self.xnor_inplace(&mut out, c1, key);
2403        out
2404    }
2405
2406    fn xor(
2407        &mut self,
2408        c0: &Self::Ciphertext,
2409        c1: &Self::Ciphertext,
2410        key: &Self::Key,
2411    ) -> Self::Ciphertext {
2412        let mut out = c0.clone();
2413        self.xor_inplace(&mut out, c1, key);
2414        out
2415    }
2416
2417    fn not(&mut self, c: &Self::Ciphertext) -> Self::Ciphertext {
2418        let mut out = c.clone();
2419        self.not_inplace(&mut out);
2420        out
2421    }
2422}