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