tfhe/integer/server_key/
mod.rs1pub mod comparator;
6pub(crate) mod crt;
7mod crt_parallel;
8pub(crate) mod radix;
9pub(crate) mod radix_parallel;
10
11use super::backward_compatibility::server_key::{CompressedServerKeyVersions, ServerKeyVersions};
12use crate::conformance::ParameterSetConformant;
13use crate::core_crypto::prelude::UnsignedInteger;
14use crate::integer::client_key::ClientKey;
15use crate::shortint::atomic_pattern::AtomicPatternParameters;
16use crate::shortint::ciphertext::{Degree, MaxDegree};
17pub use crate::shortint::CheckError;
19use crate::shortint::{CarryModulus, MessageModulus};
20pub use radix::scalar_mul::ScalarMultiplier;
21pub use radix::scalar_sub::TwosComplementNegation;
22pub use radix_parallel::{MatchValues, MiniUnsignedInteger, Reciprocable};
23use serde::{Deserialize, Serialize};
24use tfhe_versionable::Versionize;
25
26#[derive(Serialize, Deserialize, Clone, Versionize)]
34#[versionize(ServerKeyVersions)]
35pub struct ServerKey {
36 pub(crate) key: crate::shortint::ServerKey,
37}
38
39impl From<ServerKey> for crate::shortint::ServerKey {
40 fn from(key: ServerKey) -> Self {
41 key.key
42 }
43}
44
45impl MaxDegree {
46 pub(crate) fn integer_radix_server_key(
52 message_modulus: MessageModulus,
53 carry_modulus: CarryModulus,
54 ) -> Self {
55 let full_max_degree = message_modulus.0 * carry_modulus.0 - 1;
56
57 let carry_max_degree = carry_modulus.0 - 1;
58
59 Self::new(full_max_degree - carry_max_degree)
61 }
62}
63
64impl MaxDegree {
65 fn integer_crt_server_key(
69 message_modulus: MessageModulus,
70 carry_modulus: CarryModulus,
71 ) -> Self {
72 let full_max_degree = message_modulus.0 * carry_modulus.0 - 1;
73
74 Self::new(full_max_degree)
75 }
76}
77
78impl ServerKey {
79 pub fn new_radix_server_key<C>(cks: C) -> Self
94 where
95 C: AsRef<ClientKey>,
96 {
97 let client_key = cks.as_ref();
99 let max_degree = MaxDegree::integer_radix_server_key(
100 client_key.key.parameters.message_modulus(),
101 client_key.key.parameters.carry_modulus(),
102 );
103
104 let sks = crate::shortint::server_key::ServerKey::new_with_max_degree(
105 &client_key.key,
106 max_degree,
107 );
108
109 Self { key: sks }
110 }
111
112 pub fn new_crt_server_key<C>(cks: C) -> Self
113 where
114 C: AsRef<ClientKey>,
115 {
116 let client_key = cks.as_ref();
117 let max_degree = MaxDegree::integer_crt_server_key(
118 client_key.key.parameters.message_modulus(),
119 client_key.key.parameters.carry_modulus(),
120 );
121
122 let sks = crate::shortint::server_key::ServerKey::new_with_max_degree(
123 &client_key.key,
124 max_degree,
125 );
126
127 Self { key: sks }
128 }
129
130 pub fn new_radix_server_key_from_shortint(
151 mut key: crate::shortint::server_key::ServerKey,
152 ) -> Self {
153 let max_degree =
155 MaxDegree::integer_radix_server_key(key.message_modulus, key.carry_modulus);
156
157 key.max_degree = max_degree;
158 Self { key }
159 }
160
161 pub fn new_crt_server_key_from_shortint(
182 mut key: crate::shortint::server_key::ServerKey,
183 ) -> Self {
184 key.max_degree = MaxDegree::integer_crt_server_key(key.message_modulus, key.carry_modulus);
185 Self { key }
186 }
187
188 pub fn into_raw_parts(self) -> crate::shortint::ServerKey {
190 self.key
191 }
192
193 pub fn from_raw_parts(key: crate::shortint::ServerKey) -> Self {
195 Self { key }
196 }
197
198 pub fn deterministic_pbs_execution(&self) -> bool {
199 self.key.deterministic_execution()
200 }
201
202 pub fn set_deterministic_pbs_execution(&mut self, new_deterministic_execution: bool) {
203 self.key
204 .set_deterministic_execution(new_deterministic_execution);
205 }
206
207 pub fn message_modulus(&self) -> MessageModulus {
208 self.key.message_modulus
209 }
210
211 pub fn carry_modulus(&self) -> CarryModulus {
212 self.key.carry_modulus
213 }
214
215 pub fn num_blocks_to_represent_unsigned_value<Clear>(&self, clear: Clear) -> usize
218 where
219 Clear: UnsignedInteger,
220 {
221 let num_bits_to_represent_output_value = num_bits_to_represent_unsigned_value(clear);
222 let num_bits_in_message = self.message_modulus().0.ilog2();
223 num_bits_to_represent_output_value.div_ceil(num_bits_in_message as usize)
224 }
225
226 pub(crate) fn max_sum_size(&self, degree: Degree) -> usize {
235 let max_degree =
236 MaxDegree::from_msg_carry_modulus(self.message_modulus(), self.carry_modulus());
237 let max_sum_to_full_carry = max_degree.get() / degree.get();
238
239 max_sum_to_full_carry.min(self.key.max_noise_level.get()) as usize
240 }
241}
242
243impl AsRef<crate::shortint::ServerKey> for ServerKey {
244 fn as_ref(&self) -> &crate::shortint::ServerKey {
245 &self.key
246 }
247}
248
249#[derive(Clone, Serialize, Deserialize, Versionize)]
250#[versionize(CompressedServerKeyVersions)]
251pub struct CompressedServerKey {
252 pub(crate) key: crate::shortint::CompressedServerKey,
253}
254
255impl CompressedServerKey {
256 pub fn new_radix_compressed_server_key(client_key: &ClientKey) -> Self {
257 let max_degree = MaxDegree::integer_radix_server_key(
258 client_key.key.parameters.message_modulus(),
259 client_key.key.parameters.carry_modulus(),
260 );
261
262 let key =
263 crate::shortint::CompressedServerKey::new_with_max_degree(&client_key.key, max_degree);
264 Self { key }
265 }
266
267 pub fn new_crt_compressed_server_key(client_key: &ClientKey) -> Self {
268 let key = crate::shortint::CompressedServerKey::new(&client_key.key);
269 Self { key }
270 }
271
272 pub fn decompress(&self) -> ServerKey {
274 ServerKey {
275 key: self.key.decompress(),
276 }
277 }
278
279 pub fn into_raw_parts(self) -> crate::shortint::CompressedServerKey {
281 self.key
282 }
283
284 pub fn from_raw_parts(key: crate::shortint::CompressedServerKey) -> Self {
286 Self { key }
287 }
288}
289
290pub fn num_bits_to_represent_unsigned_value<Clear>(clear: Clear) -> usize
291where
292 Clear: UnsignedInteger,
293{
294 if clear == Clear::MAX {
295 Clear::BITS
296 } else {
297 let bits = (clear + Clear::ONE).ceil_ilog2() as usize;
298 if bits == 0 {
299 1
300 } else {
301 bits
302 }
303 }
304}
305
306impl ParameterSetConformant for ServerKey {
307 type ParameterSet = AtomicPatternParameters;
308
309 fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool {
310 let Self { key } = self;
311
312 let expected_max_degree = MaxDegree::integer_radix_server_key(
313 parameter_set.message_modulus(),
314 parameter_set.carry_modulus(),
315 );
316
317 key.is_conformant(&(*parameter_set, expected_max_degree))
318 }
319}
320
321impl ParameterSetConformant for CompressedServerKey {
322 type ParameterSet = AtomicPatternParameters;
323
324 fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool {
325 let Self { key } = self;
326
327 let expected_max_degree = MaxDegree::integer_radix_server_key(
328 parameter_set.message_modulus(),
329 parameter_set.carry_modulus(),
330 );
331
332 key.is_conformant(&(*parameter_set, expected_max_degree))
333 }
334}
335
336#[cfg(test)]
337mod test {
338 use super::*;
339 use crate::integer::RadixClientKey;
340 use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
341
342 #[test]
346 fn test_compressed_server_key_max_degree() {
347 {
348 let cks = ClientKey::new(
349 crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
350 );
351 let expected_radix_max_degree = MaxDegree::new(12);
353
354 let sks = ServerKey::new_radix_server_key(&cks);
355 assert_eq!(sks.key.max_degree, expected_radix_max_degree);
356
357 let csks = CompressedServerKey::new_radix_compressed_server_key(&cks);
358 assert_eq!(csks.key.max_degree, expected_radix_max_degree);
359
360 let decompressed_sks: ServerKey = csks.decompress();
361 assert_eq!(decompressed_sks.key.max_degree, expected_radix_max_degree);
362 }
363
364 {
365 let cks = ClientKey::new(
366 crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128,
367 );
368 let expected_crt_max_degree = MaxDegree::new(15);
370
371 let sks = ServerKey::new_crt_server_key(&cks);
372 assert_eq!(sks.key.max_degree, expected_crt_max_degree);
373
374 let csks = CompressedServerKey::new_crt_compressed_server_key(&cks);
375 assert_eq!(csks.key.max_degree, expected_crt_max_degree);
376
377 let decompressed_sks: ServerKey = csks.decompress();
378 assert_eq!(decompressed_sks.key.max_degree, expected_crt_max_degree);
379 }
380
381 {
383 let client_key = RadixClientKey::new(PARAM_MESSAGE_2_CARRY_2, 14);
384 let compressed_eval_key =
385 CompressedServerKey::new_radix_compressed_server_key(client_key.as_ref());
386 let evaluation_key = compressed_eval_key.decompress();
387 let modulus = (client_key.parameters().message_modulus().0 as u128)
388 .pow(client_key.num_blocks() as u32);
389
390 let mut ct = client_key.encrypt(modulus - 1);
391 let mut res_ct = ct.clone();
392 for _ in 0..5 {
393 res_ct = evaluation_key.smart_add_parallelized(&mut res_ct, &mut ct);
394 }
395 let res: u128 = client_key.decrypt(&res_ct);
396 assert_eq!(modulus - 6, res);
397 }
398 }
399}