concrete_core/backends/default/implementation/engines/default_engine/
lwe_ciphertext_fusing_addition.rs

1use crate::backends::default::implementation::engines::DefaultEngine;
2use crate::backends::default::implementation::entities::{LweCiphertext32, LweCiphertext64};
3use crate::specification::engines::{
4    LweCiphertextFusingAdditionEngine, LweCiphertextFusingAdditionError,
5};
6
7/// # Description:
8/// Implementation of [`LweCiphertextFusingAdditionEngine`] for [`DefaultEngine`] that operates on
9/// 32 bits integers.
10impl LweCiphertextFusingAdditionEngine<LweCiphertext32, LweCiphertext32> for DefaultEngine {
11    /// # Example:
12    /// ```
13    /// use concrete_core::prelude::{LweDimension, Variance, *};
14    /// # use std::error::Error;
15    ///
16    /// # fn main() -> Result<(), Box<dyn Error>> {
17    /// // DISCLAIMER: the parameters used here are only for test purpose, and are not secure.
18    /// let lwe_dimension = LweDimension(2);
19    /// // Here a hard-set encoding is applied (shift by 20 bits)
20    /// let input_1 = 3_u32 << 20;
21    /// let input_2 = 5_u32 << 20;
22    /// let noise = Variance(2_f64.powf(-25.));
23    ///
24    /// // Unix seeder must be given a secret input.
25    /// // Here we just give it 0, which is totally unsafe.
26    /// const UNSAFE_SECRET: u128 = 0;
27    /// let mut engine = DefaultEngine::new(Box::new(UnixSeeder::new(UNSAFE_SECRET)))?;
28    /// let key: LweSecretKey32 = engine.generate_new_lwe_secret_key(lwe_dimension)?;
29    /// let plaintext_1 = engine.create_plaintext_from(&input_1)?;
30    /// let plaintext_2 = engine.create_plaintext_from(&input_2)?;
31    /// let ciphertext_1 = engine.encrypt_lwe_ciphertext(&key, &plaintext_1, noise)?;
32    /// let mut ciphertext_2 = engine.encrypt_lwe_ciphertext(&key, &plaintext_2, noise)?;
33    ///
34    /// engine.fuse_add_lwe_ciphertext(&mut ciphertext_2, &ciphertext_1)?;
35    /// #
36    /// assert_eq!(ciphertext_2.lwe_dimension(), lwe_dimension);
37    ///
38    /// #
39    /// # Ok(())
40    /// # }
41    /// ```
42    fn fuse_add_lwe_ciphertext(
43        &mut self,
44        output: &mut LweCiphertext32,
45        input: &LweCiphertext32,
46    ) -> Result<(), LweCiphertextFusingAdditionError<Self::EngineError>> {
47        LweCiphertextFusingAdditionError::perform_generic_checks(output, input)?;
48        unsafe { self.fuse_add_lwe_ciphertext_unchecked(output, input) };
49        Ok(())
50    }
51
52    unsafe fn fuse_add_lwe_ciphertext_unchecked(
53        &mut self,
54        output: &mut LweCiphertext32,
55        input: &LweCiphertext32,
56    ) {
57        output.0.update_with_add(&input.0);
58    }
59}
60
61/// # Description:
62/// Implementation of [`LweCiphertextFusingAdditionEngine`] for [`DefaultEngine`] that operates on
63/// 64 bits integers.
64impl LweCiphertextFusingAdditionEngine<LweCiphertext64, LweCiphertext64> for DefaultEngine {
65    /// # Example:
66    /// ```
67    /// use concrete_core::prelude::{LweDimension, Variance, *};
68    /// # use std::error::Error;
69    ///
70    /// # fn main() -> Result<(), Box<dyn Error>> {
71    /// // DISCLAIMER: the parameters used here are only for test purpose, and are not secure.
72    /// let lwe_dimension = LweDimension(2);
73    /// // Here a hard-set encoding is applied (shift by 50 bits)
74    /// let input_1 = 3_u64 << 50;
75    /// let input_2 = 5_u64 << 50;
76    /// let noise = Variance(2_f64.powf(-25.));
77    ///
78    /// // Unix seeder must be given a secret input.
79    /// // Here we just give it 0, which is totally unsafe.
80    /// const UNSAFE_SECRET: u128 = 0;
81    /// let mut engine = DefaultEngine::new(Box::new(UnixSeeder::new(UNSAFE_SECRET)))?;
82    /// let key: LweSecretKey64 = engine.generate_new_lwe_secret_key(lwe_dimension)?;
83    /// let plaintext_1 = engine.create_plaintext_from(&input_1)?;
84    /// let plaintext_2 = engine.create_plaintext_from(&input_2)?;
85    /// let ciphertext_1 = engine.encrypt_lwe_ciphertext(&key, &plaintext_1, noise)?;
86    /// let mut ciphertext_2 = engine.encrypt_lwe_ciphertext(&key, &plaintext_2, noise)?;
87    ///
88    /// engine.fuse_add_lwe_ciphertext(&mut ciphertext_2, &ciphertext_1)?;
89    /// #
90    /// assert_eq!(ciphertext_2.lwe_dimension(), lwe_dimension);
91    ///
92    /// #
93    /// # Ok(())
94    /// # }
95    /// ```
96    fn fuse_add_lwe_ciphertext(
97        &mut self,
98        output: &mut LweCiphertext64,
99        input: &LweCiphertext64,
100    ) -> Result<(), LweCiphertextFusingAdditionError<Self::EngineError>> {
101        LweCiphertextFusingAdditionError::perform_generic_checks(output, input)?;
102        unsafe { self.fuse_add_lwe_ciphertext_unchecked(output, input) };
103        Ok(())
104    }
105
106    unsafe fn fuse_add_lwe_ciphertext_unchecked(
107        &mut self,
108        output: &mut LweCiphertext64,
109        input: &LweCiphertext64,
110    ) {
111        output.0.update_with_add(&input.0);
112    }
113}