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