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::{
  4    backend::Modulus,
  5    decomposer::{Decomposer, NumInfo},
  6    utils::log2,
  7};
  8
  9pub(crate) trait DoubleDecomposerCount {
 10    type Count;
 11    fn a(&self) -> Self::Count;
 12    fn b(&self) -> Self::Count;
 13}
 14
 15pub(crate) trait DoubleDecomposerParams {
 16    type Base;
 17    type Count;
 18
 19    fn decomposition_base(&self) -> Self::Base;
 20    fn decomposition_count_a(&self) -> Self::Count;
 21    fn decomposition_count_b(&self) -> Self::Count;
 22}
 23
 24pub(crate) trait SingleDecomposerParams {
 25    type Base;
 26    type Count;
 27
 28    // fn new(base: Self::Base, count: Self::Count) -> Self;
 29    fn decomposition_base(&self) -> Self::Base;
 30    fn decomposition_count(&self) -> Self::Count;
 31}
 32
 33impl DoubleDecomposerParams
 34    for (
 35        DecompostionLogBase,
 36        // Assume (Decomposition count for A, Decomposition count for B)
 37        (DecompositionCount, DecompositionCount),
 38    )
 39{
 40    type Base = DecompostionLogBase;
 41    type Count = DecompositionCount;
 42
 43    // fn new(
 44    //     base: DecompostionLogBase,
 45    //     count_a: DecompositionCount,
 46    //     count_b: DecompositionCount,
 47    // ) -> Self {
 48    //     (base, (count_a, count_b))
 49    // }
 50
 51    fn decomposition_base(&self) -> Self::Base {
 52        self.0
 53    }
 54
 55    fn decomposition_count_a(&self) -> Self::Count {
 56        self.1 .0
 57    }
 58
 59    fn decomposition_count_b(&self) -> Self::Count {
 60        self.1 .1
 61    }
 62}
 63
 64impl SingleDecomposerParams for (DecompostionLogBase, DecompositionCount) {
 65    type Base = DecompostionLogBase;
 66    type Count = DecompositionCount;
 67
 68    // fn new(base: DecompostionLogBase, count: DecompositionCount) -> Self {
 69    //     (base, count)
 70    // }
 71
 72    fn decomposition_base(&self) -> Self::Base {
 73        self.0
 74    }
 75
 76    fn decomposition_count(&self) -> Self::Count {
 77        self.1
 78    }
 79}
 80
 81#[derive(Clone, PartialEq, Debug)]
 82pub(crate) enum SecretKeyDistribution {
 83    /// Elements of secret key are sample from Gaussian distribitution with
 84    /// \sigma = 3.19 and \mu = 0.0
 85    ErrorDistribution,
 86    /// Elements of secret key are chosen from the set {1,0,-1} with hamming
 87    /// weight `floor(N/2)` where `N` is the secret dimension.
 88    TernaryDistribution,
 89}
 90
 91#[derive(Clone, PartialEq, Debug)]
 92pub(crate) enum ParameterVariant {
 93    SingleParty,
 94    MultiParty,
 95    NonInteractiveMultiParty,
 96}
 97#[derive(Clone, PartialEq)]
 98pub struct BoolParameters<El> {
 99    /// RLWE secret key distribution
100    rlwe_secret_key_dist: SecretKeyDistribution,
101    /// LWE secret key distribtuion
102    lwe_secret_key_dist: SecretKeyDistribution,
103    /// RLWE ciphertext modulus Q
104    rlwe_q: CiphertextModulus<El>,
105    /// LWE ciphertext modulus q (usually referred to as Q_{ks})
106    lwe_q: CiphertextModulus<El>,
107    /// Blind rotation modulus. It is the modulus to which we switch before
108    /// blind rotation.
109    ///
110    /// Since blind rotation decrypts LWE ciphertext in the exponent  of a ring
111    /// polynomial, which is a ring mod 2N, blind rotation modulus is
112    /// always <= 2N.
113    br_q: usize,
114    /// Ring dimension `N` for 2N^{th} cyclotomic polynomial ring
115    rlwe_n: PolynomialSize,
116    /// LWE dimension `n`
117    lwe_n: LweDimension,
118    /// LWE key switch decompositon params
119    lwe_decomposer_params: (DecompostionLogBase, DecompositionCount),
120    /// Decompostion parameters for RLWE x RGSW.
121    ///
122    /// We restrict decomposition for RLWE'(-sm) and RLWE'(m) to have same base
123    /// but can have different decomposition count. We refer to this
124    /// DoubleDecomposer / RlweDecomposer
125    ///
126    /// Decomposition count `d_a` (i.e. for SignedDecompose(RLWE_A(m)) x
127    /// RLWE'(-sm)) and `d_b` (i.e. for SignedDecompose(RLWE_B(m)) x RLWE'(m))
128    /// are always stored as `(d_a, d_b)`
129    rlrg_decomposer_params: (
130        DecompostionLogBase,
131        (DecompositionCount, DecompositionCount),
132    ),
133    /// Decomposition parameters for RLWE automorphism
134    auto_decomposer_params: (DecompostionLogBase, DecompositionCount),
135    /// Decomposition parameters for RGSW0 x RGSW1
136    ///
137    /// `0` and `1` indicate that RGSW0 and RGSW1 may not use same decomposition
138    /// parameters.
139    ///
140    /// In RGSW0 x RGSW1, decomposition parameters for RGSW1 are required.
141    /// Hence, the parameters we store are decomposition parameters of RGSW1.
142    ///
143    /// Like RLWE x RGSW decomposition parameters (1) we restrict to same base
144    /// but can have different decomposition counts `d_a` and `d_b` and (2)
145    /// decomposition count `d_a` and `d_b` are always stored as `(d_a, d_b)`
146    ///
147    /// RGSW0 x RGSW1 are optional because they only necessary to be supplied in
148    /// multi-party setting.
149    rgrg_decomposer_params: Option<(
150        DecompostionLogBase,
151        (DecompositionCount, DecompositionCount),
152    )>,
153    /// Decomposition parameters for non-interactive key switching from u_j to
154    /// s, hwere u_j is RLWE secret `u` of party `j` and `s` is the ideal RLWE
155    /// secret key.
156    ///
157    /// Decomposition parameters for non-interactive key switching are optional
158    /// and must be supplied only for non-interactive multi-party
159    non_interactive_ui_to_s_key_switch_decomposer:
160        Option<(DecompostionLogBase, DecompositionCount)>,
161    /// Group generator for Z^*_{br_q}
162    g: usize,
163    /// Window size parameter for LMKC++ blind rotation
164    w: usize,
165    /// Parameter variant
166    variant: ParameterVariant,
167}
168
169impl<El> BoolParameters<El> {
170    pub(crate) fn rlwe_secret_key_dist(&self) -> &SecretKeyDistribution {
171        &self.rlwe_secret_key_dist
172    }
173
174    pub(crate) fn lwe_secret_key_dist(&self) -> &SecretKeyDistribution {
175        &self.lwe_secret_key_dist
176    }
177
178    pub(crate) fn rlwe_q(&self) -> &CiphertextModulus<El> {
179        &self.rlwe_q
180    }
181
182    pub(crate) fn lwe_q(&self) -> &CiphertextModulus<El> {
183        &self.lwe_q
184    }
185
186    pub(crate) fn br_q(&self) -> &usize {
187        &self.br_q
188    }
189
190    pub(crate) fn rlwe_n(&self) -> &PolynomialSize {
191        &self.rlwe_n
192    }
193
194    pub(crate) fn lwe_n(&self) -> &LweDimension {
195        &self.lwe_n
196    }
197
198    pub(crate) fn g(&self) -> usize {
199        self.g
200    }
201
202    pub(crate) fn w(&self) -> usize {
203        self.w
204    }
205
206    pub(crate) fn rlwe_by_rgsw_decomposition_params(
207        &self,
208    ) -> &(
209        DecompostionLogBase,
210        (DecompositionCount, DecompositionCount),
211    ) {
212        &self.rlrg_decomposer_params
213    }
214
215    pub(crate) fn rgsw_by_rgsw_decomposition_params(
216        &self,
217    ) -> (
218        DecompostionLogBase,
219        (DecompositionCount, DecompositionCount),
220    ) {
221        self.rgrg_decomposer_params.expect(&format!(
222            "Parameter variant {:?} does not support RGSWxRGSW",
223            self.variant
224        ))
225    }
226
227    pub(crate) fn rlwe_rgsw_decomposition_base(&self) -> DecompostionLogBase {
228        self.rlrg_decomposer_params.0
229    }
230
231    pub(crate) fn rlwe_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
232        self.rlrg_decomposer_params.1
233    }
234
235    pub(crate) fn rgsw_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
236        let params = self.rgrg_decomposer_params.expect(&format!(
237            "Parameter variant {:?} does not support RGSW x RGSW",
238            self.variant
239        ));
240        params.1
241    }
242
243    pub(crate) fn auto_decomposition_param(&self) -> &(DecompostionLogBase, DecompositionCount) {
244        &self.auto_decomposer_params
245    }
246
247    pub(crate) fn auto_decomposition_base(&self) -> DecompostionLogBase {
248        self.auto_decomposer_params.decomposition_base()
249    }
250
251    pub(crate) fn auto_decomposition_count(&self) -> DecompositionCount {
252        self.auto_decomposer_params.decomposition_count()
253    }
254
255    pub(crate) fn lwe_decomposition_base(&self) -> DecompostionLogBase {
256        self.lwe_decomposer_params.decomposition_base()
257    }
258
259    pub(crate) fn lwe_decomposition_count(&self) -> DecompositionCount {
260        self.lwe_decomposer_params.decomposition_count()
261    }
262
263    pub(crate) fn non_interactive_ui_to_s_key_switch_decomposition_count(
264        &self,
265    ) -> DecompositionCount {
266        let params = self
267            .non_interactive_ui_to_s_key_switch_decomposer
268            .expect(&format!(
269                "Parameter variant {:?} does not support non-interactive",
270                self.variant
271            ));
272        params.decomposition_count()
273    }
274
275    pub(crate) fn rgsw_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
276    where
277        El: Copy,
278    {
279        let params = self.rgrg_decomposer_params.expect(&format!(
280            "Parameter variant {:?} does not support RGSW x RGSW",
281            self.variant
282        ));
283        (
284            // A
285            D::new(
286                self.rlwe_q.0,
287                params.decomposition_base().0,
288                params.decomposition_count_a().0,
289            ),
290            // B
291            D::new(
292                self.rlwe_q.0,
293                params.decomposition_base().0,
294                params.decomposition_count_b().0,
295            ),
296        )
297    }
298
299    pub(crate) fn auto_decomposer<D: Decomposer<Element = El>>(&self) -> D
300    where
301        El: Copy,
302    {
303        D::new(
304            self.rlwe_q.0,
305            self.auto_decomposer_params.decomposition_base().0,
306            self.auto_decomposer_params.decomposition_count().0,
307        )
308    }
309
310    pub(crate) fn lwe_decomposer<D: Decomposer<Element = El>>(&self) -> D
311    where
312        El: Copy,
313    {
314        D::new(
315            self.lwe_q.0,
316            self.lwe_decomposer_params.decomposition_base().0,
317            self.lwe_decomposer_params.decomposition_count().0,
318        )
319    }
320
321    pub(crate) fn rlwe_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
322    where
323        El: Copy,
324    {
325        (
326            // A
327            D::new(
328                self.rlwe_q.0,
329                self.rlrg_decomposer_params.decomposition_base().0,
330                self.rlrg_decomposer_params.decomposition_count_a().0,
331            ),
332            // B
333            D::new(
334                self.rlwe_q.0,
335                self.rlrg_decomposer_params.decomposition_base().0,
336                self.rlrg_decomposer_params.decomposition_count_b().0,
337            ),
338        )
339    }
340
341    pub(crate) fn non_interactive_ui_to_s_key_switch_decomposer<D: Decomposer<Element = El>>(
342        &self,
343    ) -> D
344    where
345        El: Copy,
346    {
347        let params = self
348            .non_interactive_ui_to_s_key_switch_decomposer
349            .expect(&format!(
350                "Parameter variant {:?} does not support non-interactive",
351                self.variant
352            ));
353        D::new(
354            self.rlwe_q.0,
355            params.decomposition_base().0,
356            params.decomposition_count().0,
357        )
358    }
359
360    /// Returns dlogs of `g` for which auto keys are required as
361    /// per the parameter. Given that autos are required for [-g, g, g^2, ...,
362    /// g^w] function returns the following [0, 1, 2, ..., w] where `w` is
363    /// the window size. Note that although g^0 = 1, we use 0 for -g.
364    pub(crate) fn auto_element_dlogs(&self) -> Vec<usize> {
365        let mut els = vec![0];
366        (1..self.w + 1).into_iter().for_each(|e| {
367            els.push(e);
368        });
369        els
370    }
371
372    pub(crate) fn variant(&self) -> &ParameterVariant {
373        &self.variant
374    }
375}
376
377#[derive(Clone, Copy, PartialEq)]
378pub struct DecompostionLogBase(pub(crate) usize);
379impl AsRef<usize> for DecompostionLogBase {
380    fn as_ref(&self) -> &usize {
381        &self.0
382    }
383}
384#[derive(Clone, Copy, PartialEq)]
385pub struct DecompositionCount(pub(crate) usize);
386impl AsRef<usize> for DecompositionCount {
387    fn as_ref(&self) -> &usize {
388        &self.0
389    }
390}
391
392#[derive(Clone, Copy, PartialEq)]
393pub(crate) struct LweDimension(pub(crate) usize);
394#[derive(Clone, Copy, PartialEq)]
395pub(crate) struct PolynomialSize(pub(crate) usize);
396#[derive(Clone, Copy, PartialEq, Debug)]
397
398/// T equals modulus when modulus is non-native. Otherwise T equals 0. bool is
399/// true when modulus is native, false otherwise.
400pub struct CiphertextModulus<T>(T, bool);
401
402impl<T: ConstZero> CiphertextModulus<T> {
403    const fn new_native() -> Self {
404        // T::zero is stored only for convenience. It has no use when modulus
405        // is native. That is, either u128,u64,u32,u16
406        Self(T::ZERO, true)
407    }
408
409    const fn new_non_native(q: T) -> Self {
410        Self(q, false)
411    }
412}
413
414impl<T> CiphertextModulus<T>
415where
416    T: PrimInt + NumInfo,
417{
418    fn _bits() -> usize {
419        T::BITS as usize
420    }
421
422    fn _native(&self) -> bool {
423        self.1
424    }
425
426    fn _half_q(&self) -> T {
427        if self._native() {
428            T::one() << (Self::_bits() - 1)
429        } else {
430            self.0 >> 1
431        }
432    }
433
434    fn _q(&self) -> Option<T> {
435        if self._native() {
436            None
437        } else {
438            Some(self.0)
439        }
440    }
441}
442
443impl<T> Modulus for CiphertextModulus<T>
444where
445    T: PrimInt + FromPrimitive + NumInfo,
446{
447    type Element = T;
448    fn is_native(&self) -> bool {
449        self._native()
450    }
451    fn largest_unsigned_value(&self) -> Self::Element {
452        if self._native() {
453            T::max_value()
454        } else {
455            self.0 - T::one()
456        }
457    }
458    fn neg_one(&self) -> Self::Element {
459        if self._native() {
460            T::max_value()
461        } else {
462            self.0 - T::one()
463        }
464    }
465    // fn signed_max(&self) -> Self::Element {}
466    // fn signed_min(&self) -> Self::Element {}
467    fn smallest_unsigned_value(&self) -> Self::Element {
468        T::zero()
469    }
470
471    fn map_element_to_i64(&self, v: &Self::Element) -> i64 {
472        assert!(*v <= self.largest_unsigned_value());
473        if *v > self._half_q() {
474            -((self.largest_unsigned_value() - *v) + T::one())
475                .to_i64()
476                .unwrap()
477        } else {
478            v.to_i64().unwrap()
479        }
480    }
481
482    fn map_element_from_f64(&self, v: f64) -> Self::Element {
483        let v = v.round();
484
485        let v_el = T::from_f64(v.abs()).unwrap();
486        assert!(v_el <= self.largest_unsigned_value());
487
488        if v < 0.0 {
489            self.largest_unsigned_value() - v_el + T::one()
490        } else {
491            v_el
492        }
493    }
494
495    fn map_element_from_i64(&self, v: i64) -> Self::Element {
496        let v_el = T::from_i64(v.abs()).unwrap();
497        assert!(v_el <= self.largest_unsigned_value());
498        if v < 0 {
499            self.largest_unsigned_value() - v_el + T::one()
500        } else {
501            v_el
502        }
503    }
504
505    fn q(&self) -> Option<Self::Element> {
506        self._q()
507    }
508
509    fn q_as_f64(&self) -> Option<f64> {
510        if self._native() {
511            Some(T::max_value().to_f64().unwrap() + 1.0)
512        } else {
513            self.0.to_f64()
514        }
515    }
516
517    fn log_q(&self) -> usize {
518        if self.is_native() {
519            Self::_bits()
520        } else {
521            log2(&self.q().unwrap())
522        }
523    }
524}
525
526pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
527    rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution,
528    lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution,
529    rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
530    lwe_q: CiphertextModulus::new_non_native(1 << 20),
531    br_q: 1 << 11,
532    rlwe_n: PolynomialSize(1 << 11),
533    lwe_n: LweDimension(500),
534    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
535    rlrg_decomposer_params: (
536        DecompostionLogBase(12),
537        (DecompositionCount(5), DecompositionCount(5)),
538    ),
539    rgrg_decomposer_params: Some((
540        DecompostionLogBase(12),
541        (DecompositionCount(5), DecompositionCount(5)),
542    )),
543    auto_decomposer_params: (DecompostionLogBase(12), DecompositionCount(5)),
544    non_interactive_ui_to_s_key_switch_decomposer: None,
545    g: 5,
546    w: 10,
547    variant: ParameterVariant::MultiParty,
548};
549
550pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
551    rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution,
552    lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution,
553    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
554    lwe_q: CiphertextModulus::new_non_native(1 << 20),
555    br_q: 1 << 11,
556    rlwe_n: PolynomialSize(1 << 11),
557    lwe_n: LweDimension(600),
558    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
559    rlrg_decomposer_params: (
560        DecompostionLogBase(11),
561        (DecompositionCount(2), DecompositionCount(1)),
562    ),
563    rgrg_decomposer_params: Some((
564        DecompostionLogBase(11),
565        (DecompositionCount(5), DecompositionCount(4)),
566    )),
567    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
568    non_interactive_ui_to_s_key_switch_decomposer: None,
569    g: 5,
570    w: 10,
571    variant: ParameterVariant::MultiParty,
572};
573
574pub(crate) const I_2P: BoolParameters<u64> = BoolParameters::<u64> {
575    rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution,
576    lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution,
577    rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
578    lwe_q: CiphertextModulus::new_non_native(1 << 15),
579    br_q: 1 << 11,
580    rlwe_n: PolynomialSize(1 << 11),
581    lwe_n: LweDimension(480),
582    lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(11)),
583    rlrg_decomposer_params: (
584        DecompostionLogBase(16),
585        (DecompositionCount(1), DecompositionCount(1)),
586    ),
587    rgrg_decomposer_params: Some((
588        DecompostionLogBase(8),
589        (DecompositionCount(6), DecompositionCount(6)),
590    )),
591    auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
592    non_interactive_ui_to_s_key_switch_decomposer: None,
593    g: 5,
594    w: 10,
595    variant: ParameterVariant::MultiParty,
596};
597
598pub(crate) const NI_2P: BoolParameters<u64> = BoolParameters::<u64> {
599    rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution,
600    lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution,
601    rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
602    lwe_q: CiphertextModulus::new_non_native(1 << 15),
603    br_q: 1 << 11,
604    rlwe_n: PolynomialSize(1 << 11),
605    lwe_n: LweDimension(480),
606    lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
607    rlrg_decomposer_params: (
608        DecompostionLogBase(16),
609        (DecompositionCount(1), DecompositionCount(1)),
610    ),
611    rgrg_decomposer_params: Some((
612        DecompostionLogBase(6),
613        (DecompositionCount(7), DecompositionCount(7)),
614    )),
615    auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
616    non_interactive_ui_to_s_key_switch_decomposer: Some((
617        DecompostionLogBase(1),
618        DecompositionCount(50),
619    )),
620    g: 5,
621    w: 10,
622    variant: ParameterVariant::NonInteractiveMultiParty,
623};
624
625pub(crate) const NI_4P: BoolParameters<u64> = BoolParameters::<u64> {
626    rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution,
627    lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution,
628    rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
629    lwe_q: CiphertextModulus::new_non_native(1 << 16),
630    br_q: 1 << 11,
631    rlwe_n: PolynomialSize(1 << 11),
632    lwe_n: LweDimension(510),
633    lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
634    rlrg_decomposer_params: (
635        DecompostionLogBase(17),
636        (DecompositionCount(1), DecompositionCount(1)),
637    ),
638    rgrg_decomposer_params: Some((
639        DecompostionLogBase(4),
640        (DecompositionCount(10), DecompositionCount(9)),
641    )),
642    auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
643    non_interactive_ui_to_s_key_switch_decomposer: Some((
644        DecompostionLogBase(1),
645        DecompositionCount(50),
646    )),
647    g: 5,
648    w: 10,
649    variant: ParameterVariant::NonInteractiveMultiParty,
650};
651
652#[cfg(test)]
653pub(crate) const SP_TEST_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
654    rlwe_secret_key_dist: SecretKeyDistribution::TernaryDistribution,
655    lwe_secret_key_dist: SecretKeyDistribution::ErrorDistribution,
656    rlwe_q: CiphertextModulus::new_non_native(268369921u64),
657    lwe_q: CiphertextModulus::new_non_native(1 << 16),
658    br_q: 1 << 9,
659    rlwe_n: PolynomialSize(1 << 9),
660    lwe_n: LweDimension(100),
661    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
662    rlrg_decomposer_params: (
663        DecompostionLogBase(7),
664        (DecompositionCount(4), DecompositionCount(4)),
665    ),
666    rgrg_decomposer_params: None,
667    auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
668    non_interactive_ui_to_s_key_switch_decomposer: None,
669    g: 5,
670    w: 5,
671    variant: ParameterVariant::SingleParty,
672};
673
674#[cfg(test)]
675mod tests {
676
677    impl BoolParameters<u64> {
678        pub(crate) fn default_rlwe_modop(&self) -> ModularOpsU64<CiphertextModulus<u64>> {
679            ModularOpsU64::new(self.rlwe_q)
680        }
681        pub(crate) fn default_rlwe_nttop(&self) -> NttBackendU64 {
682            NttBackendU64::new(&self.rlwe_q, self.rlwe_n.0)
683        }
684    }
685
686    use crate::{utils::generate_prime, ModInit, ModularOpsU64, Ntt, NttBackendU64, NttInit};
687
688    use super::{BoolParameters, CiphertextModulus};
689
690    #[test]
691    fn find_prime() {
692        let bits = 60;
693        let ring_size = 1 << 11;
694        let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
695        dbg!(prime);
696    }
697}