arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/bool/mp_api.rs
src/bool/mp_api.rsRaw
  1use std::{cell::RefCell, ops::Mul, sync::OnceLock};
  2
  3use crate::{
  4    backend::{ModularOpsU64, ModulusPowerOf2},
  5    ntt::NttBackendU64,
  6    random::{DefaultSecureRng, NewWithSeed},
  7    utils::{Global, WithLocal},
  8};
  9
 10use super::{evaluator::MultiPartyCrs, keys::*, parameters::*, ClientKey, ParameterSelector};
 11
 12pub(crate) type BoolEvaluator = super::evaluator::BoolEvaluator<
 13    Vec<Vec<u64>>,
 14    NttBackendU64,
 15    ModularOpsU64<CiphertextModulus<u64>>,
 16    ModulusPowerOf2<CiphertextModulus<u64>>,
 17    ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>,
 18>;
 19
 20thread_local! {
 21    static BOOL_EVALUATOR: RefCell<Option<BoolEvaluator>> = RefCell::new(None);
 22
 23}
 24static BOOL_SERVER_KEY: OnceLock<ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>> = OnceLock::new();
 25
 26static MULTI_PARTY_CRS: OnceLock<MultiPartyCrs<[u8; 32]>> = OnceLock::new();
 27
 28pub fn set_parameter_set(select: ParameterSelector) {
 29    match select {
 30        ParameterSelector::MultiPartyLessThanOrEqualTo16 => {
 31            BOOL_EVALUATOR.with_borrow_mut(|v| *v = Some(BoolEvaluator::new(SMALL_MP_BOOL_PARAMS)));
 32        }
 33        ParameterSelector::HighCommunicationButFast2Party => {
 34            BOOL_EVALUATOR
 35                .with_borrow_mut(|v| *v = Some(BoolEvaluator::new(OPTIMISED_SMALL_MP_BOOL_PARAMS)));
 36        }
 37        _ => {
 38            panic!("Paramerters not supported")
 39        }
 40    }
 41}
 42
 43pub fn set_mp_seed(seed: [u8; 32]) {
 44    assert!(
 45        MULTI_PARTY_CRS.set(MultiPartyCrs { seed: seed }).is_ok(),
 46        "Attempted to set MP SEED twice."
 47    )
 48}
 49
 50pub fn gen_client_key() -> ClientKey {
 51    BoolEvaluator::with_local(|e| e.client_key())
 52}
 53
 54pub fn gen_mp_keys_phase1(
 55    ck: &ClientKey,
 56) -> CommonReferenceSeededCollectivePublicKeyShare<Vec<u64>, [u8; 32], BoolParameters<u64>> {
 57    BoolEvaluator::with_local(|e| {
 58        let pk_share = e.multi_party_public_key_share(MultiPartyCrs::global(), ck);
 59        pk_share
 60    })
 61}
 62
 63pub fn gen_mp_keys_phase2<R, ModOp>(
 64    ck: &ClientKey,
 65    user_id: usize,
 66    total_users: usize,
 67    pk: &PublicKey<Vec<Vec<u64>>, R, ModOp>,
 68) -> CommonReferenceSeededMultiPartyServerKeyShare<
 69    Vec<Vec<u64>>,
 70    BoolParameters<u64>,
 71    MultiPartyCrs<[u8; 32]>,
 72> {
 73    BoolEvaluator::with_local_mut(|e| {
 74        let server_key_share = e.multi_party_server_key_share(
 75            user_id,
 76            total_users,
 77            MultiPartyCrs::global(),
 78            pk.key(),
 79            ck,
 80        );
 81        server_key_share
 82    })
 83}
 84
 85pub fn aggregate_public_key_shares(
 86    shares: &[CommonReferenceSeededCollectivePublicKeyShare<
 87        Vec<u64>,
 88        [u8; 32],
 89        BoolParameters<u64>,
 90    >],
 91) -> PublicKey<Vec<Vec<u64>>, DefaultSecureRng, ModularOpsU64<CiphertextModulus<u64>>> {
 92    PublicKey::from(shares)
 93}
 94
 95pub fn aggregate_server_key_shares(
 96    shares: &[CommonReferenceSeededMultiPartyServerKeyShare<
 97        Vec<Vec<u64>>,
 98        BoolParameters<u64>,
 99        MultiPartyCrs<[u8; 32]>,
100    >],
101) -> SeededMultiPartyServerKey<Vec<Vec<u64>>, MultiPartyCrs<[u8; 32]>, BoolParameters<u64>> {
102    BoolEvaluator::with_local(|e| e.aggregate_multi_party_server_key_shares(shares))
103}
104
105impl
106    SeededMultiPartyServerKey<
107        Vec<Vec<u64>>,
108        MultiPartyCrs<<DefaultSecureRng as NewWithSeed>::Seed>,
109        BoolParameters<u64>,
110    >
111{
112    pub fn set_server_key(&self) {
113        assert!(
114            BOOL_SERVER_KEY
115                .set(ShoupServerKeyEvaluationDomain::from(
116                    ServerKeyEvaluationDomain::<_, _, DefaultSecureRng, NttBackendU64>::from(self),
117                ))
118                .is_ok(),
119            "Attempted to set server key twice."
120        );
121    }
122}
123
124//  MULTIPARTY CRS  //
125impl Global for MultiPartyCrs<[u8; 32]> {
126    fn global() -> &'static Self {
127        MULTI_PARTY_CRS
128            .get()
129            .expect("Multi Party Common Reference String not set")
130    }
131}
132
133// BOOL EVALUATOR //
134impl WithLocal for BoolEvaluator {
135    fn with_local<F, R>(func: F) -> R
136    where
137        F: Fn(&Self) -> R,
138    {
139        BOOL_EVALUATOR.with_borrow(|s| func(s.as_ref().expect("Parameters not set")))
140    }
141
142    fn with_local_mut<F, R>(func: F) -> R
143    where
144        F: Fn(&mut Self) -> R,
145    {
146        BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set")))
147    }
148
149    fn with_local_mut_mut<F, R>(func: &mut F) -> R
150    where
151        F: FnMut(&mut Self) -> R,
152    {
153        BOOL_EVALUATOR.with_borrow_mut(|s| func(s.as_mut().expect("Parameters not set")))
154    }
155}
156
157pub(crate) type RuntimeServerKey = ShoupServerKeyEvaluationDomain<Vec<Vec<u64>>>;
158impl Global for RuntimeServerKey {
159    fn global() -> &'static Self {
160        BOOL_SERVER_KEY.get().expect("Server key not set!")
161    }
162}
163
164mod impl_enc_dec {
165    use crate::{
166        bool::evaluator::BoolEncoding,
167        pbs::{sample_extract, PbsInfo},
168        rgsw::public_key_encrypt_rlwe,
169        Encryptor, Matrix, MatrixEntity, MultiPartyDecryptor, RowEntity,
170    };
171    use itertools::Itertools;
172    use num_traits::{ToPrimitive, Zero};
173
174    use super::*;
175
176    type Mat = Vec<Vec<u64>>;
177
178    impl<Rng, ModOp> Encryptor<[bool], Vec<Mat>> for PublicKey<Mat, Rng, ModOp> {
179        fn encrypt(&self, m: &[bool]) -> Vec<Mat> {
180            BoolEvaluator::with_local(|e| {
181                DefaultSecureRng::with_local_mut(|rng| {
182                    let parameters = e.parameters();
183                    let ring_size = parameters.rlwe_n().0;
184
185                    let rlwe_count = ((m.len() as f64 / ring_size as f64).ceil())
186                        .to_usize()
187                        .unwrap();
188
189                    // encrypt `m` into ceil(len(m)/N) RLWE ciphertexts
190                    let rlwes = (0..rlwe_count)
191                        .map(|index| {
192                            let mut message = vec![<Mat as Matrix>::MatElement::zero(); ring_size];
193                            m[(index * ring_size)..std::cmp::min(m.len(), (index + 1) * ring_size)]
194                                .iter()
195                                .enumerate()
196                                .for_each(|(i, v)| {
197                                    if *v {
198                                        message[i] = parameters.rlwe_q().true_el()
199                                    } else {
200                                        message[i] = parameters.rlwe_q().false_el()
201                                    }
202                                });
203
204                            // encrypt message
205                            let mut rlwe_out =
206                                <Mat as MatrixEntity>::zeros(2, parameters.rlwe_n().0);
207
208                            public_key_encrypt_rlwe::<_, _, _, _, i32, _>(
209                                &mut rlwe_out,
210                                self.key(),
211                                &message,
212                                e.pbs_info().modop_rlweq(),
213                                e.pbs_info().nttop_rlweq(),
214                                rng,
215                            );
216
217                            rlwe_out
218                        })
219                        .collect_vec();
220                    rlwes
221                })
222            })
223        }
224    }
225
226    impl<Rng, ModOp> Encryptor<bool, <Mat as Matrix>::R> for PublicKey<Mat, Rng, ModOp> {
227        fn encrypt(&self, m: &bool) -> <Mat as Matrix>::R {
228            let m = vec![*m];
229            let rlwe = &self.encrypt(m.as_slice())[0];
230            BoolEvaluator::with_local(|e| {
231                let mut lwe = <Mat as Matrix>::R::zeros(e.parameters().rlwe_n().0 + 1);
232                sample_extract(&mut lwe, rlwe, e.pbs_info().modop_rlweq(), 0);
233                lwe
234            })
235        }
236    }
237}
238
239#[cfg(test)]
240mod tests {
241    use std::thread::panicking;
242
243    use itertools::Itertools;
244    use rand::{thread_rng, RngCore};
245
246    use crate::{
247        bool::{
248            evaluator::BooleanGates,
249            keys::tests::{ideal_sk_rlwe, measure_noise_lwe},
250        },
251        evaluator::{BoolEncoding, BoolEvaluator},
252        Encryptor, MultiPartyDecryptor,
253    };
254
255    use super::*;
256
257    #[test]
258    fn multi_party_bool_gates() {
259        set_parameter_set(ParameterSelector::HighCommunicationButFast2Party);
260        let mut seed = [0u8; 32];
261        thread_rng().fill_bytes(&mut seed);
262        set_mp_seed(seed);
263
264        let parties = 2;
265        let cks = (0..parties).map(|_| gen_client_key()).collect_vec();
266
267        // round 1
268        let pk_shares = cks.iter().map(|k| gen_mp_keys_phase1(k)).collect_vec();
269
270        // collective pk
271        let pk = aggregate_public_key_shares(&pk_shares);
272
273        // round 2
274        let server_key_shares = cks
275            .iter()
276            .enumerate()
277            .map(|(user_id, k)| gen_mp_keys_phase2(k, user_id, parties, &pk))
278            .collect_vec();
279
280        // server key
281        let server_key = aggregate_server_key_shares(&server_key_shares);
282        server_key.set_server_key();
283
284        let mut m0 = false;
285        let mut m1 = true;
286
287        let mut ct0 = pk.encrypt(&m0);
288        let mut ct1 = pk.encrypt(&m1);
289
290        let ideal_sk_rlwe = ideal_sk_rlwe(&cks);
291        let parameters = BoolEvaluator::with_local(|e| e.parameters().clone());
292        let rlwe_modop = parameters.default_rlwe_modop();
293
294        for _ in 0..500 {
295            let ct_out =
296                BoolEvaluator::with_local_mut(|e| e.nand(&ct0, &ct1, RuntimeServerKey::global()));
297
298            let m_expected = !(m0 && m1);
299
300            let decryption_shares = cks
301                .iter()
302                .map(|k| k.gen_decryption_share(&ct_out))
303                .collect_vec();
304            let m_out = cks[0].aggregate_decryption_shares(&ct_out, &decryption_shares);
305
306            assert!(m_out == m_expected, "Expected {m_expected}, got {m_out}");
307            {
308                let m_expected_el = if m_expected == true {
309                    parameters.rlwe_q().true_el()
310                } else {
311                    parameters.rlwe_q().false_el()
312                };
313                let noise = measure_noise_lwe(&ct_out, m_expected_el, &ideal_sk_rlwe, &rlwe_modop);
314                println!("NAND Noise: {noise}");
315            }
316
317            m1 = m0;
318            m0 = m_expected;
319
320            ct1 = ct0;
321            ct0 = ct_out;
322        }
323
324        for _ in 0..500 {
325            let ct_out =
326                BoolEvaluator::with_local_mut(|e| e.xnor(&ct0, &ct1, RuntimeServerKey::global()));
327
328            let m_expected = !(m0 ^ m1);
329
330            let decryption_shares = cks
331                .iter()
332                .map(|k| k.gen_decryption_share(&ct_out))
333                .collect_vec();
334            let m_out = cks[0].aggregate_decryption_shares(&ct_out, &decryption_shares);
335
336            assert!(m_out == m_expected, "Expected {m_expected}, got {m_out}");
337
338            m1 = m0;
339            m0 = m_expected;
340
341            ct1 = ct0;
342            ct0 = ct_out;
343        }
344    }
345
346    mod sp_api {
347        use num_traits::ToPrimitive;
348        use rand::Rng;
349
350        use crate::{
351            backend::ModulusPowerOf2, evaluator::BoolEncoding, pbs::PbsInfo,
352            rgsw::secret_key_encrypt_rlwe, utils::WithLocal, Decryptor, ModularOpsU64,
353            NttBackendU64, SampleExtractor,
354        };
355
356        use super::*;
357
358        pub(crate) fn set_single_party_parameter_sets(parameter: BoolParameters<u64>) {
359            BOOL_EVALUATOR.with_borrow_mut(|e| *e = Some(BoolEvaluator::new(parameter)));
360        }
361
362        // SERVER KEY EVAL (/SHOUP) DOMAIN //
363        impl SeededSinglePartyServerKey<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]> {
364            pub fn set_server_key(&self) {
365                assert!(
366                    BOOL_SERVER_KEY
367                        .set(
368                            ShoupServerKeyEvaluationDomain::from(ServerKeyEvaluationDomain::<
369                                _,
370                                _,
371                                DefaultSecureRng,
372                                NttBackendU64,
373                            >::from(
374                                self
375                            ),)
376                        )
377                        .is_ok(),
378                    "Attempted to set server key twice."
379                );
380            }
381        }
382
383        pub(crate) fn gen_keys() -> (
384            ClientKey,
385            SeededSinglePartyServerKey<Vec<Vec<u64>>, BoolParameters<u64>, [u8; 32]>,
386        ) {
387            super::BoolEvaluator::with_local_mut(|e| {
388                let ck = e.client_key();
389                let sk = e.single_party_server_key(&ck);
390
391                (ck, sk)
392            })
393        }
394
395        impl<K: SinglePartyClientKey<Element = i32>> Encryptor<bool, Vec<u64>> for K {
396            fn encrypt(&self, m: &bool) -> Vec<u64> {
397                BoolEvaluator::with_local(|e| e.sk_encrypt(*m, self))
398            }
399        }
400
401        impl<K: SinglePartyClientKey<Element = i32>> Decryptor<bool, Vec<u64>> for K {
402            fn decrypt(&self, c: &Vec<u64>) -> bool {
403                BoolEvaluator::with_local(|e| e.sk_decrypt(c, self))
404            }
405        }
406        impl<K> Encryptor<[bool], (Vec<Vec<u64>>, [u8; 32])> for K
407        where
408            K: SinglePartyClientKey<Element = i32>,
409        {
410            fn encrypt(&self, m: &[bool]) -> (Vec<Vec<u64>>, [u8; 32]) {
411                BoolEvaluator::with_local(|e| {
412                    DefaultSecureRng::with_local_mut(|rng| {
413                        let parameters = e.parameters();
414                        let ring_size = parameters.rlwe_n().0;
415
416                        let rlwe_count = ((m.len() as f64 / ring_size as f64).ceil())
417                            .to_usize()
418                            .unwrap();
419
420                        let mut seed = <DefaultSecureRng as NewWithSeed>::Seed::default();
421                        rng.fill_bytes(&mut seed);
422                        let mut prng = DefaultSecureRng::new_seeded(seed);
423
424                        let sk_u = self.sk_rlwe();
425
426                        // encrypt `m` into ceil(len(m)/N) RLWE ciphertexts
427                        let rlwes = (0..rlwe_count)
428                            .map(|index| {
429                                let mut message = vec![0; ring_size];
430                                m[(index * ring_size)
431                                    ..std::cmp::min(m.len(), (index + 1) * ring_size)]
432                                    .iter()
433                                    .enumerate()
434                                    .for_each(|(i, v)| {
435                                        if *v {
436                                            message[i] = parameters.rlwe_q().true_el()
437                                        } else {
438                                            message[i] = parameters.rlwe_q().false_el()
439                                        }
440                                    });
441
442                                // encrypt message
443                                let mut rlwe_out = vec![0u64; parameters.rlwe_n().0];
444
445                                secret_key_encrypt_rlwe(
446                                    &message,
447                                    &mut rlwe_out,
448                                    &sk_u,
449                                    e.pbs_info().modop_rlweq(),
450                                    e.pbs_info().nttop_rlweq(),
451                                    &mut prng,
452                                    rng,
453                                );
454
455                                rlwe_out
456                            })
457                            .collect_vec();
458
459                        (rlwes, seed)
460                    })
461                })
462            }
463        }
464
465        #[test]
466        fn batch_extract_works() {
467            set_single_party_parameter_sets(SP_TEST_BOOL_PARAMS);
468
469            let (ck, sk) = gen_keys();
470            sk.set_server_key();
471
472            let batch_size = (SP_TEST_BOOL_PARAMS.rlwe_n().0 * 3 + 123);
473            let m = (0..batch_size)
474                .map(|_| thread_rng().gen::<u8>())
475                .collect_vec();
476
477            let seeded_ct = ck.encrypt(m.as_slice());
478            let ct = seeded_ct.unseed::<Vec<Vec<u64>>>();
479
480            let m_back = (0..batch_size)
481                .map(|i| ck.decrypt(&ct.extract(i)))
482                .collect_vec();
483
484            assert_eq!(m, m_back);
485        }
486
487        #[test]
488        #[cfg(feature = "interactive_mp")]
489        fn all_uint8_apis() {
490            use num_traits::Euclid;
491
492            set_single_party_parameter_sets(SP_TEST_BOOL_PARAMS);
493
494            let (ck, sk) = gen_keys();
495            sk.set_server_key();
496
497            for i in 144..=255 {
498                for j in 100..=255 {
499                    let m0 = i;
500                    let m1 = j;
501                    let c0 = ck.encrypt(&m0);
502                    let c1 = ck.encrypt(&m1);
503
504                    assert!(ck.decrypt(&c0) == m0);
505                    assert!(ck.decrypt(&c1) == m1);
506
507                    // Arithmetic
508                    {
509                        {
510                            // Add
511                            let c_add = &c0 + &c1;
512                            let m0_plus_m1 = ck.decrypt(&c_add);
513                            assert_eq!(
514                                m0_plus_m1,
515                                m0.wrapping_add(m1),
516                                "Expected {} but got {m0_plus_m1} for {i}+{j}",
517                                m0.wrapping_add(m1)
518                            );
519                        }
520                        {
521                            // Sub
522                            let c_sub = &c0 - &c1;
523                            let m0_sub_m1 = ck.decrypt(&c_sub);
524                            assert_eq!(
525                                m0_sub_m1,
526                                m0.wrapping_sub(m1),
527                                "Expected {} but got {m0_sub_m1} for {i}-{j}",
528                                m0.wrapping_sub(m1)
529                            );
530                        }
531
532                        {
533                            // Mul
534                            let c_m0m1 = &c0 * &c1;
535                            let m0m1 = ck.decrypt(&c_m0m1);
536                            assert_eq!(
537                                m0m1,
538                                m0.wrapping_mul(m1),
539                                "Expected {} but got {m0m1} for {i}x{j}",
540                                m0.wrapping_mul(m1)
541                            );
542                        }
543
544                        // Div & Rem
545                        {
546                            let (c_quotient, c_rem) = c0.div_rem(&c1);
547                            let m_quotient = ck.decrypt(&c_quotient);
548                            let m_remainder = ck.decrypt(&c_rem);
549                            if j != 0 {
550                                let (q, r) = i.div_rem_euclid(&j);
551                                assert_eq!(
552                                    m_quotient, q,
553                                    "Expected {} but got {m_quotient} for {i}/{j}",
554                                    q
555                                );
556                                assert_eq!(
557                                    m_remainder, r,
558                                    "Expected {} but got {m_quotient} for {i}%{j}",
559                                    r
560                                );
561                            } else {
562                                assert_eq!(
563                                    m_quotient, 255,
564                                    "Expected 255 but got {m_quotient}. Case div by zero"
565                                );
566                                assert_eq!(
567                                    m_remainder, i,
568                                    "Expected {i} but got {m_quotient}. Case div by zero"
569                                )
570                            }
571                        }
572                    }
573
574                    // Comparisons
575                    {
576                        {
577                            let c_eq = c0.eq(&c1);
578                            let is_eq = ck.decrypt(&c_eq);
579                            assert_eq!(
580                                is_eq,
581                                i == j,
582                                "Expected {} but got {is_eq} for {i}=={j}",
583                                i == j
584                            );
585                        }
586
587                        {
588                            let c_gt = c0.gt(&c1);
589                            let is_gt = ck.decrypt(&c_gt);
590                            assert_eq!(
591                                is_gt,
592                                i > j,
593                                "Expected {} but got {is_gt} for {i}>{j}",
594                                i > j
595                            );
596                        }
597
598                        {
599                            let c_lt = c0.lt(&c1);
600                            let is_lt = ck.decrypt(&c_lt);
601                            assert_eq!(
602                                is_lt,
603                                i < j,
604                                "Expected {} but got {is_lt} for {i}<{j}",
605                                i < j
606                            );
607                        }
608
609                        {
610                            let c_ge = c0.ge(&c1);
611                            let is_ge = ck.decrypt(&c_ge);
612                            assert_eq!(
613                                is_ge,
614                                i >= j,
615                                "Expected {} but got {is_ge} for {i}>={j}",
616                                i >= j
617                            );
618                        }
619
620                        {
621                            let c_le = c0.le(&c1);
622                            let is_le = ck.decrypt(&c_le);
623                            assert_eq!(
624                                is_le,
625                                i <= j,
626                                "Expected {} but got {is_le} for {i}<={j}",
627                                i <= j
628                            );
629                        }
630                    }
631                }
632            }
633        }
634    }
635}