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