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