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