1use std::ops::RangeInclusive;
2
3use serde::{Deserialize, Serialize};
4use tfhe_versionable::Versionize;
5
6use crate::conformance::EnumSet;
7use crate::core_crypto::prelude::{CastInto, UnsignedInteger};
8use crate::named::Named;
9use crate::shortint::backward_compatibility::parameters::{
10 DedicatedCompactPublicKeyParametersVersions, MetaParametersVersions,
11};
12use crate::shortint::parameters::{
13 Backend, CompactPublicKeyEncryptionParameters, CompressionParameters,
14 MetaNoiseSquashingParameters, ShortintKeySwitchingParameters, SupportedCompactPkeZkScheme,
15};
16use crate::shortint::{
17 AtomicPatternParameters, CarryModulus, EncryptionKeyChoice, MessageModulus,
18 MultiBitPBSParameters, PBSParameters,
19};
20
21#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Versionize)]
22#[versionize(DedicatedCompactPublicKeyParametersVersions)]
23pub struct DedicatedCompactPublicKeyParameters {
24 pub pke_params: CompactPublicKeyEncryptionParameters,
26 pub ksk_params: ShortintKeySwitchingParameters,
29 pub re_randomization_parameters: Option<ShortintKeySwitchingParameters>,
32}
33
34#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Versionize)]
35#[versionize(MetaParametersVersions)]
36pub struct MetaParameters {
37 pub backend: Backend,
38 pub compute_parameters: AtomicPatternParameters,
40 pub dedicated_compact_public_key_parameters: Option<DedicatedCompactPublicKeyParameters>,
43 pub compression_parameters: Option<CompressionParameters>,
45 pub noise_squashing_parameters: Option<MetaNoiseSquashingParameters>,
47}
48
49impl Named for MetaParameters {
50 const NAME: &str = "shortint::MetaParameters";
51}
52
53impl MetaParameters {
54 pub fn noise_distribution_kind(&self) -> NoiseDistributionKind {
55 match self.compute_parameters {
56 AtomicPatternParameters::Standard(pbsparameters) => match pbsparameters {
57 PBSParameters::PBS(pbs) => pbs.lwe_noise_distribution.kind(),
58 PBSParameters::MultiBitPBS(multi_bit_pbs) => {
59 multi_bit_pbs.lwe_noise_distribution.kind()
60 }
61 },
62 AtomicPatternParameters::KeySwitch32(key_switch32_pbsparameters) => {
63 key_switch32_pbsparameters.lwe_noise_distribution.kind()
64 }
65 }
66 }
67
68 pub fn failure_probability(&self) -> Log2PFail {
69 Log2PFail(self.compute_parameters.log2_p_fail())
70 }
71}
72
73#[derive(Debug, Copy, Clone, PartialEq, Eq)]
75pub enum NoiseDistributionKind {
76 Gaussian = 0,
77 TUniform = 1,
78}
79
80impl CastInto<usize> for NoiseDistributionKind {
81 fn cast_into(self) -> usize {
82 self as usize
83 }
84}
85
86#[derive(Debug, Copy, Clone)]
91pub struct NoiseDistributionChoice(EnumSet<NoiseDistributionKind>);
92
93impl NoiseDistributionChoice {
94 pub fn new() -> Self {
98 Self(EnumSet::new())
99 }
100
101 pub fn allow_all() -> Self {
103 Self::new()
104 .allow(NoiseDistributionKind::Gaussian)
105 .allow(NoiseDistributionKind::TUniform)
106 }
107
108 pub fn allow(mut self, kind: NoiseDistributionKind) -> Self {
112 self.0.insert(kind);
113 self
114 }
115
116 pub fn deny(mut self, kind: NoiseDistributionKind) -> Self {
120 self.0.remove(kind);
121 self
122 }
123
124 fn is_compatible(&self, params: &MetaParameters) -> bool {
125 self.0.contains(params.noise_distribution_kind())
126 }
127}
128
129impl Default for NoiseDistributionChoice {
130 fn default() -> Self {
131 Self::new()
132 }
133}
134
135impl<T: UnsignedInteger> super::DynamicDistribution<T> {
136 fn kind(&self) -> NoiseDistributionKind {
137 match self {
138 Self::Gaussian(_) => NoiseDistributionKind::Gaussian,
139 Self::TUniform(_) => NoiseDistributionKind::TUniform,
140 }
141 }
142}
143
144#[derive(Debug)]
146pub enum Constraint<T> {
147 LessThan(T),
149 LessThanOrEqual(T),
151 GreaterThan(T),
153 GreaterThanOrEqual(T),
155 Equal(T),
157 Within(RangeInclusive<T>),
159}
160
161impl<T> Constraint<T>
162where
163 T: PartialOrd + PartialEq,
164{
165 fn is_compatible(&self, value: &T) -> bool {
166 match self {
167 Self::LessThan(v) => value < v,
168 Self::LessThanOrEqual(v) => value <= v,
169 Self::GreaterThan(v) => value > v,
170 Self::GreaterThanOrEqual(v) => value >= v,
171 Self::Equal(v) => value == v,
172 Self::Within(range) => range.contains(value),
173 }
174 }
175}
176
177#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
181pub struct Log2PFail(pub f64);
182
183#[derive(Debug, Copy, Clone, PartialEq, Eq)]
184pub struct Version(pub u8, pub u8);
185
186impl Version {
187 pub fn major(self) -> u8 {
188 self.0
189 }
190 pub fn minor(self) -> u8 {
191 self.1
192 }
193
194 pub fn current() -> Self {
195 let major = env!("CARGO_PKG_VERSION_MAJOR")
196 .parse::<u8>()
197 .expect("Failed to parse major version");
198 let minor = env!("CARGO_PKG_VERSION_MINOR")
199 .parse::<u8>()
200 .expect("Failed to parse minor version");
201 Self(major, minor)
202 }
203}
204
205pub struct MultiBitPBSChoice {
207 pub(crate) grouping_factor: Constraint<usize>,
208}
209
210impl MultiBitPBSChoice {
211 pub fn new(grouping_factor: Constraint<usize>) -> Self {
213 Self { grouping_factor }
214 }
215
216 fn is_compatible(&self, params: &MultiBitPBSParameters) -> bool {
217 self.grouping_factor
218 .is_compatible(¶ms.grouping_factor.0)
219 }
220}
221
222pub struct AtomicPatternChoice {
230 classical: bool,
231 multibit: Option<MultiBitPBSChoice>,
232 keyswitch32: bool,
233}
234
235impl AtomicPatternChoice {
236 pub fn new() -> Self {
238 Self {
239 classical: false,
240 multibit: None,
241 keyswitch32: false,
242 }
243 }
244
245 pub fn classic_pbs(mut self, allowed: bool) -> Self {
247 self.classical = allowed;
248 self
249 }
250
251 pub fn multi_bit_pbs(mut self, constraints: Option<MultiBitPBSChoice>) -> Self {
253 self.multibit = constraints;
254 self
255 }
256
257 pub fn keyswitch32(mut self, allowed: bool) -> Self {
259 self.keyswitch32 = allowed;
260 self
261 }
262
263 fn is_compatible(&self, ap: &AtomicPatternParameters) -> bool {
264 match ap {
265 AtomicPatternParameters::Standard(pbs_params) => match pbs_params {
266 PBSParameters::PBS(_) => self.classical,
267 PBSParameters::MultiBitPBS(multi_bit_params) => self
268 .multibit
269 .as_ref()
270 .is_some_and(|constraints| constraints.is_compatible(multi_bit_params)),
271 },
272 AtomicPatternParameters::KeySwitch32(_) => self.keyswitch32,
273 }
274 }
275
276 fn default_for_device(device: Backend) -> Self {
277 match device {
278 Backend::Cpu => Self::default_cpu(),
279 Backend::CudaGpu => Self::default_gpu(),
280 }
281 }
282
283 fn default_cpu() -> Self {
284 Self {
285 classical: true,
286 multibit: None,
287 keyswitch32: false,
288 }
289 }
290
291 fn default_gpu() -> Self {
292 Self {
293 classical: false,
294 multibit: Some(MultiBitPBSChoice::new(Constraint::LessThanOrEqual(4))),
295 keyswitch32: false,
296 }
297 }
298}
299
300impl Default for AtomicPatternChoice {
301 fn default() -> Self {
302 Self::new()
303 }
304}
305
306#[derive(Copy, Clone, Debug)]
308pub struct CompactPkeZkSchemeChoice(EnumSet<SupportedCompactPkeZkScheme>);
309
310impl CastInto<usize> for SupportedCompactPkeZkScheme {
311 fn cast_into(self) -> usize {
312 self as usize
313 }
314}
315
316impl CompactPkeZkSchemeChoice {
317 pub fn new() -> Self {
318 Self(EnumSet::new())
319 }
320
321 pub fn not_used() -> Self {
322 Self::new().allow(SupportedCompactPkeZkScheme::ZkNotSupported)
323 }
324
325 pub fn allow_all() -> Self {
326 Self::new()
327 .allow(SupportedCompactPkeZkScheme::V1)
328 .allow(SupportedCompactPkeZkScheme::V2)
329 }
330
331 pub fn allow(mut self, v: SupportedCompactPkeZkScheme) -> Self {
332 self.0.insert(v);
333 self
334 }
335
336 pub fn deny(mut self, v: SupportedCompactPkeZkScheme) -> Self {
337 self.0.remove(v);
338 self
339 }
340
341 fn is_compatible(&self, v: SupportedCompactPkeZkScheme) -> bool {
342 if self.0.contains(SupportedCompactPkeZkScheme::ZkNotSupported) {
343 true
344 } else {
345 self.0.contains(v)
346 }
347 }
348}
349
350impl Default for CompactPkeZkSchemeChoice {
351 fn default() -> Self {
352 Self::new()
353 }
354}
355
356#[derive(Copy, Clone, Debug)]
357pub struct PkeKeyswitchTargetChoice(EnumSet<EncryptionKeyChoice>);
358
359impl CastInto<usize> for EncryptionKeyChoice {
360 fn cast_into(self) -> usize {
361 self as usize
362 }
363}
364
365impl PkeKeyswitchTargetChoice {
366 pub fn new() -> Self {
367 Self(EnumSet::new())
368 }
369
370 pub fn allow_all() -> Self {
371 Self::new()
372 .allow(EncryptionKeyChoice::Big)
373 .allow(EncryptionKeyChoice::Small)
374 }
375
376 pub fn allow(mut self, v: EncryptionKeyChoice) -> Self {
377 self.0.insert(v);
378 self
379 }
380
381 pub fn deny(mut self, v: EncryptionKeyChoice) -> Self {
382 self.0.remove(v);
383 self
384 }
385
386 fn is_compatible(&self, v: EncryptionKeyChoice) -> bool {
387 self.0.contains(v)
388 }
389}
390
391impl Default for PkeKeyswitchTargetChoice {
392 fn default() -> Self {
393 Self::new()
394 }
395}
396
397pub struct DedicatedPublicKeyChoice {
399 zk_scheme: CompactPkeZkSchemeChoice,
400 pke_keyswitch_target: PkeKeyswitchTargetChoice,
401 require_re_rand: bool,
402}
403
404impl DedicatedPublicKeyChoice {
405 pub fn new() -> Self {
406 Self::default()
407 }
408
409 pub fn with_zk_scheme(mut self, zk_scheme: CompactPkeZkSchemeChoice) -> Self {
411 self.zk_scheme = zk_scheme;
412 self
413 }
414
415 pub fn with_pke_switch(mut self, pke_switch: PkeKeyswitchTargetChoice) -> Self {
417 self.pke_keyswitch_target = pke_switch;
418 self
419 }
420
421 pub fn with_re_randomization(mut self, required: bool) -> Self {
422 self.require_re_rand = required;
423 self
424 }
425
426 fn is_compatible(&self, dedicated_pk_params: &DedicatedCompactPublicKeyParameters) -> bool {
427 if self.require_re_rand && dedicated_pk_params.re_randomization_parameters.is_none() {
428 return false;
429 }
430
431 self.pke_keyswitch_target
432 .is_compatible(dedicated_pk_params.ksk_params.destination_key)
433 && self
434 .zk_scheme
435 .is_compatible(dedicated_pk_params.pke_params.zk_scheme)
436 }
437}
438
439impl Default for DedicatedPublicKeyChoice {
440 fn default() -> Self {
441 Self {
442 zk_scheme: CompactPkeZkSchemeChoice::allow_all(),
443 pke_keyswitch_target: PkeKeyswitchTargetChoice::allow_all(),
444 require_re_rand: false,
445 }
446 }
447}
448
449#[derive(Copy, Clone, Debug)]
451pub enum NoiseSquashingChoice {
452 Yes { with_compression: bool },
454 No,
456}
457
458impl NoiseSquashingChoice {
459 fn is_compatible(self, params: Option<&MetaNoiseSquashingParameters>) -> bool {
460 match (self, params) {
461 (Self::Yes { .. }, None) => false,
462 (Self::Yes { with_compression }, Some(params)) => {
463 params.compression_parameters.is_some() == with_compression
464 }
465 (Self::No, None | Some(_)) => true,
466 }
467 }
468}
469
470const KNOWN_PARAMETERS: [(Version, &[(&MetaParameters, &str)]); 2] = [
471 (Version(1, 4), &super::v1_4::VEC_ALL_META_PARAMETERS),
472 (Version(1, 5), &super::v1_5::VEC_ALL_META_PARAMETERS),
473];
474
475pub struct MetaParametersFinder {
482 msg_modulus: MessageModulus,
483 carry_modulus: CarryModulus,
484 failure_probability: Constraint<Log2PFail>,
485 version: Version,
486 backend: Backend,
487 atomic_pattern_choice: AtomicPatternChoice,
488 noise_distribution: NoiseDistributionChoice,
489 dedicated_compact_public_key_choice: Option<DedicatedPublicKeyChoice>,
490 use_compression: bool,
491 noise_squashing_choice: NoiseSquashingChoice,
492 use_re_randomization: bool,
493}
494
495impl MetaParametersFinder {
496 pub fn new(pfail: Constraint<Log2PFail>, backend: Backend) -> Self {
503 Self {
504 msg_modulus: MessageModulus(4),
505 carry_modulus: CarryModulus(4),
506 failure_probability: pfail,
507 version: Version::current(),
508 backend,
509 atomic_pattern_choice: AtomicPatternChoice::default_for_device(backend),
510 dedicated_compact_public_key_choice: None,
511 use_compression: false,
512 noise_squashing_choice: NoiseSquashingChoice::No,
513 noise_distribution: NoiseDistributionChoice::allow_all(),
514 use_re_randomization: false,
515 }
516 }
517
518 pub fn with_version(mut self, version: Version) -> Self {
519 self.version = version;
520 self
521 }
522
523 pub const fn with_noise_distribution(
525 mut self,
526 noise_distribution: NoiseDistributionChoice,
527 ) -> Self {
528 self.noise_distribution = noise_distribution;
529 self
530 }
531
532 pub const fn with_atomic_pattern(mut self, atomic_pattern_choice: AtomicPatternChoice) -> Self {
534 self.atomic_pattern_choice = atomic_pattern_choice;
535 self
536 }
537
538 pub const fn with_dedicated_compact_public_key(
540 mut self,
541 choice: Option<DedicatedPublicKeyChoice>,
542 ) -> Self {
543 self.dedicated_compact_public_key_choice = choice;
544 self
545 }
546
547 pub const fn with_compression(mut self, enabled: bool) -> Self {
549 self.use_compression = enabled;
550 self
551 }
552
553 pub const fn with_noise_squashing(mut self, choice: NoiseSquashingChoice) -> Self {
555 self.noise_squashing_choice = choice;
556 self
557 }
558
559 pub const fn with_block_modulus(mut self, message_modulus: MessageModulus) -> Self {
563 self.msg_modulus = message_modulus;
564 self.carry_modulus = CarryModulus(message_modulus.0);
565 self
566 }
567
568 pub const fn with_re_randomization(mut self, enabled: bool) -> Self {
569 self.use_re_randomization = enabled;
570 self
571 }
572
573 fn is_compatible(&self, parameters: &MetaParameters) -> bool {
579 if self.backend != parameters.backend {
580 return false;
581 }
582
583 if self.msg_modulus != parameters.compute_parameters.message_modulus()
584 || self.carry_modulus != parameters.compute_parameters.carry_modulus()
585 {
586 return false;
587 }
588
589 if !self
590 .failure_probability
591 .is_compatible(¶meters.failure_probability())
592 {
593 return false;
594 }
595
596 if !self.noise_distribution.is_compatible(parameters) {
597 return false;
598 }
599
600 if !self
601 .atomic_pattern_choice
602 .is_compatible(¶meters.compute_parameters)
603 {
604 return false;
605 }
606
607 match (
608 self.dedicated_compact_public_key_choice.as_ref(),
609 ¶meters.dedicated_compact_public_key_parameters,
610 ) {
611 (None, None | Some(_)) => {}
612 (Some(_), None) => return false,
613 (Some(choice), Some(params)) => {
614 if !choice.is_compatible(params) {
615 return false;
616 }
617 }
618 }
619
620 if self.use_compression && parameters.compression_parameters.is_none() {
621 return false;
622 }
623
624 if !self
625 .noise_squashing_choice
626 .is_compatible(parameters.noise_squashing_parameters.as_ref())
627 {
628 return false;
629 }
630
631 true
632 }
633
634 fn fit(&self, parameters: &MetaParameters) -> Option<MetaParameters> {
639 if self.is_compatible(parameters) {
640 let mut result = *parameters;
641 if self.dedicated_compact_public_key_choice.is_none() {
642 result.dedicated_compact_public_key_parameters = None;
643 }
644
645 if let Some(dedicated_pke_choice) = self.dedicated_compact_public_key_choice.as_ref() {
646 if !dedicated_pke_choice.require_re_rand {
647 if let Some(pke_params) =
648 result.dedicated_compact_public_key_parameters.as_mut()
649 {
650 pke_params.re_randomization_parameters = None;
651 }
652 }
653 } else {
654 result.dedicated_compact_public_key_parameters = None;
655 }
656
657 if !self.use_compression {
658 result.compression_parameters = None;
659 }
660
661 match self.noise_squashing_choice {
662 NoiseSquashingChoice::Yes { with_compression } => {
663 if !with_compression {
664 if let Some(ns_params) = result.noise_squashing_parameters.as_mut() {
665 ns_params.compression_parameters.take();
666 }
667 }
668 }
669 NoiseSquashingChoice::No => result.noise_squashing_parameters = None,
670 }
671
672 Some(result)
673 } else {
674 None
675 }
676 }
677
678 pub fn find_all(&self) -> Vec<MetaParameters> {
680 self.named_find_all().into_iter().map(|(p, _)| p).collect()
681 }
682
683 pub fn find(&self) -> Option<MetaParameters> {
695 let mut candidates = self.named_find_all();
696
697 if candidates.is_empty() {
698 return None;
699 }
700
701 if candidates.len() == 1 {
702 return candidates.pop().map(|(param, _)| param);
703 }
704
705 fn filter_candidates(
706 candidates: Vec<(MetaParameters, &str)>,
707 filter: impl Fn(&(MetaParameters, &str)) -> bool,
708 ) -> Vec<(MetaParameters, &str)> {
709 let filtered = candidates
710 .iter()
711 .copied()
712 .filter(filter)
713 .collect::<Vec<_>>();
714
715 if filtered.is_empty() {
721 candidates
722 } else {
723 filtered
724 }
725 }
726
727 let candidates = filter_candidates(candidates, |(params, _)| {
728 if let Some(pke_params) = params.dedicated_compact_public_key_parameters {
729 return pke_params.pke_params.zk_scheme == SupportedCompactPkeZkScheme::V2;
730 }
731 true
732 });
733
734 let mut candidates = match self.backend {
735 Backend::Cpu => filter_candidates(candidates, |(params, _)| {
737 matches!(
738 params.compute_parameters,
739 AtomicPatternParameters::Standard(PBSParameters::PBS(_))
740 ) && params.noise_distribution_kind() == NoiseDistributionKind::TUniform
741 }),
742 Backend::CudaGpu => filter_candidates(candidates, |(params, _)| {
744 matches!(
745 params.compute_parameters,
746 AtomicPatternParameters::Standard(PBSParameters::MultiBitPBS(_))
747 ) && params.noise_distribution_kind() == NoiseDistributionKind::TUniform
748 }),
749 };
750
751 candidates.sort_by(|(a, _), (b, _)| {
757 a.failure_probability()
758 .partial_cmp(&b.failure_probability())
759 .unwrap()
760 });
761
762 candidates.last().copied().map(|(params, _)| params)
763 }
764
765 fn named_find_all(&self) -> Vec<(MetaParameters, &'static str)> {
770 let mut candidates = Vec::new();
771
772 for (version, parameter_list) in KNOWN_PARAMETERS.iter() {
773 if *version != self.version {
774 continue; }
776
777 for (parameters, name) in *parameter_list {
778 if let Some(params) = self.fit(parameters) {
779 candidates.push((params, *name));
780 }
781 }
782 }
783
784 candidates
785 }
786}
787
788#[cfg(test)]
789mod tests {
790 use super::*;
791
792 #[test]
793 fn test_parameter_finder() {
794 {
795 let finder = MetaParametersFinder::new(
796 Constraint::LessThanOrEqual(Log2PFail(-64.0)),
797 Backend::Cpu,
798 )
799 .with_compression(true)
800 .with_noise_squashing(NoiseSquashingChoice::Yes {
801 with_compression: true,
802 })
803 .with_version(Version(1, 4));
804
805 let params = finder.find();
806
807 let mut expected =
808 super::super::v1_4::meta::cpu::V1_4_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_BIG_ZKV1_TUNIFORM_2M128;
809 expected.dedicated_compact_public_key_parameters = None;
810 assert_eq!(params, Some(expected));
811
812 let finder = MetaParametersFinder::new(
813 Constraint::LessThanOrEqual(Log2PFail(-64.0)),
814 Backend::Cpu,
815 )
816 .with_version(Version(1, 4))
817 .with_atomic_pattern(AtomicPatternChoice::new().classic_pbs(true))
818 .with_compression(true)
819 .with_noise_squashing(NoiseSquashingChoice::Yes {
820 with_compression: true,
821 });
822 let params = finder.find();
823 assert_eq!(params.unwrap(), expected);
824 }
825
826 {
827 let finder = MetaParametersFinder::new(
829 Constraint::LessThanOrEqual(Log2PFail(-40.0)),
830 Backend::Cpu,
831 )
832 .with_version(Version(1, 4))
833 .with_atomic_pattern(
834 AtomicPatternChoice::new()
835 .multi_bit_pbs(Some(MultiBitPBSChoice::new(Constraint::LessThanOrEqual(4)))),
836 );
837 let params = finder.find();
838 assert_eq!(
839 params,
840 Some(super::super::v1_4::meta::cpu::V1_4_META_PARAM_CPU_2_2_MULTI_BIT_GROUP_4_KS_PBS_GAUSSIAN_2M40)
841 );
842
843 let finder = MetaParametersFinder::new(
845 Constraint::LessThanOrEqual(Log2PFail(-40.0)),
846 Backend::CudaGpu,
847 )
848 .with_version(Version(1, 4))
849 .with_atomic_pattern(
850 AtomicPatternChoice::new()
851 .multi_bit_pbs(Some(MultiBitPBSChoice::new(Constraint::LessThanOrEqual(4)))),
852 );
853 let params = finder.find();
854
855 let mut expected =
856 super::super::v1_4::meta::gpu::V1_4_META_PARAM_GPU_2_2_MULTI_BIT_GROUP_3_KS_PBS_TUNIFORM_2M40;
857 expected.dedicated_compact_public_key_parameters = None;
858
859 assert_eq!(params, Some(expected));
860 }
861 }
862 #[test]
863 fn test_parameter_finder_dedicated_pke() {
864 {
865 let finder = MetaParametersFinder::new(
867 Constraint::LessThanOrEqual(Log2PFail(-64.0)),
868 Backend::Cpu,
869 )
870 .with_version(Version(1, 4))
871 .with_dedicated_compact_public_key(Some(
872 DedicatedPublicKeyChoice::new()
873 .with_zk_scheme(CompactPkeZkSchemeChoice::not_used())
874 .with_pke_switch(
875 PkeKeyswitchTargetChoice::new().allow(EncryptionKeyChoice::Big),
876 ),
877 ));
878
879 let params = finder.find();
880
881 let mut expected =
882 super::super::v1_4::meta::cpu::V1_4_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_BIG_ZKV2_TUNIFORM_2M128;
883 expected.compression_parameters = None;
884 expected.noise_squashing_parameters = None;
885 expected
886 .dedicated_compact_public_key_parameters
887 .as_mut()
888 .unwrap()
889 .re_randomization_parameters = None;
890 assert_eq!(params, Some(expected));
891
892 let finder = MetaParametersFinder::new(
894 Constraint::LessThanOrEqual(Log2PFail(-64.0)),
895 Backend::Cpu,
896 )
897 .with_version(Version(1, 4))
898 .with_dedicated_compact_public_key(Some(
899 DedicatedPublicKeyChoice::new()
900 .with_zk_scheme(CompactPkeZkSchemeChoice::not_used())
901 .with_pke_switch(
902 PkeKeyswitchTargetChoice::new().allow(EncryptionKeyChoice::Small),
903 )
904 .with_re_randomization(true),
905 ));
906
907 let params = finder.find();
908
909 let mut expected =
910 super::super::v1_4::meta::cpu::V1_4_META_PARAM_CPU_2_2_KS_PBS_PKE_TO_SMALL_ZKV2_TUNIFORM_2M128;
911 expected.compression_parameters = None;
912 expected.noise_squashing_parameters = None;
913 assert_eq!(params, Some(expected));
914 }
915 }
916
917 #[test]
918 fn test_parameter_finder_ks32() {
919 let finder =
920 MetaParametersFinder::new(Constraint::LessThanOrEqual(Log2PFail(-64.0)), Backend::Cpu)
921 .with_version(Version(1, 4))
922 .with_atomic_pattern(AtomicPatternChoice::new().keyswitch32(true));
923
924 let params = finder.find();
925
926 let expected =
927 super::super::v1_4::meta::cpu::V1_4_META_PARAM_CPU_2_2_KS32_PBS_TUNIFORM_2M128;
928
929 assert_eq!(params, Some(expected));
930 }
931}