arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/src/bool/parameters.rs
src/bool/parameters.rsRaw
  1use num_traits::{ConstZero, FromPrimitive, PrimInt};
  2
  3use crate::{backend::Modulus, decomposer::Decomposer};
  4
  5pub(super) trait DoubleDecomposerParams {
  6    type Base;
  7    type Count;
  8
  9    fn new(base: Self::Base, count_a: Self::Count, count_b: Self::Count) -> Self;
 10    fn decomposition_base(&self) -> Self::Base;
 11    fn decomposition_count_a(&self) -> Self::Count;
 12    fn decomposition_count_b(&self) -> Self::Count;
 13}
 14
 15trait SingleDecomposerParams {
 16    type Base;
 17    type Count;
 18
 19    fn new(base: Self::Base, count: Self::Count) -> Self;
 20    fn decomposition_base(&self) -> Self::Base;
 21    fn decomposition_count(&self) -> Self::Count;
 22}
 23
 24impl DoubleDecomposerParams
 25    for (
 26        DecompostionLogBase,
 27        // Assume (Decomposition count for A, Decomposition count for B)
 28        (DecompositionCount, DecompositionCount),
 29    )
 30{
 31    type Base = DecompostionLogBase;
 32    type Count = DecompositionCount;
 33
 34    fn new(
 35        base: DecompostionLogBase,
 36        count_a: DecompositionCount,
 37        count_b: DecompositionCount,
 38    ) -> Self {
 39        (base, (count_a, count_b))
 40    }
 41
 42    fn decomposition_base(&self) -> Self::Base {
 43        self.0
 44    }
 45
 46    fn decomposition_count_a(&self) -> Self::Count {
 47        self.1 .0
 48    }
 49
 50    fn decomposition_count_b(&self) -> Self::Count {
 51        self.1 .1
 52    }
 53}
 54
 55impl SingleDecomposerParams for (DecompostionLogBase, DecompositionCount) {
 56    type Base = DecompostionLogBase;
 57    type Count = DecompositionCount;
 58
 59    fn new(base: DecompostionLogBase, count: DecompositionCount) -> Self {
 60        (base, count)
 61    }
 62
 63    fn decomposition_base(&self) -> Self::Base {
 64        self.0
 65    }
 66
 67    fn decomposition_count(&self) -> Self::Count {
 68        self.1
 69    }
 70}
 71
 72// impl DecomposerParams for (DecompostionLogBase, (DecompositionCount)) {
 73//     type Base = DecompostionLogBase;
 74//     type Count = DecompositionCount;
 75
 76//     fn decomposition_base(&self) -> Self::Base {
 77//         self.0
 78//     }
 79
 80//     fn decomposition_count(&self) -> Self::Count {
 81//         self.1
 82//     }
 83// }
 84
 85#[derive(Clone, PartialEq, Debug)]
 86pub(crate) enum ParameterVariant {
 87    SingleParty,
 88    MultiParty,
 89    NonInteractiveMultiParty,
 90}
 91#[derive(Clone, PartialEq)]
 92pub struct BoolParameters<El> {
 93    rlwe_q: CiphertextModulus<El>,
 94    lwe_q: CiphertextModulus<El>,
 95    br_q: usize,
 96    rlwe_n: PolynomialSize,
 97    lwe_n: LweDimension,
 98    lwe_decomposer_params: (DecompostionLogBase, DecompositionCount),
 99    /// RLWE x RGSW decomposition count for (part A, part B)
100    rlrg_decomposer_params: (
101        DecompostionLogBase,
102        (DecompositionCount, DecompositionCount),
103    ),
104    auto_decomposer_params: (DecompostionLogBase, DecompositionCount),
105    /// RGSW x RGSW decomposition count for (part A, part B)
106    rgrg_decomposer_params: Option<(
107        DecompostionLogBase,
108        (DecompositionCount, DecompositionCount),
109    )>,
110    non_interactive_ui_to_s_key_switch_decomposer:
111        Option<(DecompostionLogBase, DecompositionCount)>,
112    g: usize,
113    w: usize,
114    variant: ParameterVariant,
115}
116
117impl<El> BoolParameters<El> {
118    pub(crate) fn rlwe_q(&self) -> &CiphertextModulus<El> {
119        &self.rlwe_q
120    }
121
122    pub(crate) fn lwe_q(&self) -> &CiphertextModulus<El> {
123        &self.lwe_q
124    }
125
126    pub(crate) fn br_q(&self) -> &usize {
127        &self.br_q
128    }
129
130    pub(crate) fn rlwe_n(&self) -> &PolynomialSize {
131        &self.rlwe_n
132    }
133
134    pub(crate) fn lwe_n(&self) -> &LweDimension {
135        &self.lwe_n
136    }
137
138    pub(crate) fn g(&self) -> usize {
139        self.g
140    }
141
142    pub(crate) fn w(&self) -> usize {
143        self.w
144    }
145
146    pub(crate) fn rlwe_by_rgsw_decomposition_params(
147        &self,
148    ) -> (
149        DecompostionLogBase,
150        (DecompositionCount, DecompositionCount),
151    ) {
152        self.rlrg_decomposer_params
153    }
154
155    pub(crate) fn rgsw_by_rgsw_decomposition_params(
156        &self,
157    ) -> (
158        DecompostionLogBase,
159        (DecompositionCount, DecompositionCount),
160    ) {
161        self.rgrg_decomposer_params.expect(&format!(
162            "Parameter variant {:?} does not support RGSWxRGSW",
163            self.variant
164        ))
165    }
166
167    pub(crate) fn rlwe_rgsw_decomposition_base(&self) -> DecompostionLogBase {
168        self.rlrg_decomposer_params.0
169    }
170
171    pub(crate) fn rlwe_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
172        self.rlrg_decomposer_params.1
173    }
174
175    pub(crate) fn rgsw_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
176        let params = self.rgrg_decomposer_params.expect(&format!(
177            "Parameter variant {:?} does not support RGSW x RGSW",
178            self.variant
179        ));
180        params.1
181    }
182
183    pub(crate) fn auto_decomposition_base(&self) -> DecompostionLogBase {
184        self.auto_decomposer_params.decomposition_base()
185    }
186
187    pub(crate) fn auto_decomposition_count(&self) -> DecompositionCount {
188        self.auto_decomposer_params.decomposition_count()
189    }
190
191    pub(crate) fn lwe_decomposition_base(&self) -> DecompostionLogBase {
192        self.lwe_decomposer_params.decomposition_base()
193    }
194
195    pub(crate) fn lwe_decomposition_count(&self) -> DecompositionCount {
196        self.lwe_decomposer_params.decomposition_count()
197    }
198
199    pub(crate) fn non_interactive_ui_to_s_key_switch_decomposition_count(
200        &self,
201    ) -> DecompositionCount {
202        let params = self
203            .non_interactive_ui_to_s_key_switch_decomposer
204            .expect(&format!(
205                "Parameter variant {:?} does not support non-interactive",
206                self.variant
207            ));
208        params.decomposition_count()
209    }
210
211    pub(crate) fn rgsw_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
212    where
213        El: Copy,
214    {
215        let params = self.rgrg_decomposer_params.expect(&format!(
216            "Parameter variant {:?} does not support RGSW x RGSW",
217            self.variant
218        ));
219        (
220            // A
221            D::new(
222                self.rlwe_q.0,
223                params.decomposition_base().0,
224                params.decomposition_count_a().0,
225            ),
226            // B
227            D::new(
228                self.rlwe_q.0,
229                params.decomposition_base().0,
230                params.decomposition_count_b().0,
231            ),
232        )
233    }
234
235    pub(crate) fn auto_decomposer<D: Decomposer<Element = El>>(&self) -> D
236    where
237        El: Copy,
238    {
239        D::new(
240            self.rlwe_q.0,
241            self.auto_decomposer_params.decomposition_base().0,
242            self.auto_decomposer_params.decomposition_count().0,
243        )
244    }
245
246    pub(crate) fn lwe_decomposer<D: Decomposer<Element = El>>(&self) -> D
247    where
248        El: Copy,
249    {
250        D::new(
251            self.lwe_q.0,
252            self.lwe_decomposer_params.decomposition_base().0,
253            self.lwe_decomposer_params.decomposition_count().0,
254        )
255    }
256
257    pub(crate) fn rlwe_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
258    where
259        El: Copy,
260    {
261        (
262            // A
263            D::new(
264                self.rlwe_q.0,
265                self.rlrg_decomposer_params.decomposition_base().0,
266                self.rlrg_decomposer_params.decomposition_count_a().0,
267            ),
268            // B
269            D::new(
270                self.rlwe_q.0,
271                self.rlrg_decomposer_params.decomposition_base().0,
272                self.rlrg_decomposer_params.decomposition_count_b().0,
273            ),
274        )
275    }
276
277    pub(crate) fn non_interactive_ui_to_s_key_switch_decomposer<D: Decomposer<Element = El>>(
278        &self,
279    ) -> D
280    where
281        El: Copy,
282    {
283        let params = self
284            .non_interactive_ui_to_s_key_switch_decomposer
285            .expect(&format!(
286                "Parameter variant {:?} does not support non-interactive",
287                self.variant
288            ));
289        D::new(
290            self.rlwe_q.0,
291            params.decomposition_base().0,
292            params.decomposition_count().0,
293        )
294    }
295
296    /// Returns dlogs of `g` for which auto keys are required as
297    /// per the parameter. Given that autos are required for [-g, g, g^2, ...,
298    /// g^w] function returns the following [0, 1, 2, ..., w] where `w` is
299    /// the window size. Note that although g^0 = 1, we use 0 for -g.
300    pub(crate) fn auto_element_dlogs(&self) -> Vec<usize> {
301        let mut els = vec![0];
302        (1..self.w + 1).into_iter().for_each(|e| {
303            els.push(e);
304        });
305        els
306    }
307
308    pub(crate) fn variant(&self) -> &ParameterVariant {
309        &self.variant
310    }
311}
312
313#[derive(Clone, Copy, PartialEq)]
314pub(crate) struct DecompostionLogBase(pub(crate) usize);
315impl AsRef<usize> for DecompostionLogBase {
316    fn as_ref(&self) -> &usize {
317        &self.0
318    }
319}
320#[derive(Clone, Copy, PartialEq)]
321pub(crate) struct DecompositionCount(pub(crate) usize);
322impl AsRef<usize> for DecompositionCount {
323    fn as_ref(&self) -> &usize {
324        &self.0
325    }
326}
327#[derive(Clone, Copy, PartialEq)]
328pub(crate) struct LweDimension(pub(crate) usize);
329#[derive(Clone, Copy, PartialEq)]
330pub(crate) struct PolynomialSize(pub(crate) usize);
331#[derive(Clone, Copy, PartialEq, Debug)]
332
333/// T equals modulus when modulus is non-native. Otherwise T equals 0. bool is
334/// true when modulus is native, false otherwise.
335pub struct CiphertextModulus<T>(T, bool);
336
337impl<T: ConstZero> CiphertextModulus<T> {
338    const fn new_native() -> Self {
339        // T::zero is stored only for convenience. It has no use when modulus
340        // is native. That is, either u128,u64,u32,u16
341        Self(T::ZERO, true)
342    }
343
344    const fn new_non_native(q: T) -> Self {
345        Self(q, false)
346    }
347}
348
349impl<T> CiphertextModulus<T>
350where
351    T: PrimInt,
352{
353    pub(crate) fn _bits() -> usize {
354        std::mem::size_of::<T>() as usize * 8
355    }
356
357    fn _native(&self) -> bool {
358        self.1
359    }
360
361    fn _half_q(&self) -> T {
362        if self._native() {
363            T::one() << (Self::_bits() - 1)
364        } else {
365            self.0 >> 1
366        }
367    }
368
369    fn _q(&self) -> Option<T> {
370        if self._native() {
371            None
372        } else {
373            Some(self.0)
374        }
375    }
376}
377
378impl<T> Modulus for CiphertextModulus<T>
379where
380    T: PrimInt + FromPrimitive,
381{
382    type Element = T;
383    fn is_native(&self) -> bool {
384        self._native()
385    }
386    fn largest_unsigned_value(&self) -> Self::Element {
387        if self._native() {
388            T::max_value()
389        } else {
390            self.0 - T::one()
391        }
392    }
393    fn neg_one(&self) -> Self::Element {
394        if self._native() {
395            T::max_value()
396        } else {
397            self.0 - T::one()
398        }
399    }
400    // fn signed_max(&self) -> Self::Element {}
401    // fn signed_min(&self) -> Self::Element {}
402    fn smallest_unsigned_value(&self) -> Self::Element {
403        T::zero()
404    }
405
406    fn map_element_to_i64(&self, v: &Self::Element) -> i64 {
407        if *v > self._half_q() {
408            -((self.largest_unsigned_value() - *v) + T::one())
409                .to_i64()
410                .unwrap()
411        } else {
412            v.to_i64().unwrap()
413        }
414    }
415
416    fn map_element_from_f64(&self, v: f64) -> Self::Element {
417        let v = v.round();
418        if v < 0.0 {
419            self.largest_unsigned_value() - T::from_f64(v.abs()).unwrap() + T::one()
420        } else {
421            T::from_f64(v.abs()).unwrap()
422        }
423    }
424
425    fn map_element_from_i64(&self, v: i64) -> Self::Element {
426        if v < 0 {
427            self.largest_unsigned_value() - T::from_i64(v.abs()).unwrap() + T::one()
428        } else {
429            T::from_i64(v.abs()).unwrap()
430        }
431    }
432
433    fn q(&self) -> Option<Self::Element> {
434        self._q()
435    }
436
437    fn q_as_f64(&self) -> Option<f64> {
438        if self._native() {
439            Some(T::max_value().to_f64().unwrap() + 1.0)
440        } else {
441            self.0.to_f64()
442        }
443    }
444}
445
446pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
447    rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
448    lwe_q: CiphertextModulus::new_non_native(1 << 20),
449    br_q: 1 << 11,
450    rlwe_n: PolynomialSize(1 << 11),
451    lwe_n: LweDimension(500),
452    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
453    rlrg_decomposer_params: (
454        DecompostionLogBase(12),
455        (DecompositionCount(5), DecompositionCount(5)),
456    ),
457    rgrg_decomposer_params: Some((
458        DecompostionLogBase(12),
459        (DecompositionCount(5), DecompositionCount(5)),
460    )),
461    auto_decomposer_params: (DecompostionLogBase(12), DecompositionCount(5)),
462    non_interactive_ui_to_s_key_switch_decomposer: None,
463    g: 5,
464    w: 10,
465    variant: ParameterVariant::MultiParty,
466};
467
468pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
469    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
470    lwe_q: CiphertextModulus::new_non_native(1 << 20),
471    br_q: 1 << 11,
472    rlwe_n: PolynomialSize(1 << 11),
473    lwe_n: LweDimension(600),
474    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
475    rlrg_decomposer_params: (
476        DecompostionLogBase(11),
477        (DecompositionCount(2), DecompositionCount(1)),
478    ),
479    rgrg_decomposer_params: Some((
480        DecompostionLogBase(11),
481        (DecompositionCount(5), DecompositionCount(4)),
482    )),
483    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
484    non_interactive_ui_to_s_key_switch_decomposer: None,
485    g: 5,
486    w: 10,
487    variant: ParameterVariant::MultiParty,
488};
489
490pub(crate) const I_2P: BoolParameters<u64> = BoolParameters::<u64> {
491    rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
492    lwe_q: CiphertextModulus::new_non_native(1 << 15),
493    br_q: 1 << 11,
494    rlwe_n: PolynomialSize(1 << 11),
495    lwe_n: LweDimension(500),
496    lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(11)),
497    rlrg_decomposer_params: (
498        DecompostionLogBase(16),
499        (DecompositionCount(1), DecompositionCount(1)),
500    ),
501    rgrg_decomposer_params: Some((
502        DecompostionLogBase(8),
503        (DecompositionCount(6), DecompositionCount(6)),
504    )),
505    auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
506    non_interactive_ui_to_s_key_switch_decomposer: None,
507    g: 5,
508    w: 10,
509    variant: ParameterVariant::MultiParty,
510};
511
512pub(crate) const NI_2P: BoolParameters<u64> = BoolParameters::<u64> {
513    rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
514    lwe_q: CiphertextModulus::new_non_native(1 << 15),
515    br_q: 1 << 11,
516    rlwe_n: PolynomialSize(1 << 11),
517    lwe_n: LweDimension(480),
518    lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
519    rlrg_decomposer_params: (
520        DecompostionLogBase(16),
521        (DecompositionCount(1), DecompositionCount(1)),
522    ),
523    rgrg_decomposer_params: Some((
524        DecompostionLogBase(6),
525        (DecompositionCount(7), DecompositionCount(7)),
526    )),
527    auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
528    non_interactive_ui_to_s_key_switch_decomposer: Some((
529        DecompostionLogBase(1),
530        DecompositionCount(50),
531    )),
532    g: 5,
533    w: 10,
534    variant: ParameterVariant::NonInteractiveMultiParty,
535};
536
537pub(crate) const NI_4P: BoolParameters<u64> = BoolParameters::<u64> {
538    rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
539    lwe_q: CiphertextModulus::new_non_native(1 << 16),
540    br_q: 1 << 11,
541    rlwe_n: PolynomialSize(1 << 11),
542    lwe_n: LweDimension(510),
543    lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
544    rlrg_decomposer_params: (
545        DecompostionLogBase(17),
546        (DecompositionCount(1), DecompositionCount(1)),
547    ),
548    rgrg_decomposer_params: Some((
549        DecompostionLogBase(4),
550        (DecompositionCount(10), DecompositionCount(9)),
551    )),
552    auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
553    non_interactive_ui_to_s_key_switch_decomposer: Some((
554        DecompostionLogBase(1),
555        DecompositionCount(50),
556    )),
557    g: 5,
558    w: 10,
559    variant: ParameterVariant::NonInteractiveMultiParty,
560};
561
562#[cfg(test)]
563pub(crate) const SP_TEST_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
564    rlwe_q: CiphertextModulus::new_non_native(268369921u64),
565    lwe_q: CiphertextModulus::new_non_native(1 << 16),
566    br_q: 1 << 9,
567    rlwe_n: PolynomialSize(1 << 9),
568    lwe_n: LweDimension(100),
569    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
570    rlrg_decomposer_params: (
571        DecompostionLogBase(7),
572        (DecompositionCount(4), DecompositionCount(4)),
573    ),
574    rgrg_decomposer_params: None,
575    auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
576    non_interactive_ui_to_s_key_switch_decomposer: None,
577    g: 5,
578    w: 5,
579    variant: ParameterVariant::SingleParty,
580};
581
582#[cfg(test)]
583mod tests {
584
585    impl BoolParameters<u64> {
586        pub(crate) fn default_rlwe_modop(&self) -> ModularOpsU64<CiphertextModulus<u64>> {
587            ModularOpsU64::new(self.rlwe_q)
588        }
589        pub(crate) fn default_rlwe_nttop(&self) -> NttBackendU64 {
590            NttBackendU64::new(&self.rlwe_q, self.rlwe_n.0)
591        }
592    }
593
594    use crate::{utils::generate_prime, ModInit, ModularOpsU64, Ntt, NttBackendU64, NttInit};
595
596    use super::{BoolParameters, CiphertextModulus};
597
598    #[test]
599    fn find_prime() {
600        let bits = 60;
601        let ring_size = 1 << 11;
602        let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
603        dbg!(prime);
604    }
605}