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
308#[derive(Clone, Copy, PartialEq)]
309pub(crate) struct DecompostionLogBase(pub(crate) usize);
310impl AsRef<usize> for DecompostionLogBase {
311    fn as_ref(&self) -> &usize {
312        &self.0
313    }
314}
315#[derive(Clone, Copy, PartialEq)]
316pub(crate) struct DecompositionCount(pub(crate) usize);
317impl AsRef<usize> for DecompositionCount {
318    fn as_ref(&self) -> &usize {
319        &self.0
320    }
321}
322#[derive(Clone, Copy, PartialEq)]
323pub(crate) struct LweDimension(pub(crate) usize);
324#[derive(Clone, Copy, PartialEq)]
325pub(crate) struct PolynomialSize(pub(crate) usize);
326#[derive(Clone, Copy, PartialEq, Debug)]
327
328/// T equals modulus when modulus is non-native. Otherwise T equals 0. bool is
329/// true when modulus is native, false otherwise.
330pub struct CiphertextModulus<T>(T, bool);
331
332impl<T: ConstZero> CiphertextModulus<T> {
333    const fn new_native() -> Self {
334        // T::zero is stored only for convenience. It has no use when modulus
335        // is native. That is, either u128,u64,u32,u16
336        Self(T::ZERO, true)
337    }
338
339    const fn new_non_native(q: T) -> Self {
340        Self(q, false)
341    }
342}
343
344impl<T> CiphertextModulus<T>
345where
346    T: PrimInt,
347{
348    pub(crate) fn _bits() -> usize {
349        std::mem::size_of::<T>() as usize * 8
350    }
351
352    fn _native(&self) -> bool {
353        self.1
354    }
355
356    fn _half_q(&self) -> T {
357        if self._native() {
358            T::one() << (Self::_bits() - 1)
359        } else {
360            self.0 >> 1
361        }
362    }
363
364    fn _q(&self) -> Option<T> {
365        if self._native() {
366            None
367        } else {
368            Some(self.0)
369        }
370    }
371}
372
373impl<T> Modulus for CiphertextModulus<T>
374where
375    T: PrimInt + FromPrimitive,
376{
377    type Element = T;
378    fn is_native(&self) -> bool {
379        self._native()
380    }
381    fn largest_unsigned_value(&self) -> Self::Element {
382        if self._native() {
383            T::max_value()
384        } else {
385            self.0 - T::one()
386        }
387    }
388    fn neg_one(&self) -> Self::Element {
389        if self._native() {
390            T::max_value()
391        } else {
392            self.0 - T::one()
393        }
394    }
395    // fn signed_max(&self) -> Self::Element {}
396    // fn signed_min(&self) -> Self::Element {}
397    fn smallest_unsigned_value(&self) -> Self::Element {
398        T::zero()
399    }
400
401    fn map_element_to_i64(&self, v: &Self::Element) -> i64 {
402        if *v > self._half_q() {
403            -((self.largest_unsigned_value() - *v) + T::one())
404                .to_i64()
405                .unwrap()
406        } else {
407            v.to_i64().unwrap()
408        }
409    }
410
411    fn map_element_from_f64(&self, v: f64) -> Self::Element {
412        let v = v.round();
413        if v < 0.0 {
414            self.largest_unsigned_value() - T::from_f64(v.abs()).unwrap() + T::one()
415        } else {
416            T::from_f64(v.abs()).unwrap()
417        }
418    }
419
420    fn map_element_from_i64(&self, v: i64) -> Self::Element {
421        if v < 0 {
422            self.largest_unsigned_value() - T::from_i64(v.abs()).unwrap() + T::one()
423        } else {
424            T::from_i64(v.abs()).unwrap()
425        }
426    }
427
428    fn q(&self) -> Option<Self::Element> {
429        self._q()
430    }
431
432    fn q_as_f64(&self) -> Option<f64> {
433        if self._native() {
434            Some(T::max_value().to_f64().unwrap() + 1.0)
435        } else {
436            self.0.to_f64()
437        }
438    }
439}
440
441pub(crate) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
442    rlwe_q: CiphertextModulus::new_non_native(268369921u64),
443    lwe_q: CiphertextModulus::new_non_native(1 << 16),
444    br_q: 1 << 10,
445    rlwe_n: PolynomialSize(1 << 10),
446    lwe_n: LweDimension(500),
447    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
448    rlrg_decomposer_params: (
449        DecompostionLogBase(7),
450        (DecompositionCount(4), DecompositionCount(4)),
451    ),
452    rgrg_decomposer_params: None,
453    auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
454    non_interactive_ui_to_s_key_switch_decomposer: None,
455    g: 5,
456    w: 5,
457    variant: ParameterVariant::SingleParty,
458};
459
460pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
461    rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
462    lwe_q: CiphertextModulus::new_non_native(1 << 20),
463    br_q: 1 << 11,
464    rlwe_n: PolynomialSize(1 << 11),
465    lwe_n: LweDimension(500),
466    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
467    rlrg_decomposer_params: (
468        DecompostionLogBase(12),
469        (DecompositionCount(5), DecompositionCount(5)),
470    ),
471    rgrg_decomposer_params: Some((
472        DecompostionLogBase(12),
473        (DecompositionCount(5), DecompositionCount(5)),
474    )),
475    auto_decomposer_params: (DecompostionLogBase(12), DecompositionCount(5)),
476    non_interactive_ui_to_s_key_switch_decomposer: None,
477    g: 5,
478    w: 10,
479    variant: ParameterVariant::MultiParty,
480};
481
482pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
483    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
484    lwe_q: CiphertextModulus::new_non_native(1 << 20),
485    br_q: 1 << 11,
486    rlwe_n: PolynomialSize(1 << 11),
487    lwe_n: LweDimension(600),
488    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
489    rlrg_decomposer_params: (
490        DecompostionLogBase(11),
491        (DecompositionCount(2), DecompositionCount(1)),
492    ),
493    rgrg_decomposer_params: Some((
494        DecompostionLogBase(11),
495        (DecompositionCount(5), DecompositionCount(4)),
496    )),
497    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
498    non_interactive_ui_to_s_key_switch_decomposer: None,
499    g: 5,
500    w: 10,
501    variant: ParameterVariant::MultiParty,
502};
503
504pub(crate) const NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
505    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
506    lwe_q: CiphertextModulus::new_non_native(1 << 20),
507    br_q: 1 << 11,
508    rlwe_n: PolynomialSize(1 << 11),
509    lwe_n: LweDimension(10),
510    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
511    rlrg_decomposer_params: (
512        DecompostionLogBase(11),
513        (DecompositionCount(2), DecompositionCount(1)),
514    ),
515    rgrg_decomposer_params: Some((
516        DecompostionLogBase(11),
517        (DecompositionCount(5), DecompositionCount(4)),
518    )),
519    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
520    non_interactive_ui_to_s_key_switch_decomposer: Some((
521        DecompostionLogBase(1),
522        DecompositionCount(55),
523    )),
524    g: 5,
525    w: 10,
526    variant: ParameterVariant::NonInteractiveMultiParty,
527};
528#[cfg(test)]
529mod tests {
530    use crate::utils::generate_prime;
531
532    #[test]
533    fn find_prime() {
534        let bits = 60;
535        let ring_size = 1 << 11;
536        let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
537        dbg!(prime);
538    }
539}