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 pub(crate) fn variant(&self) -> &ParameterVariant {
308 &self.variant
309 }
310}
311
312#[derive(Clone, Copy, PartialEq)]
313pub(crate) struct DecompostionLogBase(pub(crate) usize);
314impl AsRef<usize> for DecompostionLogBase {
315 fn as_ref(&self) -> &usize {
316 &self.0
317 }
318}
319#[derive(Clone, Copy, PartialEq)]
320pub(crate) struct DecompositionCount(pub(crate) usize);
321impl AsRef<usize> for DecompositionCount {
322 fn as_ref(&self) -> &usize {
323 &self.0
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 OPTIMISED_SMALL_MP_BOOL_PARAMS: 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(24),
498 (DecompositionCount(1), DecompositionCount(1)),
499 ),
500 rgrg_decomposer_params: Some((
501 DecompostionLogBase(12),
502 (DecompositionCount(3), DecompositionCount(3)),
503 )),
504 auto_decomposer_params: (DecompostionLogBase(20), 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 NON_INTERACTIVE_SMALL_MP_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
512 rlwe_q: CiphertextModulus::new_non_native(36028797018820609),
513 lwe_q: CiphertextModulus::new_non_native(1 << 20),
514 br_q: 1 << 11,
515 rlwe_n: PolynomialSize(1 << 11),
516 lwe_n: LweDimension(600),
517 lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(5)),
518 rlrg_decomposer_params: (
519 DecompostionLogBase(11),
520 (DecompositionCount(2), DecompositionCount(1)),
521 ),
522 rgrg_decomposer_params: Some((
523 DecompostionLogBase(11),
524 (DecompositionCount(5), DecompositionCount(4)),
525 )),
526 auto_decomposer_params: (DecompostionLogBase(11), DecompositionCount(2)),
527 non_interactive_ui_to_s_key_switch_decomposer: Some((
528 DecompostionLogBase(1),
529 DecompositionCount(55),
530 )),
531 g: 5,
532 w: 10,
533 variant: ParameterVariant::NonInteractiveMultiParty,
534};
535
536#[cfg(test)]
537pub(crate) const SP_TEST_BOOL_PARAMS: BoolParameters<u64> = BoolParameters::<u64> {
538 rlwe_q: CiphertextModulus::new_non_native(268369921u64),
539 lwe_q: CiphertextModulus::new_non_native(1 << 16),
540 br_q: 1 << 9,
541 rlwe_n: PolynomialSize(1 << 9),
542 lwe_n: LweDimension(100),
543 lwe_decomposer_params: (DecompostionLogBase(4), DecompositionCount(4)),
544 rlrg_decomposer_params: (
545 DecompostionLogBase(7),
546 (DecompositionCount(4), DecompositionCount(4)),
547 ),
548 rgrg_decomposer_params: None,
549 auto_decomposer_params: (DecompostionLogBase(7), DecompositionCount(4)),
550 non_interactive_ui_to_s_key_switch_decomposer: None,
551 g: 5,
552 w: 5,
553 variant: ParameterVariant::SingleParty,
554};
555
556#[cfg(test)]
557mod tests {
558
559 impl BoolParameters<u64> {
560 pub(crate) fn default_rlwe_modop(&self) -> ModularOpsU64<CiphertextModulus<u64>> {
561 ModularOpsU64::new(self.rlwe_q)
562 }
563 pub(crate) fn default_rlwe_nttop(&self) -> NttBackendU64 {
564 NttBackendU64::new(&self.rlwe_q, self.rlwe_n.0)
565 }
566 }
567
568 use crate::{utils::generate_prime, ModInit, ModularOpsU64, Ntt, NttBackendU64, NttInit};
569
570 use super::{BoolParameters, CiphertextModulus};
571
572 #[test]
573 fn find_prime() {
574 let bits = 60;
575 let ring_size = 1 << 11;
576 let prime = generate_prime(bits, ring_size * 2, 1 << bits).unwrap();
577 dbg!(prime);
578 }
579}