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        (DecompositionCount, DecompositionCount),
 28    )
 29{
 30    type Base = DecompostionLogBase;
 31    type Count = DecompositionCount;
 32
 33    fn new(
 34        base: DecompostionLogBase,
 35        count_a: DecompositionCount,
 36        count_b: DecompositionCount,
 37    ) -> Self {
 38        (base, (count_a, count_b))
 39    }
 40
 41    fn decomposition_base(&self) -> Self::Base {
 42        self.0
 43    }
 44
 45    fn decomposition_count_a(&self) -> Self::Count {
 46        self.1 .0
 47    }
 48
 49    fn decomposition_count_b(&self) -> Self::Count {
 50        self.1 .1
 51    }
 52}
 53
 54impl SingleDecomposerParams for (DecompostionLogBase, DecompositionCount) {
 55    type Base = DecompostionLogBase;
 56    type Count = DecompositionCount;
 57
 58    fn new(base: DecompostionLogBase, count: DecompositionCount) -> Self {
 59        (base, count)
 60    }
 61
 62    fn decomposition_base(&self) -> Self::Base {
 63        self.0
 64    }
 65
 66    fn decomposition_count(&self) -> Self::Count {
 67        self.1
 68    }
 69}
 70
 71// impl DecomposerParams for (DecompostionLogBase, (DecompositionCount)) {
 72//     type Base = DecompostionLogBase;
 73//     type Count = DecompositionCount;
 74
 75//     fn decomposition_base(&self) -> Self::Base {
 76//         self.0
 77//     }
 78
 79//     fn decomposition_count(&self) -> Self::Count {
 80//         self.1
 81//     }
 82// }
 83
 84#[derive(Clone, PartialEq, Debug)]
 85pub(crate) enum ParameterVariant {
 86    SingleParty,
 87    MultiParty,
 88    NonInteractiveMultiParty,
 89}
 90#[derive(Clone, PartialEq)]
 91pub struct BoolParameters<El> {
 92    rlwe_q: CiphertextModulus<El>,
 93    lwe_q: CiphertextModulus<El>,
 94    br_q: usize,
 95    rlwe_n: PolynomialSize,
 96    lwe_n: LweDimension,
 97    lwe_decomposer_params: (DecompostionLogBase, DecompositionCount),
 98    /// RLWE x RGSW decomposition count for (part A, part B)
 99    rlrg_decomposer_params: (
100        DecompostionLogBase,
101        (DecompositionCount, DecompositionCount),
102    ),
103    auto_decomposer_params: (DecompostionLogBase, DecompositionCount),
104    /// RGSW x RGSW decomposition count for (part A, part B)
105    rgrg_decomposer_params: Option<(
106        DecompostionLogBase,
107        (DecompositionCount, DecompositionCount),
108    )>,
109    non_interactive_ui_to_s_key_switch_decomposer:
110        Option<(DecompostionLogBase, DecompositionCount)>,
111    g: usize,
112    w: usize,
113    variant: ParameterVariant,
114}
115
116impl<El> BoolParameters<El> {
117    pub(crate) fn rlwe_q(&self) -> &CiphertextModulus<El> {
118        &self.rlwe_q
119    }
120
121    pub(crate) fn lwe_q(&self) -> &CiphertextModulus<El> {
122        &self.lwe_q
123    }
124
125    pub(crate) fn br_q(&self) -> &usize {
126        &self.br_q
127    }
128
129    pub(crate) fn rlwe_n(&self) -> &PolynomialSize {
130        &self.rlwe_n
131    }
132
133    pub(crate) fn lwe_n(&self) -> &LweDimension {
134        &self.lwe_n
135    }
136
137    pub(crate) fn g(&self) -> usize {
138        self.g
139    }
140
141    pub(crate) fn w(&self) -> usize {
142        self.w
143    }
144
145    pub(crate) fn rlwe_by_rgsw_decomposition_params(
146        &self,
147    ) -> (
148        DecompostionLogBase,
149        (DecompositionCount, DecompositionCount),
150    ) {
151        self.rlrg_decomposer_params
152    }
153
154    pub(crate) fn rgsw_by_rgsw_decomposition_params(
155        &self,
156    ) -> (
157        DecompostionLogBase,
158        (DecompositionCount, DecompositionCount),
159    ) {
160        self.rgrg_decomposer_params.expect(&format!(
161            "Parameter variant {:?} does not support RGSWxRGSW",
162            self.variant
163        ))
164    }
165
166    pub(crate) fn rlwe_rgsw_decomposition_base(&self) -> DecompostionLogBase {
167        self.rlrg_decomposer_params.0
168    }
169
170    pub(crate) fn rlwe_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
171        self.rlrg_decomposer_params.1
172    }
173
174    pub(crate) fn rgsw_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
175        let params = self.rgrg_decomposer_params.expect(&format!(
176            "Parameter variant {:?} does not support RGSW x RGSW",
177            self.variant
178        ));
179        params.1
180    }
181
182    pub(crate) fn auto_decomposition_base(&self) -> DecompostionLogBase {
183        self.auto_decomposer_params.decomposition_base()
184    }
185
186    pub(crate) fn auto_decomposition_count(&self) -> DecompositionCount {
187        self.auto_decomposer_params.decomposition_count()
188    }
189
190    pub(crate) fn lwe_decomposition_base(&self) -> DecompostionLogBase {
191        self.lwe_decomposer_params.decomposition_base()
192    }
193
194    pub(crate) fn lwe_decomposition_count(&self) -> DecompositionCount {
195        self.lwe_decomposer_params.decomposition_count()
196    }
197
198    pub(crate) fn non_interactive_ui_to_s_key_switch_decomposition_count(
199        &self,
200    ) -> DecompositionCount {
201        let params = self
202            .non_interactive_ui_to_s_key_switch_decomposer
203            .expect(&format!(
204                "Parameter variant {:?} does not support non-interactive",
205                self.variant
206            ));
207        params.decomposition_count()
208    }
209
210    pub(crate) fn rgsw_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
211    where
212        El: Copy,
213    {
214        let params = self.rgrg_decomposer_params.expect(&format!(
215            "Parameter variant {:?} does not support RGSW x RGSW",
216            self.variant
217        ));
218        (
219            // A
220            D::new(
221                self.rlwe_q.0,
222                params.decomposition_base().0,
223                params.decomposition_count_a().0,
224            ),
225            // B
226            D::new(
227                self.rlwe_q.0,
228                params.decomposition_base().0,
229                params.decomposition_count_b().0,
230            ),
231        )
232    }
233
234    pub(crate) fn auto_decomposer<D: Decomposer<Element = El>>(&self) -> D
235    where
236        El: Copy,
237    {
238        D::new(
239            self.rlwe_q.0,
240            self.auto_decomposer_params.decomposition_base().0,
241            self.auto_decomposer_params.decomposition_count().0,
242        )
243    }
244
245    pub(crate) fn lwe_decomposer<D: Decomposer<Element = El>>(&self) -> D
246    where
247        El: Copy,
248    {
249        D::new(
250            self.lwe_q.0,
251            self.lwe_decomposer_params.decomposition_base().0,
252            self.lwe_decomposer_params.decomposition_count().0,
253        )
254    }
255
256    pub(crate) fn rlwe_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
257    where
258        El: Copy,
259    {
260        (
261            // A
262            D::new(
263                self.rlwe_q.0,
264                self.rlrg_decomposer_params.decomposition_base().0,
265                self.rlrg_decomposer_params.decomposition_count_a().0,
266            ),
267            // B
268            D::new(
269                self.rlwe_q.0,
270                self.rlrg_decomposer_params.decomposition_base().0,
271                self.rlrg_decomposer_params.decomposition_count_b().0,
272            ),
273        )
274    }
275
276    pub(crate) fn non_interactive_ui_to_s_key_switch_decomposer<D: Decomposer<Element = El>>(
277        &self,
278    ) -> D
279    where
280        El: Copy,
281    {
282        let params = self
283            .non_interactive_ui_to_s_key_switch_decomposer
284            .expect(&format!(
285                "Parameter variant {:?} does not support non-interactive",
286                self.variant
287            ));
288        D::new(
289            self.rlwe_q.0,
290            params.decomposition_base().0,
291            params.decomposition_count().0,
292        )
293    }
294
295    /// Returns dlogs of `g` for which auto keys are required as
296    /// per the parameter. Given that autos are required for [-g, g, g^2, ...,
297    /// g^w] function returns the following [0, 1, 2, ..., w] where `w` is
298    /// the window size. Note that although g^0 = 1, we use 0 for -g.
299    pub(crate) fn auto_element_dlogs(&self) -> Vec<usize> {
300        let mut els = vec![0];
301        (1..self.w + 1).into_iter().for_each(|e| {
302            els.push(e);
303        });
304        els
305    }
306
307    pub(crate) fn variant(&self) -> &ParameterVariant {
308        &self.variant
309    }
310}
311
312#[derive(Clone, Copy, PartialEq)]
313pub(crate) struct DecompostionLogBase(pub(crate) usize);
314impl AsRef<usize> for DecompostionLogBase {
315    fn as_ref(&self) -> &usize {
316        &self.0
317    }
318}
319#[derive(Clone, Copy, PartialEq)]
320pub(crate) struct DecompositionCount(pub(crate) usize);
321impl AsRef<usize> for DecompositionCount {
322    fn as_ref(&self) -> &usize {
323        &self.0
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 SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
446    rlwe_q: CiphertextModulus::new_non_native(268369921u64),
447    lwe_q: CiphertextModulus::new_non_native(1 << 16),
448    br_q: 1 << 10,
449    rlwe_n: PolynomialSize(1 << 10),
450    lwe_n: LweDimension(500),
451    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
452    rlrg_decomposer_params: (
453        DecompostionLogBase(7),
454        (DecompositionCount(4), DecompositionCount(4)),
455    ),
456    rgrg_decomposer_params: None,
457    auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
458    non_interactive_ui_to_s_key_switch_decomposer: None,
459    g: 5,
460    w: 5,
461    variant: ParameterVariant::SingleParty,
462};
463
464pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
465    rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
466    lwe_q: CiphertextModulus::new_non_native(1 << 20),
467    br_q: 1 << 11,
468    rlwe_n: PolynomialSize(1 << 11),
469    lwe_n: LweDimension(500),
470    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
471    rlrg_decomposer_params: (
472        DecompostionLogBase(12),
473        (DecompositionCount(5), DecompositionCount(5)),
474    ),
475    rgrg_decomposer_params: Some((
476        DecompostionLogBase(12),
477        (DecompositionCount(5), DecompositionCount(5)),
478    )),
479    auto_decomposer_params: (DecompostionLogBase(12), DecompositionCount(5)),
480    non_interactive_ui_to_s_key_switch_decomposer: None,
481    g: 5,
482    w: 10,
483    variant: ParameterVariant::MultiParty,
484};
485
486pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
487    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
488    lwe_q: CiphertextModulus::new_non_native(1 << 20),
489    br_q: 1 << 11,
490    rlwe_n: PolynomialSize(1 << 11),
491    lwe_n: LweDimension(600),
492    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
493    rlrg_decomposer_params: (
494        DecompostionLogBase(11),
495        (DecompositionCount(2), DecompositionCount(1)),
496    ),
497    rgrg_decomposer_params: Some((
498        DecompostionLogBase(11),
499        (DecompositionCount(5), DecompositionCount(4)),
500    )),
501    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
502    non_interactive_ui_to_s_key_switch_decomposer: None,
503    g: 5,
504    w: 10,
505    variant: ParameterVariant::MultiParty,
506};
507
508pub(crate) const NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
509    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
510    lwe_q: CiphertextModulus::new_non_native(1 << 20),
511    br_q: 1 << 11,
512    rlwe_n: PolynomialSize(1 << 11),
513    lwe_n: LweDimension(600),
514    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
515    rlrg_decomposer_params: (
516        DecompostionLogBase(11),
517        (DecompositionCount(2), DecompositionCount(1)),
518    ),
519    rgrg_decomposer_params: Some((
520        DecompostionLogBase(11),
521        (DecompositionCount(5), DecompositionCount(4)),
522    )),
523    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
524    non_interactive_ui_to_s_key_switch_decomposer: Some((
525        DecompostionLogBase(1),
526        DecompositionCount(55),
527    )),
528    g: 5,
529    w: 10,
530    variant: ParameterVariant::NonInteractiveMultiParty,
531};
532#[cfg(test)]
533mod tests {
534
535    impl BoolParameters<u64> {
536        pub(crate) fn default_rlwe_modop(&self) -> ModularOpsU64<CiphertextModulus<u64>> {
537            ModularOpsU64::new(self.rlwe_q)
538        }
539        pub(crate) fn default_rlwe_nttop(&self) -> NttBackendU64 {
540            NttBackendU64::new(&self.rlwe_q, self.rlwe_n.0)
541        }
542    }
543
544    use crate::{utils::generate_prime, ModInit, ModularOpsU64, Ntt, NttBackendU64, NttInit};
545
546    use super::{BoolParameters, CiphertextModulus};
547
548    #[test]
549    fn find_prime() {
550        let bits = 60;
551        let ring_size = 1 << 11;
552        let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
553        dbg!(prime);
554    }
555}