concrete_integer/server_key/radix/neg.rs
1use crate::ciphertext::RadixCiphertext;
2use crate::server_key::CheckError;
3use crate::server_key::CheckError::CarryFull;
4use crate::ServerKey;
5
6impl ServerKey {
7 /// Homomorphically computes the opposite of a ciphertext encrypting an integer message.
8 ///
9 /// This function computes the opposite of a message without checking if it exceeds the
10 /// capacity of the ciphertext.
11 ///
12 /// The result is returned as a new ciphertext.
13 ///
14 /// # Example
15 ///
16 /// ```rust
17 /// // Encrypt two messages:
18 /// use concrete_integer::gen_keys_radix;
19 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
20 ///
21 /// // We have 4 * 2 = 8 bits of message
22 /// let size = 4;
23 /// let modulus = 1 << 8;
24 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
25 ///
26 /// let msg = 159;
27 ///
28 /// // Encrypt a message
29 /// let mut ctxt = cks.encrypt(msg);
30 ///
31 /// // Compute homomorphically a negation
32 /// sks.unchecked_neg_assign(&mut ctxt);
33 ///
34 /// // Decrypt
35 /// let dec = cks.decrypt(&ctxt);
36 /// assert_eq!(modulus - msg, dec);
37 /// ```
38 pub fn unchecked_neg(&self, ctxt: &RadixCiphertext) -> RadixCiphertext {
39 let mut result = ctxt.clone();
40
41 self.unchecked_neg_assign(&mut result);
42
43 result
44 }
45
46 /// Homomorphically computes the opposite of a ciphertext encrypting an integer message.
47 ///
48 /// This function computes the opposite of a message without checking if it exceeds the
49 /// capacity of the ciphertext.
50 ///
51 /// The result is assigned to the `ct_left` ciphertext.
52 pub fn unchecked_neg_assign(&self, ctxt: &mut RadixCiphertext) {
53 //z is used to make sure the negation doesn't fill the padding bit
54 let mut z;
55 let mut z_b;
56
57 for i in 0..ctxt.blocks.len() {
58 let c_i = &mut ctxt.blocks[i];
59 z = self.key.unchecked_neg_assign_with_z(c_i);
60
61 // Subtract z/B to the next ciphertext to compensate for the addition of z
62 z_b = z / self.key.message_modulus.0 as u64;
63
64 if i < ctxt.blocks.len() - 1 {
65 let c_j = &mut ctxt.blocks[i + 1];
66 self.key.unchecked_scalar_add_assign(c_j, z_b as u8);
67 }
68 }
69 }
70
71 /// Verifies if ct can be negated.
72 ///
73 /// # Example
74 ///
75 ///```rust
76 /// use concrete_integer::gen_keys_radix;
77 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
78 ///
79 /// // We have 4 * 2 = 8 bits of message
80 /// let size = 4;
81 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
82 ///
83 /// let msg = 2;
84 ///
85 /// // Encrypt a message
86 /// let ctxt = cks.encrypt(msg);
87 ///
88 /// // Check if we can perform a negation
89 /// let res = sks.is_neg_possible(&ctxt);
90 ///
91 /// assert_eq!(true, res);
92 /// ```
93 pub fn is_neg_possible(&self, ctxt: &RadixCiphertext) -> bool {
94 for ct_i in ctxt.blocks.iter() {
95 if !self.key.is_neg_possible(ct_i) {
96 return false;
97 }
98 }
99 true
100 }
101
102 /// Homomorphically computes the opposite of a ciphertext encrypting an integer message.
103 ///
104 /// This function computes the opposite of a message without checking if it exceeds the
105 /// capacity of the ciphertext.
106 ///
107 /// The result is returned as a new ciphertext.
108 ///
109 /// # Example
110 ///
111 /// ```rust
112 /// use concrete_integer::gen_keys_radix;
113 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
114 ///
115 /// // We have 4 * 2 = 8 bits of message
116 /// let size = 4;
117 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
118 ///
119 /// let msg = 1;
120 ///
121 /// // Encrypt a message
122 /// let ctxt = cks.encrypt(msg);
123 ///
124 /// // Compute homomorphically a negation:
125 /// let ct_res = sks.checked_neg(&ctxt);
126 ///
127 /// match ct_res {
128 /// Err(x) => panic!("{:?}", x),
129 /// Ok(y) => {
130 /// let clear = cks.decrypt(&y);
131 /// assert_eq!(255, clear);
132 /// }
133 /// }
134 /// ```
135 pub fn checked_neg(&self, ctxt: &RadixCiphertext) -> Result<RadixCiphertext, CheckError> {
136 //If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
137 if self.is_neg_possible(ctxt) {
138 let mut result = ctxt.clone();
139 self.unchecked_neg_assign(&mut result);
140 Ok(result)
141 } else {
142 Err(CarryFull)
143 }
144 }
145
146 /// Homomorphically computes the opposite of a ciphertext encrypting an integer message.
147 ///
148 /// This function computes the opposite of a message without checking if it exceeds the
149 /// capacity of the ciphertext.
150 ///
151 /// # Example
152 ///
153 /// ```rust
154 /// use concrete_integer::gen_keys_radix;
155 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
156 ///
157 /// // We have 4 * 2 = 8 bits of message
158 /// let size = 4;
159 /// let modulus = 1 << 8;
160 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
161 ///
162 /// let msg = 1;
163 ///
164 /// // Encrypt a message
165 /// let mut ct = cks.encrypt(msg);
166 ///
167 /// // Compute homomorphically a negation:
168 /// sks.checked_neg_assign(&mut ct);
169 ///
170 /// let clear_res = cks.decrypt(&ct);
171 /// assert_eq!(clear_res, (modulus - msg));
172 /// ```
173 pub fn checked_neg_assign(&self, ctxt: &mut RadixCiphertext) -> Result<(), CheckError> {
174 //If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
175 if self.is_neg_possible(ctxt) {
176 self.unchecked_neg_assign(ctxt);
177 Ok(())
178 } else {
179 Err(CarryFull)
180 }
181 }
182
183 /// Homomorphically computes the opposite of a ciphertext encrypting an integer message.
184 ///
185 /// The result is returned as a new ciphertext.
186 ///
187 /// # Example
188 ///
189 /// ```rust
190 /// use concrete_integer::gen_keys_radix;
191 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
192 ///
193 /// // We have 4 * 2 = 8 bits of message
194 /// let size = 4;
195 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
196 ///
197 /// let msg = 1;
198 ///
199 /// // Encrypt two messages:
200 /// let mut ctxt = cks.encrypt(msg);
201 ///
202 /// // Compute homomorphically a negation
203 /// let ct_res = sks.smart_neg(&mut ctxt);
204 ///
205 /// // Decrypt
206 /// let dec = cks.decrypt(&ct_res);
207 /// assert_eq!(255, dec);
208 /// ```
209 pub fn smart_neg(&self, ctxt: &mut RadixCiphertext) -> RadixCiphertext {
210 if !self.is_neg_possible(ctxt) {
211 self.full_propagate(ctxt);
212 }
213 self.unchecked_neg(ctxt)
214 }
215}