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
  5trait 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    /// RGSW x RGSW decomposition count for (part A, part B)
104    rgrg_decomposer_params: Option<(
105        DecompostionLogBase,
106        (DecompositionCount, DecompositionCount),
107    )>,
108    auto_decomposer_params: (DecompostionLogBase, DecompositionCount),
109    g: usize,
110    w: usize,
111    variant: ParameterVariant,
112}
113
114impl<El> BoolParameters<El> {
115    pub(crate) fn rlwe_q(&self) -> &CiphertextModulus<El> {
116        &self.rlwe_q
117    }
118
119    pub(crate) fn lwe_q(&self) -> &CiphertextModulus<El> {
120        &self.lwe_q
121    }
122
123    pub(crate) fn br_q(&self) -> &usize {
124        &self.br_q
125    }
126
127    pub(crate) fn rlwe_n(&self) -> &PolynomialSize {
128        &self.rlwe_n
129    }
130
131    pub(crate) fn lwe_n(&self) -> &LweDimension {
132        &self.lwe_n
133    }
134
135    pub(crate) fn g(&self) -> usize {
136        self.g
137    }
138
139    pub(crate) fn w(&self) -> usize {
140        self.w
141    }
142
143    pub(crate) fn rlwe_rgsw_decomposition_base(&self) -> DecompostionLogBase {
144        self.rlrg_decomposer_params.0
145    }
146
147    pub(crate) fn rlwe_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
148        self.rlrg_decomposer_params.1
149    }
150
151    pub(crate) fn rgsw_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
152        let params = self.rgrg_decomposer_params.expect(&format!(
153            "Parameter variant {:?} does not support RGSW x RGSW",
154            self.variant
155        ));
156        params.1
157    }
158
159    pub(crate) fn auto_decomposition_base(&self) -> DecompostionLogBase {
160        self.auto_decomposer_params.decomposition_base()
161    }
162
163    pub(crate) fn auto_decomposition_count(&self) -> DecompositionCount {
164        self.auto_decomposer_params.decomposition_count()
165    }
166
167    pub(crate) fn lwe_decomposition_base(&self) -> DecompostionLogBase {
168        self.lwe_decomposer_params.decomposition_base()
169    }
170
171    pub(crate) fn lwe_decomposition_count(&self) -> DecompositionCount {
172        self.lwe_decomposer_params.decomposition_count()
173    }
174
175    pub(crate) fn rgsw_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
176    where
177        El: Copy,
178    {
179        let params = self.rgrg_decomposer_params.expect(&format!(
180            "Parameter variant {:?} does not support RGSW x RGSW",
181            self.variant
182        ));
183        (
184            // A
185            D::new(
186                self.rlwe_q.0,
187                params.decomposition_base().0,
188                params.decomposition_count_a().0,
189            ),
190            // B
191            D::new(
192                self.rlwe_q.0,
193                params.decomposition_base().0,
194                params.decomposition_count_b().0,
195            ),
196        )
197    }
198
199    pub(crate) fn auto_decomposer<D: Decomposer<Element = El>>(&self) -> D
200    where
201        El: Copy,
202    {
203        D::new(
204            self.rlwe_q.0,
205            self.auto_decomposer_params.decomposition_base().0,
206            self.auto_decomposer_params.decomposition_count().0,
207        )
208    }
209
210    pub(crate) fn lwe_decomposer<D: Decomposer<Element = El>>(&self) -> D
211    where
212        El: Copy,
213    {
214        D::new(
215            self.lwe_q.0,
216            self.lwe_decomposer_params.decomposition_base().0,
217            self.lwe_decomposer_params.decomposition_count().0,
218        )
219    }
220
221    pub(crate) fn rlwe_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
222    where
223        El: Copy,
224    {
225        (
226            // A
227            D::new(
228                self.rlwe_q.0,
229                self.rlrg_decomposer_params.decomposition_base().0,
230                self.rlrg_decomposer_params.decomposition_count_a().0,
231            ),
232            // B
233            D::new(
234                self.rlwe_q.0,
235                self.rlrg_decomposer_params.decomposition_base().0,
236                self.rlrg_decomposer_params.decomposition_count_b().0,
237            ),
238        )
239    }
240
241    /// Returns dlogs of `g` for which auto keys are required as
242    /// per the parameter. Given that autos are required for [-g, g, g^2, ...,
243    /// g^w] function returns the following [0, 1, 2, ..., w] where `w` is
244    /// the window size. Note that although g^0 = 1, we use 0 for -g.
245    pub(crate) fn auto_element_dlogs(&self) -> Vec<usize> {
246        let mut els = vec![0];
247        (1..self.w + 1).into_iter().for_each(|e| {
248            els.push(e);
249        });
250        els
251    }
252}
253
254#[derive(Clone, Copy, PartialEq)]
255pub(crate) struct DecompostionLogBase(pub(crate) usize);
256impl AsRef<usize> for DecompostionLogBase {
257    fn as_ref(&self) -> &usize {
258        &self.0
259    }
260}
261#[derive(Clone, Copy, PartialEq)]
262pub(crate) struct DecompositionCount(pub(crate) usize);
263impl AsRef<usize> for DecompositionCount {
264    fn as_ref(&self) -> &usize {
265        &self.0
266    }
267}
268#[derive(Clone, Copy, PartialEq)]
269pub(crate) struct LweDimension(pub(crate) usize);
270#[derive(Clone, Copy, PartialEq)]
271pub(crate) struct PolynomialSize(pub(crate) usize);
272#[derive(Clone, Copy, PartialEq, Debug)]
273
274/// T equals modulus when modulus is non-native. Otherwise T equals 0. bool is
275/// true when modulus is native, false otherwise.
276pub struct CiphertextModulus<T>(T, bool);
277
278impl<T: ConstZero> CiphertextModulus<T> {
279    const fn new_native() -> Self {
280        // T::zero is stored only for convenience. It has no use when modulus
281        // is native. That is, either u128,u64,u32,u16
282        Self(T::ZERO, true)
283    }
284
285    const fn new_non_native(q: T) -> Self {
286        Self(q, false)
287    }
288}
289
290impl<T> CiphertextModulus<T>
291where
292    T: PrimInt,
293{
294    pub(crate) fn _bits() -> usize {
295        std::mem::size_of::<T>() as usize * 8
296    }
297
298    fn _native(&self) -> bool {
299        self.1
300    }
301
302    fn _half_q(&self) -> T {
303        if self._native() {
304            T::one() << (Self::_bits() - 1)
305        } else {
306            self.0 >> 1
307        }
308    }
309
310    fn _q(&self) -> Option<T> {
311        if self._native() {
312            None
313        } else {
314            Some(self.0)
315        }
316    }
317}
318
319impl<T> Modulus for CiphertextModulus<T>
320where
321    T: PrimInt + FromPrimitive,
322{
323    type Element = T;
324    fn is_native(&self) -> bool {
325        self._native()
326    }
327    fn largest_unsigned_value(&self) -> Self::Element {
328        if self._native() {
329            T::max_value()
330        } else {
331            self.0 - T::one()
332        }
333    }
334    fn neg_one(&self) -> Self::Element {
335        if self._native() {
336            T::max_value()
337        } else {
338            self.0 - T::one()
339        }
340    }
341    // fn signed_max(&self) -> Self::Element {}
342    // fn signed_min(&self) -> Self::Element {}
343    fn smallest_unsigned_value(&self) -> Self::Element {
344        T::zero()
345    }
346
347    fn map_element_to_i64(&self, v: &Self::Element) -> i64 {
348        if *v > self._half_q() {
349            -((self.largest_unsigned_value() - *v) + T::one())
350                .to_i64()
351                .unwrap()
352        } else {
353            v.to_i64().unwrap()
354        }
355    }
356
357    fn map_element_from_f64(&self, v: f64) -> Self::Element {
358        let v = v.round();
359        if v < 0.0 {
360            self.largest_unsigned_value() - T::from_f64(v.abs()).unwrap() + T::one()
361        } else {
362            T::from_f64(v.abs()).unwrap()
363        }
364    }
365
366    fn map_element_from_i64(&self, v: i64) -> Self::Element {
367        if v < 0 {
368            self.largest_unsigned_value() - T::from_i64(v.abs()).unwrap() + T::one()
369        } else {
370            T::from_i64(v.abs()).unwrap()
371        }
372    }
373
374    fn q(&self) -> Option<Self::Element> {
375        self._q()
376    }
377
378    fn q_as_f64(&self) -> Option<f64> {
379        if self._native() {
380            Some(T::max_value().to_f64().unwrap() + 1.0)
381        } else {
382            self.0.to_f64()
383        }
384    }
385}
386
387pub(crate) const SP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
388    rlwe_q: CiphertextModulus::new_non_native(268369921u64),
389    lwe_q: CiphertextModulus::new_non_native(1 << 16),
390    br_q: 1 << 10,
391    rlwe_n: PolynomialSize(1 << 10),
392    lwe_n: LweDimension(500),
393    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
394    rlrg_decomposer_params: (
395        DecompostionLogBase(7),
396        (DecompositionCount(4), DecompositionCount(4)),
397    ),
398    rgrg_decomposer_params: None,
399    auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
400    g: 5,
401    w: 5,
402    variant: ParameterVariant::SingleParty,
403};
404
405pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
406    rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
407    lwe_q: CiphertextModulus::new_non_native(1 << 20),
408    br_q: 1 << 11,
409    rlwe_n: PolynomialSize(1 << 11),
410    lwe_n: LweDimension(500),
411    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
412    rlrg_decomposer_params: (
413        DecompostionLogBase(12),
414        (DecompositionCount(5), DecompositionCount(5)),
415    ),
416    rgrg_decomposer_params: Some((
417        DecompostionLogBase(12),
418        (DecompositionCount(5), DecompositionCount(5)),
419    )),
420    auto_decomposer_params: (DecompostionLogBase(12), DecompositionCount(5)),
421    g: 5,
422    w: 10,
423    variant: ParameterVariant::MultiParty,
424};
425
426pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
427    rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
428    lwe_q: CiphertextModulus::new_non_native(1 << 20),
429    br_q: 1 << 11,
430    rlwe_n: PolynomialSize(1 << 11),
431    lwe_n: LweDimension(600),
432    lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
433    rlrg_decomposer_params: (
434        DecompostionLogBase(11),
435        (DecompositionCount(2), DecompositionCount(1)),
436    ),
437    rgrg_decomposer_params: Some((
438        DecompostionLogBase(11),
439        (DecompositionCount(5), DecompositionCount(4)),
440    )),
441    auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
442    g: 5,
443    w: 10,
444    variant: ParameterVariant::MultiParty,
445};
446
447#[cfg(test)]
448mod tests {
449    use crate::utils::generate_prime;
450
451    #[test]
452    fn find_prime() {
453        let bits = 55;
454        let ring_size = 1 << 15;
455        let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
456        dbg!(prime);
457    }
458}