concrete_integer/server_key/crt/sub_crt.rs
1use crate::{CrtCiphertext, ServerKey};
2
3impl ServerKey {
4 /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
5 ///
6 /// This function computes the subtraction without checking if it exceeds the capacity of the
7 /// ciphertext.
8 ///
9 /// The result is returned as a new ciphertext.
10 /// # Example
11 ///
12 ///```rust
13 /// use concrete_integer::gen_keys;
14 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
15 ///
16 /// // Generate the client key and the server key:
17 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
18 ///
19 /// let clear_1 = 14;
20 /// let clear_2 = 5;
21 /// let basis = vec![2, 3, 5];
22 /// // Encrypt two messages
23 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
24 /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
25 ///
26 /// let ctxt = sks.unchecked_crt_sub(&mut ctxt_1, &mut ctxt_2);
27 ///
28 /// // Decrypt
29 /// let res = cks.decrypt_crt(&ctxt);
30 /// assert_eq!((clear_1 - clear_2) % 30, res);
31 /// ```
32 pub fn unchecked_crt_sub(
33 &self,
34 ctxt_left: &CrtCiphertext,
35 ctxt_right: &CrtCiphertext,
36 ) -> CrtCiphertext {
37 let mut result = ctxt_left.clone();
38 self.unchecked_crt_sub_assign(&mut result, ctxt_right);
39 result
40 }
41
42 /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
43 ///
44 /// This function computes the subtraction without checking if it exceeds the capacity of the
45 /// ciphertext.
46 ///
47 /// The result is assigned to the `ct_left` ciphertext.
48 /// # Example
49 ///
50 ///```rust
51 /// use concrete_integer::gen_keys;
52 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
53 ///
54 /// // Generate the client key and the server key:
55 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
56 ///
57 /// let clear_1 = 14;
58 /// let clear_2 = 5;
59 /// let basis = vec![2, 3, 5];
60 /// // Encrypt two messages
61 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
62 /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
63 ///
64 /// let ctxt = sks.unchecked_crt_sub(&mut ctxt_1, &mut ctxt_2);
65 ///
66 /// // Decrypt
67 /// let res = cks.decrypt_crt(&ctxt);
68 /// assert_eq!((clear_1 - clear_2) % 30, res);
69 /// ```
70 pub fn unchecked_crt_sub_assign(
71 &self,
72 ctxt_left: &mut CrtCiphertext,
73 ctxt_right: &CrtCiphertext,
74 ) {
75 let neg = self.unchecked_crt_neg(ctxt_right);
76 self.unchecked_crt_add_assign(ctxt_left, &neg);
77 }
78
79 /// Computes homomorphically the subtraction between ct_left and ct_right.
80 ///
81 /// # Example
82 ///
83 ///```rust
84 /// use concrete_integer::gen_keys;
85 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
86 ///
87 /// // Generate the client key and the server key:
88 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
89 ///
90 /// let clear_1 = 14;
91 /// let clear_2 = 5;
92 /// let basis = vec![2, 3, 5];
93 /// // Encrypt two messages
94 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
95 /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
96 ///
97 /// let ctxt = sks.smart_crt_sub(&mut ctxt_1, &mut ctxt_2);
98 ///
99 /// // Decrypt
100 /// let res = cks.decrypt_crt(&ctxt);
101 /// assert_eq!((clear_1 - clear_2) % 30, res);
102 /// ```
103 pub fn smart_crt_sub(
104 &self,
105 ctxt_left: &mut CrtCiphertext,
106 ctxt_right: &mut CrtCiphertext,
107 ) -> CrtCiphertext {
108 // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
109 if !self.is_crt_sub_possible(ctxt_left, ctxt_right) {
110 self.full_extract(ctxt_left);
111 self.full_extract(ctxt_right);
112 }
113
114 let mut result = ctxt_left.clone();
115 self.unchecked_crt_sub_assign(&mut result, ctxt_right);
116
117 result
118 }
119
120 /// Computes homomorphically the subtraction between ct_left and ct_right.
121 ///
122 /// # Example
123 ///
124 ///```rust
125 /// use concrete_integer::gen_keys;
126 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
127 ///
128 /// // Generate the client key and the server key:
129 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
130 ///
131 /// let clear_1 = 14;
132 /// let clear_2 = 5;
133 /// let basis = vec![2, 3, 5];
134 /// // Encrypt two messages
135 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
136 /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
137 ///
138 /// sks.smart_crt_sub_assign(&mut ctxt_1, &mut ctxt_2);
139 ///
140 /// // Decrypt
141 /// let res = cks.decrypt_crt(&ctxt_1);
142 /// assert_eq!((clear_1 - clear_2) % 30, res);
143 /// ```
144 pub fn smart_crt_sub_assign(
145 &self,
146 ctxt_left: &mut CrtCiphertext,
147 ctxt_right: &mut CrtCiphertext,
148 ) {
149 // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
150 if !self.is_crt_sub_possible(ctxt_left, ctxt_right) {
151 self.full_extract(ctxt_left);
152 self.full_extract(ctxt_right);
153 }
154
155 self.unchecked_crt_sub_assign(ctxt_left, ctxt_right);
156 }
157
158 pub fn is_crt_sub_possible(
159 &self,
160 ctxt_left: &CrtCiphertext,
161 ctxt_right: &CrtCiphertext,
162 ) -> bool {
163 for (ct_left_i, ct_right_i) in ctxt_left.blocks.iter().zip(ctxt_right.blocks.iter()) {
164 if !self.key.is_sub_possible(ct_left_i, ct_right_i) {
165 return false;
166 }
167 }
168 true
169 }
170}