concrete_integer/server_key/crt_parallel/scalar_sub_crt.rs
1use crate::server_key::CheckError;
2use crate::server_key::CheckError::CarryFull;
3use crate::{CrtCiphertext, ServerKey};
4use rayon::prelude::*;
5
6impl ServerKey {
7 /// Computes homomorphically a subtraction between a ciphertext and a scalar.
8 ///
9 /// This function computes the operation without checking if it exceeds the capacity of the
10 /// ciphertext.
11 ///
12 /// The result is returned as a new ciphertext.
13 ///
14 /// # Example
15 ///
16 ///```rust
17 /// use concrete_integer::gen_keys;
18 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
19 ///
20 /// // Generate the client key and the server key:
21 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
22 ///
23 /// let clear_1 = 14;
24 /// let clear_2 = 7;
25 /// let basis = vec![2, 3, 5];
26 /// // Encrypt two messages
27 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
28 ///
29 /// sks.unchecked_crt_scalar_sub_assign_parallelized(&mut ctxt_1, clear_2);
30 ///
31 /// // Decrypt
32 /// let res = cks.decrypt_crt(&ctxt_1);
33 /// assert_eq!((clear_1 - clear_2) % 30, res);
34 /// ```
35 pub fn unchecked_crt_scalar_sub_parallelized(
36 &self,
37 ct: &CrtCiphertext,
38 scalar: u64,
39 ) -> CrtCiphertext {
40 let mut result = ct.clone();
41 self.unchecked_crt_scalar_sub_assign_parallelized(&mut result, scalar);
42 result
43 }
44
45 pub fn unchecked_crt_scalar_sub_assign_parallelized(
46 &self,
47 ct: &mut CrtCiphertext,
48 scalar: u64,
49 ) {
50 //Put each decomposition into a new ciphertext
51 ct.blocks
52 .par_iter_mut()
53 .zip(ct.moduli.par_iter())
54 .for_each(|(ct_i, mod_i)| {
55 let neg_scalar = (mod_i - scalar % mod_i) % mod_i;
56 self.key
57 .unchecked_scalar_add_assign_crt(ct_i, neg_scalar as u8);
58 });
59 }
60
61 /// Computes homomorphically a subtraction of a ciphertext by a scalar.
62 ///
63 /// If the operation can be performed, the result is returned in a new ciphertext.
64 /// Otherwise [CheckError::CarryFull] is returned.
65 ///
66 /// # Example
67 ///
68 /// ```rust
69 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
70 /// use concrete_integer::gen_keys;
71 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
72 ///
73 /// // Generate the client key and the server key:
74 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
75 ///
76 /// let clear_1 = 14;
77 /// let clear_2 = 8;
78 /// let basis = vec![2, 3, 5];
79 ///
80 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
81 ///
82 /// let ct_res = sks.checked_crt_scalar_sub_parallelized(&mut ctxt_1, clear_2)?;
83 ///
84 /// // Decrypt:
85 /// let dec = cks.decrypt_crt(&ct_res);
86 /// assert_eq!((clear_1 - clear_2) % 30, dec);
87 /// # Ok(())
88 /// # }
89 /// ```
90 pub fn checked_crt_scalar_sub_parallelized(
91 &self,
92 ct: &CrtCiphertext,
93 scalar: u64,
94 ) -> Result<CrtCiphertext, CheckError> {
95 if self.is_crt_scalar_sub_possible(ct, scalar) {
96 Ok(self.unchecked_crt_scalar_sub_parallelized(ct, scalar))
97 } else {
98 Err(CarryFull)
99 }
100 }
101
102 /// Computes homomorphically a subtraction of a ciphertext by a scalar.
103 ///
104 /// If the operation can be performed, the result is returned in a new ciphertext.
105 /// Otherwise [CheckError::CarryFull] is returned.
106 ///
107 /// # Example
108 ///
109 /// ```rust
110 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
111 /// use concrete_integer::gen_keys;
112 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
113 ///
114 /// // Generate the client key and the server key:
115 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
116 ///
117 /// let clear_1 = 14;
118 /// let clear_2 = 7;
119 /// let basis = vec![2, 3, 5];
120 ///
121 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
122 ///
123 /// sks.checked_crt_scalar_sub_assign_parallelized(&mut ctxt_1, clear_2)?;
124 ///
125 /// // Decrypt:
126 /// let dec = cks.decrypt_crt(&ctxt_1);
127 /// assert_eq!((clear_1 - clear_2) % 30, dec);
128 /// # Ok(())
129 /// # }
130 /// ```
131 pub fn checked_crt_scalar_sub_assign_parallelized(
132 &self,
133 ct: &mut CrtCiphertext,
134 scalar: u64,
135 ) -> Result<(), CheckError> {
136 if self.is_crt_scalar_sub_possible(ct, scalar) {
137 self.unchecked_crt_scalar_sub_assign_parallelized(ct, scalar);
138 Ok(())
139 } else {
140 Err(CarryFull)
141 }
142 }
143
144 /// Computes homomorphically a subtraction of a ciphertext by a scalar.
145 ///
146 /// # Example
147 ///
148 ///```rust
149 /// use concrete_integer::gen_keys;
150 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
151 ///
152 /// // Generate the client key and the server key:
153 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
154 ///
155 /// let clear_1 = 14;
156 /// let clear_2 = 7;
157 /// let basis = vec![2, 3, 5];
158 /// // Encrypt two messages
159 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
160 ///
161 /// sks.smart_crt_scalar_sub_assign_parallelized(&mut ctxt_1, clear_2);
162 ///
163 /// // Decrypt
164 /// let res = cks.decrypt_crt(&ctxt_1);
165 /// assert_eq!((clear_1 - clear_2) % 30, res);
166 /// ```
167 pub fn smart_crt_scalar_sub_parallelized(
168 &self,
169 ct: &mut CrtCiphertext,
170 scalar: u64,
171 ) -> CrtCiphertext {
172 if !self.is_crt_scalar_sub_possible(ct, scalar) {
173 self.full_extract_parallelized(ct);
174 }
175
176 self.unchecked_crt_scalar_sub_parallelized(ct, scalar)
177 }
178
179 pub fn smart_crt_scalar_sub_assign_parallelized(&self, ct: &mut CrtCiphertext, scalar: u64) {
180 if !self.is_crt_scalar_sub_possible(ct, scalar) {
181 self.full_extract_parallelized(ct);
182 }
183
184 self.unchecked_crt_scalar_sub_assign_parallelized(ct, scalar);
185 }
186}