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