Skip to main content

tfhe/shortint/noise_squashing/atomic_pattern/
standard.rs

1use 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/// The definition of the noise squashing key elements used in the
25/// [`Standard`](crate::shortint::atomic_pattern::AtomicPatternKind::Standard) atomic pattern
26#[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            // Under the big key, first need to keyswitch
82            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            // Under the small key, no need to keyswitch
103            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}