Skip to main content

tfhe/high_level_api/booleans/
compressed.rs

1use crate::backward_compatibility::booleans::{
2    CompressedFheBoolVersions, InnerCompressedFheBoolVersions,
3};
4use crate::conformance::ParameterSetConformant;
5use crate::high_level_api::global_state;
6use crate::high_level_api::keys::InternalServerKey;
7use crate::high_level_api::re_randomization::ReRandomizationMetadata;
8use crate::high_level_api::traits::Tagged;
9use crate::integer::BooleanBlock;
10use crate::named::Named;
11use crate::prelude::FheTryEncrypt;
12use crate::shortint::ciphertext::{
13    CompressedModulusSwitchedCiphertext, CompressedModulusSwitchedCiphertextConformanceParams,
14    Degree,
15};
16use crate::shortint::{AtomicPatternParameters, CompressedCiphertext};
17use crate::{ClientKey, FheBool, ServerKey, Tag};
18use serde::{Deserialize, Serialize};
19use tfhe_versionable::Versionize;
20
21#[derive(Clone, Serialize, Deserialize, Versionize)]
22#[versionize(InnerCompressedFheBoolVersions)]
23pub enum InnerCompressedFheBool {
24    Seeded(CompressedCiphertext),
25    ModulusSwitched(CompressedModulusSwitchedCiphertext),
26}
27
28/// Compressed [FheBool]
29///
30/// Meant to save in storage space / transfer.
31///
32/// - A Compressed type must be decompressed before it can be used.
33/// - It is not possible to compress an existing [FheBool], compression can only be achieved at
34///   encryption time
35///
36/// # Example
37///
38/// ```rust
39/// use tfhe::prelude::*;
40/// use tfhe::{generate_keys, CompressedFheBool, ConfigBuilder};
41///
42/// let (client_key, _) = generate_keys(ConfigBuilder::default());
43/// let compressed = CompressedFheBool::encrypt(true, &client_key);
44///
45/// let decompressed = compressed.decompress();
46/// let decrypted: bool = decompressed.decrypt(&client_key);
47/// assert!(decrypted);
48/// ```
49#[derive(Clone, Serialize, Deserialize, Versionize)]
50#[versionize(CompressedFheBoolVersions)]
51pub struct CompressedFheBool {
52    pub(in crate::high_level_api) inner: InnerCompressedFheBool,
53    pub(crate) tag: Tag,
54}
55
56impl Tagged for CompressedFheBool {
57    fn tag(&self) -> &Tag {
58        &self.tag
59    }
60
61    fn tag_mut(&mut self) -> &mut Tag {
62        &mut self.tag
63    }
64}
65
66impl CompressedFheBool {
67    pub(in crate::high_level_api) fn new(ciphertext: CompressedCiphertext, tag: Tag) -> Self {
68        Self {
69            inner: InnerCompressedFheBool::Seeded(ciphertext),
70            tag,
71        }
72    }
73
74    /// Decompresses itself into a [FheBool]
75    ///
76    /// See [CompressedFheBool] example.
77    pub fn decompress(&self) -> FheBool {
78        let ciphertext = BooleanBlock::new_unchecked(match &self.inner {
79            InnerCompressedFheBool::Seeded(seeded) => seeded.decompress(),
80            InnerCompressedFheBool::ModulusSwitched(modulus_switched) => {
81                global_state::with_internal_keys(|keys| match keys {
82                    InternalServerKey::Cpu(cpu_key) => {
83                        cpu_key.pbs_key().key.decompress(modulus_switched)
84                    }
85                    #[cfg(feature = "gpu")]
86                    InternalServerKey::Cuda(_) => {
87                        panic!("decompress() on FheBool is not supported on GPU, use a CompressedCiphertextList instead");
88                    }
89                    #[cfg(feature = "hpu")]
90                    InternalServerKey::Hpu(_) => {
91                        panic!("decompress() on FheBool is not supported on HPU devices");
92                    }
93                })
94            }
95        });
96        let mut ciphertext = FheBool::new(
97            ciphertext,
98            self.tag.clone(),
99            ReRandomizationMetadata::default(),
100        );
101        ciphertext.ciphertext.move_to_device_of_server_key_if_set();
102        ciphertext
103    }
104}
105
106impl FheTryEncrypt<bool, ClientKey> for CompressedFheBool {
107    type Error = crate::Error;
108
109    /// Creates a compressed encryption of a boolean value
110    fn try_encrypt(value: bool, key: &ClientKey) -> Result<Self, Self::Error> {
111        let mut ciphertext = key.key.key.key.encrypt_compressed(u64::from(value));
112        ciphertext.degree = Degree::new(1);
113        Ok(Self::new(ciphertext, key.tag.clone()))
114    }
115}
116
117#[derive(Copy, Clone)]
118pub struct CompressedFheBoolConformanceParams(
119    pub(crate) CompressedModulusSwitchedCiphertextConformanceParams,
120);
121
122impl<P: Into<AtomicPatternParameters>> From<P> for CompressedFheBoolConformanceParams {
123    fn from(params: P) -> Self {
124        let mut params = params.into().to_compressed_modswitched_conformance_param();
125        params.degree = crate::shortint::ciphertext::Degree::new(1);
126        Self(params)
127    }
128}
129
130impl From<&ServerKey> for CompressedFheBoolConformanceParams {
131    fn from(sk: &ServerKey) -> Self {
132        let mut parameter_set = Self(
133            sk.key
134                .pbs_key()
135                .key
136                .compressed_modswitched_conformance_params(),
137        );
138        parameter_set.0.degree = crate::shortint::ciphertext::Degree::new(1);
139        parameter_set
140    }
141}
142
143impl ParameterSetConformant for CompressedFheBool {
144    type ParameterSet = CompressedFheBoolConformanceParams;
145
146    fn is_conformant(&self, params: &CompressedFheBoolConformanceParams) -> bool {
147        match &self.inner {
148            InnerCompressedFheBool::Seeded(seeded) => seeded.is_conformant(&params.0.into()),
149            InnerCompressedFheBool::ModulusSwitched(ct) => ct.is_conformant(&params.0),
150        }
151    }
152}
153
154impl Named for CompressedFheBool {
155    const NAME: &'static str = "high_level_api::CompressedFheBool";
156}
157
158impl FheBool {
159    pub fn compress(&self) -> CompressedFheBool {
160        global_state::with_internal_keys(|keys| match keys {
161            InternalServerKey::Cpu(cpu_key) => {
162                let inner = InnerCompressedFheBool::ModulusSwitched(
163                    cpu_key
164                        .pbs_key()
165                        .key
166                        .switch_modulus_and_compress(&self.ciphertext.on_cpu().0),
167                );
168                CompressedFheBool {
169                    inner,
170                    tag: cpu_key.tag.clone(),
171                }
172            }
173            #[cfg(feature = "gpu")]
174            InternalServerKey::Cuda(_) => {
175                panic!("compress() on FheBool is not supported on GPU, use a CompressedCiphertextList instead");
176            }
177            #[cfg(feature = "hpu")]
178            InternalServerKey::Hpu(_) => {
179                panic!("compress() on FheBool is not supported on HPU devices");
180            }
181        })
182    }
183}