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