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}