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