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 << 12,
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}