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