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 // Assume (Decomposition count for A, Decomposition count for B)
28 (DecompositionCount, DecompositionCount),
29 )
30{
31 type Base = DecompostionLogBase;
32 type Count = DecompositionCount;
33
34 fn new(
35 base: DecompostionLogBase,
36 count_a: DecompositionCount,
37 count_b: DecompositionCount,
38 ) -> Self {
39 (base, (count_a, count_b))
40 }
41
42 fn decomposition_base(&self) -> Self::Base {
43 self.0
44 }
45
46 fn decomposition_count_a(&self) -> Self::Count {
47 self.1 .0
48 }
49
50 fn decomposition_count_b(&self) -> Self::Count {
51 self.1 .1
52 }
53}
54
55impl SingleDecomposerParams for (DecompostionLogBase, DecompositionCount) {
56 type Base = DecompostionLogBase;
57 type Count = DecompositionCount;
58
59 fn new(base: DecompostionLogBase, count: DecompositionCount) -> Self {
60 (base, count)
61 }
62
63 fn decomposition_base(&self) -> Self::Base {
64 self.0
65 }
66
67 fn decomposition_count(&self) -> Self::Count {
68 self.1
69 }
70}
71
72#[derive(Clone, PartialEq, Debug)]
73pub(crate) enum ParameterVariant {
74 SingleParty,
75 MultiParty,
76 NonInteractiveMultiParty,
77}
78#[derive(Clone, PartialEq)]
79pub struct BoolParameters<El> {
80 rlwe_q: CiphertextModulus<El>,
81 lwe_q: CiphertextModulus<El>,
82 br_q: usize,
83 rlwe_n: PolynomialSize,
84 lwe_n: LweDimension,
85 lwe_decomposer_params: (DecompostionLogBase, DecompositionCount),
86 /// RLWE x RGSW decomposition count for (part A, part B)
87 rlrg_decomposer_params: (
88 DecompostionLogBase,
89 (DecompositionCount, DecompositionCount),
90 ),
91 auto_decomposer_params: (DecompostionLogBase, DecompositionCount),
92 /// RGSW x RGSW decomposition count for (part A, part B)
93 rgrg_decomposer_params: Option<(
94 DecompostionLogBase,
95 (DecompositionCount, DecompositionCount),
96 )>,
97 non_interactive_ui_to_s_key_switch_decomposer:
98 Option<(DecompostionLogBase, DecompositionCount)>,
99 g: usize,
100 w: usize,
101 variant: ParameterVariant,
102}
103
104impl<El> BoolParameters<El> {
105 pub(crate) fn rlwe_q(&self) -> &CiphertextModulus<El> {
106 &self.rlwe_q
107 }
108
109 pub(crate) fn lwe_q(&self) -> &CiphertextModulus<El> {
110 &self.lwe_q
111 }
112
113 pub(crate) fn br_q(&self) -> &usize {
114 &self.br_q
115 }
116
117 pub(crate) fn rlwe_n(&self) -> &PolynomialSize {
118 &self.rlwe_n
119 }
120
121 pub(crate) fn lwe_n(&self) -> &LweDimension {
122 &self.lwe_n
123 }
124
125 pub(crate) fn g(&self) -> usize {
126 self.g
127 }
128
129 pub(crate) fn w(&self) -> usize {
130 self.w
131 }
132
133 pub(crate) fn rlwe_by_rgsw_decomposition_params(
134 &self,
135 ) -> (
136 DecompostionLogBase,
137 (DecompositionCount, DecompositionCount),
138 ) {
139 self.rlrg_decomposer_params
140 }
141
142 pub(crate) fn rgsw_by_rgsw_decomposition_params(
143 &self,
144 ) -> (
145 DecompostionLogBase,
146 (DecompositionCount, DecompositionCount),
147 ) {
148 self.rgrg_decomposer_params.expect(&format!(
149 "Parameter variant {:?} does not support RGSWxRGSW",
150 self.variant
151 ))
152 }
153
154 pub(crate) fn rlwe_rgsw_decomposition_base(&self) -> DecompostionLogBase {
155 self.rlrg_decomposer_params.0
156 }
157
158 pub(crate) fn rlwe_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
159 self.rlrg_decomposer_params.1
160 }
161
162 pub(crate) fn rgsw_rgsw_decomposition_count(&self) -> (DecompositionCount, DecompositionCount) {
163 let params = self.rgrg_decomposer_params.expect(&format!(
164 "Parameter variant {:?} does not support RGSW x RGSW",
165 self.variant
166 ));
167 params.1
168 }
169
170 pub(crate) fn auto_decomposition_base(&self) -> DecompostionLogBase {
171 self.auto_decomposer_params.decomposition_base()
172 }
173
174 pub(crate) fn auto_decomposition_count(&self) -> DecompositionCount {
175 self.auto_decomposer_params.decomposition_count()
176 }
177
178 pub(crate) fn lwe_decomposition_base(&self) -> DecompostionLogBase {
179 self.lwe_decomposer_params.decomposition_base()
180 }
181
182 pub(crate) fn lwe_decomposition_count(&self) -> DecompositionCount {
183 self.lwe_decomposer_params.decomposition_count()
184 }
185
186 pub(crate) fn non_interactive_ui_to_s_key_switch_decomposition_count(
187 &self,
188 ) -> DecompositionCount {
189 let params = self
190 .non_interactive_ui_to_s_key_switch_decomposer
191 .expect(&format!(
192 "Parameter variant {:?} does not support non-interactive",
193 self.variant
194 ));
195 params.decomposition_count()
196 }
197
198 pub(crate) fn rgsw_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
199 where
200 El: Copy,
201 {
202 let params = self.rgrg_decomposer_params.expect(&format!(
203 "Parameter variant {:?} does not support RGSW x RGSW",
204 self.variant
205 ));
206 (
207 // A
208 D::new(
209 self.rlwe_q.0,
210 params.decomposition_base().0,
211 params.decomposition_count_a().0,
212 ),
213 // B
214 D::new(
215 self.rlwe_q.0,
216 params.decomposition_base().0,
217 params.decomposition_count_b().0,
218 ),
219 )
220 }
221
222 pub(crate) fn auto_decomposer<D: Decomposer<Element = El>>(&self) -> D
223 where
224 El: Copy,
225 {
226 D::new(
227 self.rlwe_q.0,
228 self.auto_decomposer_params.decomposition_base().0,
229 self.auto_decomposer_params.decomposition_count().0,
230 )
231 }
232
233 pub(crate) fn lwe_decomposer<D: Decomposer<Element = El>>(&self) -> D
234 where
235 El: Copy,
236 {
237 D::new(
238 self.lwe_q.0,
239 self.lwe_decomposer_params.decomposition_base().0,
240 self.lwe_decomposer_params.decomposition_count().0,
241 )
242 }
243
244 pub(crate) fn rlwe_rgsw_decomposer<D: Decomposer<Element = El>>(&self) -> (D, D)
245 where
246 El: Copy,
247 {
248 (
249 // A
250 D::new(
251 self.rlwe_q.0,
252 self.rlrg_decomposer_params.decomposition_base().0,
253 self.rlrg_decomposer_params.decomposition_count_a().0,
254 ),
255 // B
256 D::new(
257 self.rlwe_q.0,
258 self.rlrg_decomposer_params.decomposition_base().0,
259 self.rlrg_decomposer_params.decomposition_count_b().0,
260 ),
261 )
262 }
263
264 pub(crate) fn non_interactive_ui_to_s_key_switch_decomposer<D: Decomposer<Element = El>>(
265 &self,
266 ) -> D
267 where
268 El: Copy,
269 {
270 let params = self
271 .non_interactive_ui_to_s_key_switch_decomposer
272 .expect(&format!(
273 "Parameter variant {:?} does not support non-interactive",
274 self.variant
275 ));
276 D::new(
277 self.rlwe_q.0,
278 params.decomposition_base().0,
279 params.decomposition_count().0,
280 )
281 }
282
283 /// Returns dlogs of `g` for which auto keys are required as
284 /// per the parameter. Given that autos are required for [-g, g, g^2, ...,
285 /// g^w] function returns the following [0, 1, 2, ..., w] where `w` is
286 /// the window size. Note that although g^0 = 1, we use 0 for -g.
287 pub(crate) fn auto_element_dlogs(&self) -> Vec<usize> {
288 let mut els = vec![0];
289 (1..self.w + 1).into_iter().for_each(|e| {
290 els.push(e);
291 });
292 els
293 }
294
295 pub(crate) fn variant(&self) -> &ParameterVariant {
296 &self.variant
297 }
298}
299
300#[derive(Clone, Copy, PartialEq)]
301pub(crate) struct DecompostionLogBase(pub(crate) usize);
302impl AsRef<usize> for DecompostionLogBase {
303 fn as_ref(&self) -> &usize {
304 &self.0
305 }
306}
307#[derive(Clone, Copy, PartialEq)]
308pub(crate) struct DecompositionCount(pub(crate) usize);
309impl AsRef<usize> for DecompositionCount {
310 fn as_ref(&self) -> &usize {
311 &self.0
312 }
313}
314#[derive(Clone, Copy, PartialEq)]
315pub(crate) struct LweDimension(pub(crate) usize);
316#[derive(Clone, Copy, PartialEq)]
317pub(crate) struct PolynomialSize(pub(crate) usize);
318#[derive(Clone, Copy, PartialEq, Debug)]
319
320/// T equals modulus when modulus is non-native. Otherwise T equals 0. bool is
321/// true when modulus is native, false otherwise.
322pub struct CiphertextModulus<T>(T, bool);
323
324impl<T: ConstZero> CiphertextModulus<T> {
325 const fn new_native() -> Self {
326 // T::zero is stored only for convenience. It has no use when modulus
327 // is native. That is, either u128,u64,u32,u16
328 Self(T::ZERO, true)
329 }
330
331 const fn new_non_native(q: T) -> Self {
332 Self(q, false)
333 }
334}
335
336impl<T> CiphertextModulus<T>
337where
338 T: PrimInt,
339{
340 pub(crate) fn _bits() -> usize {
341 std::mem::size_of::<T>() as usize * 8
342 }
343
344 fn _native(&self) -> bool {
345 self.1
346 }
347
348 fn _half_q(&self) -> T {
349 if self._native() {
350 T::one() << (Self::_bits() - 1)
351 } else {
352 self.0 >> 1
353 }
354 }
355
356 fn _q(&self) -> Option<T> {
357 if self._native() {
358 None
359 } else {
360 Some(self.0)
361 }
362 }
363}
364
365impl<T> Modulus for CiphertextModulus<T>
366where
367 T: PrimInt + FromPrimitive,
368{
369 type Element = T;
370 fn is_native(&self) -> bool {
371 self._native()
372 }
373 fn largest_unsigned_value(&self) -> Self::Element {
374 if self._native() {
375 T::max_value()
376 } else {
377 self.0 - T::one()
378 }
379 }
380 fn neg_one(&self) -> Self::Element {
381 if self._native() {
382 T::max_value()
383 } else {
384 self.0 - T::one()
385 }
386 }
387 // fn signed_max(&self) -> Self::Element {}
388 // fn signed_min(&self) -> Self::Element {}
389 fn smallest_unsigned_value(&self) -> Self::Element {
390 T::zero()
391 }
392
393 fn map_element_to_i64(&self, v: &Self::Element) -> i64 {
394 if *v > self._half_q() {
395 -((self.largest_unsigned_value() - *v) + T::one())
396 .to_i64()
397 .unwrap()
398 } else {
399 v.to_i64().unwrap()
400 }
401 }
402
403 fn map_element_from_f64(&self, v: f64) -> Self::Element {
404 let v = v.round();
405 if v < 0.0 {
406 self.largest_unsigned_value() - T::from_f64(v.abs()).unwrap() + T::one()
407 } else {
408 T::from_f64(v.abs()).unwrap()
409 }
410 }
411
412 fn map_element_from_i64(&self, v: i64) -> Self::Element {
413 if v < 0 {
414 self.largest_unsigned_value() - T::from_i64(v.abs()).unwrap() + T::one()
415 } else {
416 T::from_i64(v.abs()).unwrap()
417 }
418 }
419
420 fn q(&self) -> Option<Self::Element> {
421 self._q()
422 }
423
424 fn q_as_f64(&self) -> Option<f64> {
425 if self._native() {
426 Some(T::max_value().to_f64().unwrap() + 1.0)
427 } else {
428 self.0.to_f64()
429 }
430 }
431}
432
433pub(crate) const MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
434 rlwe_q: CiphertextModulus::new_non_native(1152921504606830593),
435 lwe_q: CiphertextModulus::new_non_native(1 << 20),
436 br_q: 1 << 11,
437 rlwe_n: PolynomialSize(1 << 11),
438 lwe_n: LweDimension(500),
439 lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
440 rlrg_decomposer_params: (
441 DecompostionLogBase(12),
442 (DecompositionCount(5), DecompositionCount(5)),
443 ),
444 rgrg_decomposer_params: Some((
445 DecompostionLogBase(12),
446 (DecompositionCount(5), DecompositionCount(5)),
447 )),
448 auto_decomposer_params: (DecompostionLogBase(12), DecompositionCount(5)),
449 non_interactive_ui_to_s_key_switch_decomposer: None,
450 g: 5,
451 w: 10,
452 variant: ParameterVariant::MultiParty,
453};
454
455pub(crate) const SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
456 rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
457 lwe_q: CiphertextModulus::new_non_native(1 << 20),
458 br_q: 1 << 11,
459 rlwe_n: PolynomialSize(1 << 11),
460 lwe_n: LweDimension(600),
461 lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
462 rlrg_decomposer_params: (
463 DecompostionLogBase(11),
464 (DecompositionCount(2), DecompositionCount(1)),
465 ),
466 rgrg_decomposer_params: Some((
467 DecompostionLogBase(11),
468 (DecompositionCount(5), DecompositionCount(4)),
469 )),
470 auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
471 non_interactive_ui_to_s_key_switch_decomposer: None,
472 g: 5,
473 w: 10,
474 variant: ParameterVariant::MultiParty,
475};
476
477pub(crate) const I_2P: BoolParameters<u64> = BoolParameters::<u64> {
478 rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
479 lwe_q: CiphertextModulus::new_non_native(1 << 15),
480 br_q: 1 << 11,
481 rlwe_n: PolynomialSize(1 << 11),
482 lwe_n: LweDimension(500),
483 lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(11)),
484 rlrg_decomposer_params: (
485 DecompostionLogBase(16),
486 (DecompositionCount(1), DecompositionCount(1)),
487 ),
488 rgrg_decomposer_params: Some((
489 DecompostionLogBase(8),
490 (DecompositionCount(6), DecompositionCount(6)),
491 )),
492 auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
493 non_interactive_ui_to_s_key_switch_decomposer: None,
494 g: 5,
495 w: 10,
496 variant: ParameterVariant::MultiParty,
497};
498
499pub(crate) const NI_2P: BoolParameters<u64> = BoolParameters::<u64> {
500 rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
501 lwe_q: CiphertextModulus::new_non_native(1 << 15),
502 br_q: 1 << 11,
503 rlwe_n: PolynomialSize(1 << 11),
504 lwe_n: LweDimension(480),
505 lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
506 rlrg_decomposer_params: (
507 DecompostionLogBase(16),
508 (DecompositionCount(1), DecompositionCount(1)),
509 ),
510 rgrg_decomposer_params: Some((
511 DecompostionLogBase(6),
512 (DecompositionCount(7), DecompositionCount(7)),
513 )),
514 auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
515 non_interactive_ui_to_s_key_switch_decomposer: Some((
516 DecompostionLogBase(1),
517 DecompositionCount(50),
518 )),
519 g: 5,
520 w: 10,
521 variant: ParameterVariant::NonInteractiveMultiParty,
522};
523
524pub(crate) const NI_4P: BoolParameters<u64> = BoolParameters::<u64> {
525 rlwe_q: CiphertextModulus::new_non_native(18014398509404161),
526 lwe_q: CiphertextModulus::new_non_native(1 << 16),
527 br_q: 1 << 11,
528 rlwe_n: PolynomialSize(1 << 11),
529 lwe_n: LweDimension(510),
530 lwe_decomposer_params: (DecompostionLogBase(1), DecompositionCount(12)),
531 rlrg_decomposer_params: (
532 DecompostionLogBase(17),
533 (DecompositionCount(1), DecompositionCount(1)),
534 ),
535 rgrg_decomposer_params: Some((
536 DecompostionLogBase(4),
537 (DecompositionCount(10), DecompositionCount(9)),
538 )),
539 auto_decomposer_params: (DecompostionLogBase(24), DecompositionCount(1)),
540 non_interactive_ui_to_s_key_switch_decomposer: Some((
541 DecompostionLogBase(1),
542 DecompositionCount(50),
543 )),
544 g: 5,
545 w: 10,
546 variant: ParameterVariant::NonInteractiveMultiParty,
547};
548
549#[cfg(test)]
550pub(crate) const SP_TEST_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
551 rlwe_q: CiphertextModulus::new_non_native(268369921u64),
552 lwe_q: CiphertextModulus::new_non_native(1 << 16),
553 br_q: 1 << 9,
554 rlwe_n: PolynomialSize(1 << 9),
555 lwe_n: LweDimension(100),
556 lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
557 rlrg_decomposer_params: (
558 DecompostionLogBase(7),
559 (DecompositionCount(4), DecompositionCount(4)),
560 ),
561 rgrg_decomposer_params: None,
562 auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
563 non_interactive_ui_to_s_key_switch_decomposer: None,
564 g: 5,
565 w: 5,
566 variant: ParameterVariant::SingleParty,
567};
568
569#[cfg(test)]
570mod tests {
571
572 impl BoolParameters<u64> {
573 pub(crate) fn default_rlwe_modop(&self) -> ModularOpsU64<CiphertextModulus<u64>> {
574 ModularOpsU64::new(self.rlwe_q)
575 }
576 pub(crate) fn default_rlwe_nttop(&self) -> NttBackendU64 {
577 NttBackendU64::new(&self.rlwe_q, self.rlwe_n.0)
578 }
579 }
580
581 use crate::{utils::generate_prime, ModInit, ModularOpsU64, Ntt, NttBackendU64, NttInit};
582
583 use super::{BoolParameters, CiphertextModulus};
584
585 #[test]
586 fn find_prime() {
587 let bits = 60;
588 let ring_size = 1 << 11;
589 let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
590 dbg!(prime);
591 }
592}