tfhe/shortint/noise_squashing/atomic_pattern/
standard.rs1use serde::{Deserialize, Serialize};
2use tfhe_versionable::Versionize;
3
4use crate::core_crypto::prelude::{
5 generate_programmable_bootstrap_glwe_lut, keyswitch_lwe_ciphertext, CiphertextModulus,
6 LweCiphertext,
7};
8use crate::shortint::atomic_pattern::AtomicPattern;
9use crate::shortint::backward_compatibility::noise_squashing::StandardAtomicPatternNoiseSquashingKeyVersions;
10use crate::shortint::ciphertext::SquashedNoiseCiphertext;
11use crate::shortint::client_key::atomic_pattern::{
12 EncryptionAtomicPattern, StandardAtomicPatternClientKey,
13};
14use crate::shortint::encoding::compute_delta;
15use crate::shortint::engine::ShortintEngine;
16use crate::shortint::noise_squashing::{NoiseSquashingPrivateKey, Shortint128BootstrappingKey};
17use crate::shortint::server_key::{
18 apply_programmable_bootstrap_128, ServerKeyView, StandardServerKeyView,
19};
20use crate::shortint::{CarryModulus, Ciphertext, MessageModulus, PBSOrder, PaddingBit};
21
22use super::NoiseSquashingAtomicPattern;
23
24#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Versionize)]
27#[versionize(StandardAtomicPatternNoiseSquashingKeyVersions)]
28pub struct StandardAtomicPatternNoiseSquashingKey {
29 bootstrapping_key: Shortint128BootstrappingKey<u64>,
30}
31
32impl StandardAtomicPatternNoiseSquashingKey {
33 pub fn new(
34 cks: &StandardAtomicPatternClientKey,
35 noise_squashing_private_key: &NoiseSquashingPrivateKey,
36 ) -> Self {
37 let parameters = cks.parameters();
38
39 let bootstrapping_key = Shortint128BootstrappingKey::new(
40 &cks.lwe_secret_key,
41 parameters.ciphertext_modulus(),
42 parameters.lwe_noise_distribution(),
43 noise_squashing_private_key,
44 );
45
46 Self { bootstrapping_key }
47 }
48
49 pub fn from_raw_parts(bootstrapping_key: Shortint128BootstrappingKey<u64>) -> Self {
50 Self { bootstrapping_key }
51 }
52
53 pub fn into_raw_parts(self) -> Shortint128BootstrappingKey<u64> {
54 self.bootstrapping_key
55 }
56
57 pub fn bootstrapping_key(&self) -> &Shortint128BootstrappingKey<u64> {
58 &self.bootstrapping_key
59 }
60}
61
62impl NoiseSquashingAtomicPattern for StandardAtomicPatternNoiseSquashingKey {
63 fn squash_ciphertext_noise(
64 &self,
65 ciphertext: &Ciphertext,
66 src_server_key: ServerKeyView,
67 output_message_modulus: MessageModulus,
68 output_carry_modulus: CarryModulus,
69 output_ciphertext_modulus: CiphertextModulus<u128>,
70 ) -> crate::Result<SquashedNoiseCiphertext> {
71 let sks_ap = src_server_key.atomic_pattern.kind();
72 let src_server_key: StandardServerKeyView = src_server_key.try_into().map_err(|_| {
73 crate::error!(
74 "Incompatible atomic pattern between noise squashing key and server key (noise \
75squashing ap: Standard, server key ap: {:?})",
76 sks_ap
77 )
78 })?;
79
80 let lwe_before_ms = match src_server_key.atomic_pattern.pbs_order {
81 PBSOrder::KeyswitchBootstrap => {
83 let mut after_ks_ct = LweCiphertext::new(
84 0u64,
85 src_server_key
86 .atomic_pattern
87 .key_switching_key
88 .output_lwe_size(),
89 src_server_key
90 .atomic_pattern
91 .key_switching_key
92 .ciphertext_modulus(),
93 );
94
95 keyswitch_lwe_ciphertext(
96 &src_server_key.atomic_pattern.key_switching_key,
97 &ciphertext.ct,
98 &mut after_ks_ct,
99 );
100 after_ks_ct
101 }
102 PBSOrder::BootstrapKeyswitch => ciphertext.ct.clone(),
104 };
105
106 let output_lwe_size = self.bootstrapping_key.output_lwe_dimension().to_lwe_size();
107
108 let mut res = SquashedNoiseCiphertext::new_zero(
109 output_lwe_size,
110 output_ciphertext_modulus,
111 output_message_modulus,
112 output_carry_modulus,
113 );
114
115 let bsk_glwe_size = self.bootstrapping_key.glwe_size();
116 let bsk_polynomial_size = self.bootstrapping_key.polynomial_size();
117
118 let delta = compute_delta(
119 output_ciphertext_modulus,
120 output_message_modulus,
121 output_carry_modulus,
122 PaddingBit::Yes,
123 );
124
125 let output_cleartext_space = output_message_modulus.0 * output_carry_modulus.0;
126
127 let id_lut = generate_programmable_bootstrap_glwe_lut(
128 bsk_polynomial_size,
129 bsk_glwe_size,
130 output_cleartext_space.try_into().unwrap(),
131 output_ciphertext_modulus,
132 delta,
133 |x| x,
134 );
135
136 ShortintEngine::with_thread_local_mut(|engine| {
137 let buffers = engine.get_computation_buffers();
138
139 apply_programmable_bootstrap_128(
140 &self.bootstrapping_key,
141 &lwe_before_ms,
142 res.lwe_ciphertext_mut(),
143 &id_lut,
144 buffers,
145 );
146 });
147
148 res.set_degree(ciphertext.degree);
149
150 Ok(res)
151 }
152}