concrete_shortint/server_key/
comp_op.rs

1use super::ServerKey;
2use crate::engine::ShortintEngine;
3use crate::server_key::CheckError;
4use crate::server_key::CheckError::CarryFull;
5use crate::Ciphertext;
6
7// # Note:
8// _assign comparison operation are not made public (if they exists) as we don't think there are
9// uses for them. For instance: adding has an assign variants because you can do "+" and "+="
10// however, comparisons like equality do not have that, "==" does not have and "===",
11// ">=" is greater of equal, not greater_assign.
12
13impl ServerKey {
14    /// Implements the "greater" (`>`) operator between two ciphertexts without checks.
15    ///
16    /// # Example
17    ///
18    ///```rust
19    /// use concrete_shortint::gen_keys;
20    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
21    ///
22    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
23    ///
24    /// let msg_1 = 1;
25    /// let msg_2 = 2;
26    ///
27    /// // Encrypt two messages
28    /// let ct_left = cks.encrypt(msg_1);
29    /// let ct_right = cks.encrypt(msg_2);
30    ///
31    /// let ct_res = sks.unchecked_greater(&ct_left, &ct_right);
32    ///
33    /// // Decrypt
34    /// let res = cks.decrypt(&ct_res);
35    /// assert_eq!((msg_1 > msg_2) as u64, res);
36    /// ```
37    pub fn unchecked_greater(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
38        ShortintEngine::with_thread_local_mut(|engine| {
39            engine.unchecked_greater(self, ct_left, ct_right).unwrap()
40        })
41    }
42
43    /// Implements the "greater" (`>`) operator between two ciphertexts with checks.
44    ///
45    /// If the operation can be performed, the result is returned in a _new_ ciphertext.
46    /// Otherwise [CheckError::CarryFull] is returned.
47    ///
48    /// # Example
49    ///
50    /// ```rust
51    /// use concrete_shortint::gen_keys;
52    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
53    ///
54    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
55    ///
56    /// let msg_1 = 1;
57    /// let msg_2 = 2;
58    ///
59    /// // Encrypt two messages:
60    /// let ct_left = cks.encrypt(msg_1);
61    /// let ct_right = cks.encrypt(msg_2);
62    ///
63    /// let res = sks.checked_greater(&ct_left, &ct_right);
64    ///
65    /// assert!(res.is_ok());
66    /// let res = res.unwrap();
67    ///
68    /// let clear_res = cks.decrypt(&res);
69    /// assert_eq!((msg_1 > msg_2) as u64, clear_res);
70    /// ```
71    pub fn checked_greater(
72        &self,
73        ct_left: &Ciphertext,
74        ct_right: &Ciphertext,
75    ) -> Result<Ciphertext, CheckError> {
76        if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
77            Ok(self.unchecked_greater(ct_left, ct_right))
78        } else {
79            Err(CarryFull)
80        }
81    }
82
83    /// Computes homomorphically a `>` between two ciphertexts encrypting integer values.
84    ///
85    /// This checks that the addition is possible. In the case where the carry buffers are full,
86    /// then it is automatically cleared to allow the operation.
87    /// # Example
88    ///
89    /// ```rust
90    /// use concrete_shortint::gen_keys;
91    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
92    ///
93    /// // Generate the client key and the server key:
94    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
95    ///
96    /// let msg = 1;
97    ///
98    /// // Encrypt two messages:
99    /// let mut ct1 = cks.encrypt(msg);
100    /// let mut ct2 = cks.encrypt(msg);
101    ///
102    /// // Compute homomorphically an OR:
103    /// let ct_res = sks.smart_greater(&mut ct1, &mut ct2);
104    ///
105    /// // Decrypt:
106    /// let res = cks.decrypt(&ct_res);
107    /// assert_eq!((msg > msg) as u64, res);
108    /// ```
109    pub fn smart_greater(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
110        ShortintEngine::with_thread_local_mut(|engine| {
111            engine.smart_greater(self, ct_left, ct_right).unwrap()
112        })
113    }
114
115    /// Implements the "greater or equal" (`>=`) operator between two ciphertexts without checks.
116    ///
117    /// # Example
118    ///
119    ///```rust
120    /// use concrete_shortint::gen_keys;
121    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
122    ///
123    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
124    ///
125    /// let msg_1 = 1;
126    /// let msg_2 = 2;
127    ///
128    /// // Encrypt two messages
129    /// let ct_left = cks.encrypt(msg_1);
130    /// let ct_right = cks.encrypt(msg_2);
131    ///
132    /// let ct_res = sks.unchecked_greater_or_equal(&ct_left, &ct_right);
133    ///
134    /// // Decrypt
135    /// let res = cks.decrypt(&ct_res);
136    /// assert_eq!((msg_1 >= msg_2) as u64, res);
137    /// ```
138    pub fn unchecked_greater_or_equal(
139        &self,
140        ct_left: &Ciphertext,
141        ct_right: &Ciphertext,
142    ) -> Ciphertext {
143        ShortintEngine::with_thread_local_mut(|engine| {
144            engine
145                .unchecked_greater_or_equal(self, ct_left, ct_right)
146                .unwrap()
147        })
148    }
149
150    /// Computes homomorphically a `>=` between two ciphertexts encrypting integer values.
151    ///
152    /// This checks that the addition is possible. In the case where the carry buffers are full,
153    /// then it is automatically cleared to allow the operation.
154    /// # Example
155    ///
156    /// ```rust
157    /// use concrete_shortint::gen_keys;
158    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
159    ///
160    /// // Generate the client key and the server key:
161    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
162    ///
163    /// let msg = 1;
164    ///
165    /// // Encrypt two messages:
166    /// let mut ct1 = cks.encrypt(msg);
167    /// let mut ct2 = cks.encrypt(msg);
168    ///
169    /// // Compute homomorphically an OR:
170    /// let ct_res = sks.smart_greater_or_equal(&mut ct1, &mut ct2);
171    ///
172    /// // Decrypt:
173    /// let res = cks.decrypt(&ct_res);
174    /// assert_eq!((msg >= msg) as u64, res);
175    /// ```
176    pub fn smart_greater_or_equal(
177        &self,
178        ct_left: &mut Ciphertext,
179        ct_right: &mut Ciphertext,
180    ) -> Ciphertext {
181        ShortintEngine::with_thread_local_mut(|engine| {
182            engine
183                .smart_greater_or_equal(self, ct_left, ct_right)
184                .unwrap()
185        })
186    }
187
188    /// Implements the "greater or equal" (`>=`) operator between two ciphertexts with checks.
189    ///
190    /// If the operation can be performed, the result is returned in a _new_ ciphertext.
191    /// Otherwise [CheckError::CarryFull] is returned.
192    ///
193    /// # Example
194    ///
195    /// ```rust
196    /// use concrete_shortint::gen_keys;
197    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
198    ///
199    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
200    ///
201    /// let msg_1 = 1;
202    /// let msg_2 = 2;
203    ///
204    /// // Encrypt two messages:
205    /// let ct_left = cks.encrypt(msg_1);
206    /// let ct_right = cks.encrypt(msg_2);
207    ///
208    /// let res = sks.checked_greater(&ct_left, &ct_right);
209    ///
210    /// assert!(res.is_ok());
211    /// let res = res.unwrap();
212    ///
213    /// let clear_res = cks.decrypt(&res);
214    /// assert_eq!((msg_1 >= msg_2) as u64, clear_res);
215    /// ```
216    pub fn checked_greater_or_equal(
217        &self,
218        ct_left: &Ciphertext,
219        ct_right: &Ciphertext,
220    ) -> Result<Ciphertext, CheckError> {
221        if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
222            Ok(self.unchecked_greater_or_equal(ct_left, ct_right))
223        } else {
224            Err(CarryFull)
225        }
226    }
227
228    /// Implements the "less" (`<`) operator between two ciphertexts without checks.
229    ///
230    /// # Example
231    ///
232    ///```rust
233    /// use concrete_shortint::gen_keys;
234    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
235    ///
236    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
237    ///
238    /// let msg_1 = 1;
239    /// let msg_2 = 2;
240    ///
241    /// // Encrypt two messages
242    /// let ct_left = cks.encrypt(msg_1);
243    /// let ct_right = cks.encrypt(msg_2);
244    ///
245    /// // Do the comparison
246    /// let ct_res = sks.unchecked_less(&ct_left, &ct_right);
247    ///
248    /// // Decrypt
249    /// let res = cks.decrypt(&ct_res);
250    /// assert_eq!((msg_1 < msg_2) as u64, res);
251    /// ```
252    pub fn unchecked_less(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
253        ShortintEngine::with_thread_local_mut(|engine| {
254            engine.unchecked_less(self, ct_left, ct_right).unwrap()
255        })
256    }
257
258    /// Implements the "less" (`<`) operator between two ciphertexts with checks.
259    ///
260    /// If the operation can be performed, the result is returned in a _new_ ciphertext.
261    /// Otherwise [CheckError::CarryFull] is returned.
262    ///
263    /// # Example
264    ///
265    /// ```rust
266    /// use concrete_shortint::gen_keys;
267    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
268    ///
269    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
270    ///
271    /// let msg_1 = 1;
272    /// let msg_2 = 2;
273    ///
274    /// // Encrypt two messages:
275    /// let ct_left = cks.encrypt(msg_1);
276    /// let ct_right = cks.encrypt(msg_2);
277    ///
278    /// let res = sks.checked_less(&ct_left, &ct_right);
279    ///
280    /// assert!(res.is_ok());
281    /// let res = res.unwrap();
282    ///
283    /// let clear_res = cks.decrypt(&res);
284    /// assert_eq!((msg_1 < msg_2) as u64, clear_res);
285    /// ```
286    pub fn checked_less(
287        &self,
288        ct_left: &Ciphertext,
289        ct_right: &Ciphertext,
290    ) -> Result<Ciphertext, CheckError> {
291        if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
292            Ok(self.unchecked_less(ct_left, ct_right))
293        } else {
294            Err(CarryFull)
295        }
296    }
297
298    /// Computes homomorphically a `<` between two ciphertexts encrypting integer values.
299    ///
300    /// This checks that the addition is possible. In the case where the carry buffers are full,
301    /// then it is automatically cleared to allow the operation.
302    /// # Example
303    ///
304    /// ```rust
305    /// use concrete_shortint::gen_keys;
306    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
307    ///
308    /// // Generate the client key and the server key:
309    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
310    ///
311    /// let msg = 1;
312    ///
313    /// // Encrypt two messages:
314    /// let mut ct1 = cks.encrypt(msg);
315    /// let mut ct2 = cks.encrypt(msg);
316    ///
317    /// // Compute homomorphically an OR:
318    /// let ct_res = sks.smart_less(&mut ct1, &mut ct2);
319    ///
320    /// // Decrypt:
321    /// let res = cks.decrypt(&ct_res);
322    /// assert_eq!((msg < msg) as u64, res);
323    /// ```
324    pub fn smart_less(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
325        ShortintEngine::with_thread_local_mut(|engine| {
326            engine.smart_less(self, ct_left, ct_right).unwrap()
327        })
328    }
329
330    /// Implements the "less or equal" (`<=`) between two ciphertexts operator without checks.
331    ///
332    /// # Example
333    ///
334    ///```rust
335    /// use concrete_shortint::gen_keys;
336    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
337    ///
338    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
339    ///
340    /// let msg_1 = 1;
341    /// let msg_2 = 2;
342    ///
343    /// // Encrypt two messages
344    /// let ct_left = cks.encrypt(msg_1);
345    /// let ct_right = cks.encrypt(msg_2);
346    ///
347    /// let ct_res = sks.unchecked_less_or_equal(&ct_left, &ct_right);
348    ///
349    /// // Decrypt
350    /// let res = cks.decrypt(&ct_res);
351    /// assert_eq!((msg_1 <= msg_2) as u64, res);
352    /// ```
353    pub fn unchecked_less_or_equal(
354        &self,
355        ct_left: &Ciphertext,
356        ct_right: &Ciphertext,
357    ) -> Ciphertext {
358        ShortintEngine::with_thread_local_mut(|engine| {
359            engine
360                .unchecked_less_or_equal(self, ct_left, ct_right)
361                .unwrap()
362        })
363    }
364
365    /// Implements the "less or equal" (`<=`) operator between two ciphertexts with checks.
366    ///
367    /// If the operation can be performed, the result is returned in a _new_ ciphertext.
368    /// Otherwise [CheckError::CarryFull] is returned.
369    ///
370    /// # Example
371    ///
372    /// ```rust
373    /// use concrete_shortint::gen_keys;
374    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
375    ///
376    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
377    ///
378    /// let msg_1 = 1;
379    /// let msg_2 = 2;
380    ///
381    /// // Encrypt two messages:
382    /// let ct_left = cks.encrypt(msg_1);
383    /// let ct_right = cks.encrypt(msg_2);
384    ///
385    /// let res = sks.checked_less_or_equal(&ct_left, &ct_right);
386    ///
387    /// assert!(res.is_ok());
388    /// let res = res.unwrap();
389    ///
390    /// let clear_res = cks.decrypt(&res);
391    /// assert_eq!((msg_1 <= msg_2) as u64, clear_res);
392    /// ```
393    pub fn checked_less_or_equal(
394        &self,
395        ct_left: &Ciphertext,
396        ct_right: &Ciphertext,
397    ) -> Result<Ciphertext, CheckError> {
398        if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
399            Ok(self.unchecked_less(ct_left, ct_right))
400        } else {
401            Err(CarryFull)
402        }
403    }
404
405    /// Computes homomorphically a `<=` between two ciphertexts encrypting integer values.
406    ///
407    /// This checks that the addition is possible. In the case where the carry buffers are full,
408    /// then it is automatically cleared to allow the operation.
409    /// # Example
410    ///
411    /// ```rust
412    /// use concrete_shortint::gen_keys;
413    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
414    ///
415    /// // Generate the client key and the server key:
416    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
417    ///
418    /// let msg = 1;
419    ///
420    /// // Encrypt two messages:
421    /// let mut ct1 = cks.encrypt(msg);
422    /// let mut ct2 = cks.encrypt(msg);
423    ///
424    /// // Compute homomorphically an OR:
425    /// let ct_res = sks.smart_less_or_equal(&mut ct1, &mut ct2);
426    ///
427    /// // Decrypt:
428    /// let res = cks.decrypt(&ct_res);
429    /// assert_eq!((msg >= msg) as u64, res);
430    /// ```
431    pub fn smart_less_or_equal(
432        &self,
433        ct_left: &mut Ciphertext,
434        ct_right: &mut Ciphertext,
435    ) -> Ciphertext {
436        ShortintEngine::with_thread_local_mut(|engine| {
437            engine.smart_less_or_equal(self, ct_left, ct_right).unwrap()
438        })
439    }
440
441    /// Implements the "equal" operator (`==`) between two ciphertexts without checks.
442    ///
443    /// # Example
444    ///
445    ///```rust
446    /// use concrete_shortint::gen_keys;
447    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
448    ///
449    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
450    ///
451    /// let msg_1 = 2;
452    /// let msg_2 = 2;
453    ///
454    /// // Encrypt two messages
455    /// let ct_left = cks.encrypt(msg_1);
456    /// let ct_right = cks.encrypt(msg_2);
457    ///
458    /// let ct_res = sks.unchecked_equal(&ct_left, &ct_right);
459    ///
460    /// // Decrypt
461    /// let res = cks.decrypt(&ct_res);
462    /// assert_eq!(res, 1);
463    /// ```
464    pub fn unchecked_equal(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
465        ShortintEngine::with_thread_local_mut(|engine| {
466            engine.unchecked_equal(self, ct_left, ct_right).unwrap()
467        })
468    }
469
470    /// Implements the "less" (`==`) operator between two ciphertexts with checks.
471    ///
472    /// If the operation can be performed, the result is returned in a _new_ ciphertext.
473    /// Otherwise [CheckError::CarryFull] is returned.
474    ///
475    /// # Example
476    ///
477    /// ```rust
478    /// use concrete_shortint::gen_keys;
479    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
480    ///
481    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
482    ///
483    /// let msg_1 = 1;
484    /// let msg_2 = 2;
485    ///
486    /// // Encrypt two messages:
487    /// let ct_left = cks.encrypt(msg_1);
488    /// let ct_right = cks.encrypt(msg_2);
489    ///
490    /// let res = sks.checked_equal(&ct_left, &ct_right);
491    ///
492    /// assert!(res.is_ok());
493    /// let res = res.unwrap();
494    ///
495    /// let clear_res = cks.decrypt(&res);
496    /// assert_eq!((msg_1 == msg_2) as u64, clear_res);
497    /// ```
498    pub fn checked_equal(
499        &self,
500        ct_left: &Ciphertext,
501        ct_right: &Ciphertext,
502    ) -> Result<Ciphertext, CheckError> {
503        if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
504            Ok(self.unchecked_equal(ct_left, ct_right))
505        } else {
506            Err(CarryFull)
507        }
508    }
509
510    /// Computes homomorphically a `==` between two ciphertexts encrypting integer values.
511    ///
512    /// This checks that the addition is possible. In the case where the carry buffers are full,
513    /// then it is automatically cleared to allow the operation.
514    /// # Example
515    ///
516    /// ```rust
517    /// use concrete_shortint::gen_keys;
518    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
519    ///
520    /// // Generate the client key and the server key:
521    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
522    ///
523    /// let msg = 1;
524    ///
525    /// // Encrypt two messages:
526    /// let mut ct1 = cks.encrypt(msg);
527    /// let mut ct2 = cks.encrypt(msg);
528    ///
529    /// // Compute homomorphically an OR:
530    /// let ct_res = sks.smart_equal(&mut ct1, &mut ct2);
531    ///
532    /// // Decrypt:
533    /// let res = cks.decrypt(&ct_res);
534    /// assert_eq!((msg == msg) as u64, res);
535    /// ```
536    pub fn smart_equal(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
537        ShortintEngine::with_thread_local_mut(|engine| {
538            engine.smart_equal(self, ct_left, ct_right).unwrap()
539        })
540    }
541
542    /// Implements the "equal" operator (`==`) between a ciphertext and a scalar without checks.
543    ///
544    /// # Example
545    ///
546    ///```rust
547    /// use concrete_shortint::gen_keys;
548    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
549    ///
550    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
551    ///
552    /// let msg_1 = 2;
553    /// let scalar = 2;
554    ///
555    /// // Encrypt two messages
556    /// let ct_left = cks.encrypt(msg_1);
557    ///
558    /// let ct_res = sks.smart_scalar_equal(&ct_left, scalar);
559    ///
560    /// // Decrypt
561    /// let res = cks.decrypt(&ct_res);
562    /// assert_eq!(res, (msg_1 == scalar as u64) as u64);
563    /// ```
564    pub fn smart_scalar_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
565        ShortintEngine::with_thread_local_mut(|engine| {
566            engine.smart_scalar_equal(self, ct_left, scalar).unwrap()
567        })
568    }
569
570    /// Implements the "equal" operator (`>=`) between a ciphertext and a scalar without checks.
571    ///
572    /// # Example
573    ///
574    ///```rust
575    /// use concrete_shortint::gen_keys;
576    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
577    ///
578    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
579    ///
580    /// let msg_1 = 2;
581    /// let scalar = 2;
582    ///
583    /// // Encrypt two messages
584    /// let ct_left = cks.encrypt(msg_1);
585    ///
586    /// let ct_res = sks.smart_scalar_greater_or_equal(&ct_left, scalar);
587    ///
588    /// // Decrypt
589    /// let res = cks.decrypt(&ct_res);
590    /// assert_eq!(res, (msg_1 >= scalar as u64) as u64);
591    /// ```
592    pub fn smart_scalar_greater_or_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
593        ShortintEngine::with_thread_local_mut(|engine| {
594            engine
595                .smart_scalar_greater_or_equal(self, ct_left, scalar)
596                .unwrap()
597        })
598    }
599
600    /// Implements the "less or equal" operator (`<=`) between a ciphertext and a scalar without
601    /// checks.
602    ///
603    /// # Example
604    ///
605    ///```rust
606    /// use concrete_shortint::gen_keys;
607    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
608    ///
609    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
610    ///
611    /// let msg_1 = 2;
612    /// let scalar = 2;
613    ///
614    /// // Encrypt two messages
615    /// let ct_left = cks.encrypt(msg_1);
616    ///
617    /// let ct_res = sks.smart_scalar_less_or_equal(&ct_left, scalar);
618    ///
619    /// // Decrypt
620    /// let res = cks.decrypt(&ct_res);
621    /// assert_eq!(res, (msg_1 <= scalar as u64) as u64);
622    /// ```
623    pub fn smart_scalar_less_or_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
624        ShortintEngine::with_thread_local_mut(|engine| {
625            engine
626                .smart_scalar_less_or_equal(self, ct_left, scalar)
627                .unwrap()
628        })
629    }
630
631    /// Implements the "equal" operator (`>`) between a ciphertext and a scalar without checks.
632    ///
633    /// # Example
634    ///
635    ///```rust
636    /// use concrete_shortint::gen_keys;
637    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
638    ///
639    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
640    ///
641    /// let msg_1 = 2;
642    /// let scalar = 2;
643    ///
644    /// // Encrypt two messages
645    /// let ct_left = cks.encrypt(msg_1);
646    ///
647    /// let ct_res = sks.smart_scalar_greater(&ct_left, scalar);
648    ///
649    /// // Decrypt
650    /// let res = cks.decrypt(&ct_res);
651    /// assert_eq!(res, (msg_1 > scalar as u64) as u64);
652    /// ```
653    pub fn smart_scalar_greater(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
654        ShortintEngine::with_thread_local_mut(|engine| {
655            engine.smart_scalar_greater(self, ct_left, scalar).unwrap()
656        })
657    }
658
659    /// Implements the "less" operator (`<`) between a ciphertext and a scalar without checks.
660    ///
661    /// # Example
662    ///
663    ///```rust
664    /// use concrete_shortint::gen_keys;
665    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
666    ///
667    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
668    ///
669    /// let msg_1 = 2;
670    /// let scalar = 2;
671    ///
672    /// // Encrypt two messages
673    /// let ct_left = cks.encrypt(msg_1);
674    ///
675    /// let ct_res = sks.smart_scalar_less(&ct_left, scalar);
676    ///
677    /// // Decrypt
678    /// let res = cks.decrypt(&ct_res);
679    /// assert_eq!(res, (msg_1 < scalar as u64) as u64);
680    /// ```
681    pub fn smart_scalar_less(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
682        ShortintEngine::with_thread_local_mut(|engine| {
683            engine.smart_scalar_less(self, ct_left, scalar).unwrap()
684        })
685    }
686}