pub struct ServerKey {
pub key_switching_key: LweKeyswitchKeyOwned<u64>,
pub bootstrapping_key: ShortintBootstrappingKey,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub max_degree: MaxDegree,
pub max_noise_level: MaxNoiseLevel,
pub ciphertext_modulus: CiphertextModulus,
pub pbs_order: PBSOrder,
}
shortint
only.Expand description
A structure containing the server public key.
The server key is generated by the client and is meant to be published: the client sends it to the server so it can compute homomorphic circuits.
Fields§
§key_switching_key: LweKeyswitchKeyOwned<u64>
§bootstrapping_key: ShortintBootstrappingKey
§message_modulus: MessageModulus
§carry_modulus: CarryModulus
§max_degree: MaxDegree
§max_noise_level: MaxNoiseLevel
§ciphertext_modulus: CiphertextModulus
§pbs_order: PBSOrder
Implementations§
Source§impl ServerKey
impl ServerKey
Sourcepub fn generate_oblivious_pseudo_random(
&self,
seed: Seed,
random_bits_count: u64,
) -> Ciphertext
pub fn generate_oblivious_pseudo_random( &self, seed: Seed, random_bits_count: u64, ) -> Ciphertext
Uniformly generates a random encrypted value in [0, 2^random_bits_count[
2^random_bits_count
must be smaller than the message modulus
The encryted value is oblivious to the server
Source§impl ServerKey
impl ServerKey
Sourcepub fn add(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn add(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically an addition between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an addition:
let ct_res = sks.add(&ct1, &ct2);
// Decrypt:
let two = cks.decrypt(&ct_res);
assert_eq!(msg + msg, two);
Sourcepub fn add_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn add_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Compute homomorphically an addition between two ciphertexts
The result is stored in the ct_left
ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let ct2 = cks.encrypt(msg2);
// Compute homomorphically an addition:
sks.add_assign(&mut ct1, &ct2);
// Decrypt:
let two = cks.decrypt(&ct1);
// 15 + 3 mod 4 -> 3 + 3 mod 4 -> 2 mod 4
let modulus = cks.parameters.message_modulus().0;
assert_eq!((msg2 + msg1) % modulus, two);
Sourcepub fn unchecked_add(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_add( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute homomorphically an addition between two ciphertexts encrypting integer values.
The result is returned in a new ciphertext.
This function computes the addition without checking if it exceeds the capacity of the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 1;
let msg2 = 2;
let ct1 = cks.encrypt(msg1);
let ct2 = cks.encrypt(msg2);
// Compute homomorphically an addition:
let ct_res = sks.unchecked_add(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg1 + msg2, res);
Sourcepub fn unchecked_add_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_add_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Compute homomorphically an addition between two ciphertexts encrypting integer values.
The result is stored in the ct_left
ciphertext.
This function computes the addition without checking if it exceeds the capacity of the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
let mut ct_left = cks.encrypt(msg);
let ct_right = cks.encrypt(msg);
// Compute homomorphically an addition:
sks.unchecked_add_assign(&mut ct_left, &ct_right);
// Decrypt:
let two = cks.decrypt(&ct_left);
assert_eq!(msg + msg, two);
Sourcepub fn is_add_possible(
&self,
ct_left: CiphertextNoiseDegree,
ct_right: CiphertextNoiseDegree,
) -> Result<(), CheckError>
pub fn is_add_possible( &self, ct_left: CiphertextNoiseDegree, ct_right: CiphertextNoiseDegree, ) -> Result<(), CheckError>
Verify if ct_left and ct_right can be added together.
This checks that the sum of their degree is smaller than the maximum degree.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2u64;
// Encrypt two messages:
let ct_left = cks.encrypt(msg);
let ct_right = cks.encrypt(msg);
// Check if we can perform an addition
sks.is_add_possible(ct_left.noise_degree(), ct_right.noise_degree())
.unwrap();
Sourcepub fn checked_add(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_add( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Compute homomorphically an addition between two ciphertexts encrypting integer values.
If the operation can be performed, the result is returned a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an addition:
let ct_res = sks.checked_add(&ct1, &ct2).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, msg + msg);
Sourcepub fn checked_add_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> Result<(), CheckError>
pub fn checked_add_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> Result<(), CheckError>
Compute homomorphically an addition between two ciphertexts encrypting integer values.
If the operation can be performed, the result is stored in the ct_left
ciphertext.
Otherwise a CheckError is returned, and ct_left
is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct_left = cks.encrypt(msg);
let ct_right = cks.encrypt(msg);
// Compute homomorphically an addition:
sks.checked_add_assign(&mut ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&ct_left);
assert_eq!(clear_res, msg + msg);
Sourcepub fn smart_add(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_add( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically an addition between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an addition:
let ct_res = sks.smart_add(&mut ct1, &mut ct2);
// Decrypt:
let two = cks.decrypt(&ct_res);
assert_eq!(msg + msg, two);
Sourcepub fn smart_add_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_add_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Compute homomorphically an addition between two ciphertexts
The result is stored in the ct_left
cipher text.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let mut ct2 = cks.encrypt(msg2);
// Compute homomorphically an addition:
sks.smart_add_assign(&mut ct1, &mut ct2);
// Decrypt:
let two = cks.decrypt(&ct1);
// 15 + 3 mod 4 -> 3 + 3 mod 4 -> 2 mod 4
let modulus = cks.parameters.message_modulus().0;
assert_eq!((msg2 + msg1) % modulus, two);
Source§impl ServerKey
impl ServerKey
Sourcepub fn bitand(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn bitand(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically an AND between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an AND:
let ct_res = sks.bitand(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg, res);
Sourcepub fn bitand_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn bitand_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Compute homomorphically an AND between two ciphertexts encrypting integer values.
The result is stored in the ct_left
cipher text.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let modulus = 4;
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let ct2 = cks.encrypt(msg2);
// Compute homomorphically an AND:
sks.bitand_assign(&mut ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct1);
assert_eq!((msg2 & msg1) % modulus, res);
Sourcepub fn unchecked_bitand(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_bitand( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute bitwise AND between two ciphertexts without checks.
The result is returned in a new ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 2;
let clear_2 = 1;
let ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
let ct_res = sks.unchecked_bitand(&ct_1, &ct_2);
let res = cks.decrypt(&ct_res);
assert_eq!(clear_1 & clear_2, res);
Sourcepub fn unchecked_bitand_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_bitand_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Compute bitwise AND between two ciphertexts without checks.
The result is assigned in the ct_left
ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
let mut ct_left = cks.encrypt(clear_1);
let ct_right = cks.encrypt(clear_2);
sks.unchecked_bitand_assign(&mut ct_left, &ct_right);
let res = cks.decrypt(&ct_left);
assert_eq!(clear_1 & clear_2, res);
Sourcepub fn checked_bitand(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_bitand( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Compute bitwise AND between two ciphertexts without checks.
If the operation can be performed, the result is returned a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an AND:
let ct_res = sks.checked_bitand(&ct1, &ct2).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, msg);
Sourcepub fn checked_bitand_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> Result<(), CheckError>
pub fn checked_bitand_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> Result<(), CheckError>
Compute bitwise AND between two ciphertexts without checks.
If the operation can be performed, the result is stored in the ct_left
ciphertext.
Otherwise a CheckError is returned, and ct_left
is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct_left = cks.encrypt(msg);
let ct_right = cks.encrypt(msg);
// Compute homomorphically an AND:
sks.checked_bitand_assign(&mut ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&ct_left);
assert_eq!(clear_res, msg);
Sourcepub fn smart_bitand(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_bitand( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically an AND between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an AND:
let ct_res = sks.smart_bitand(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg, res);
Sourcepub fn smart_bitand_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_bitand_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Compute homomorphically an AND between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
The result is stored in the ct_left
cipher text.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let modulus = 4;
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let mut ct2 = cks.encrypt(msg2);
// Compute homomorphically an AND:
sks.smart_bitand_assign(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct1);
assert_eq!((msg2 & msg1) % modulus, res);
Sourcepub fn bitxor(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn bitxor(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically an XOR between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically a XOR:
let ct_res = sks.bitxor(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn bitxor_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn bitxor_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Compute homomorphically a XOR between two ciphertexts encrypting integer values.
The result is stored in the ct_left
cipher text.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let modulus = 4;
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let ct2 = cks.encrypt(msg2);
// Compute homomorphically a XOR:
sks.bitxor_assign(&mut ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct1);
assert_eq!((msg2 ^ msg1) % modulus, res);
Sourcepub fn unchecked_bitxor(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_bitxor( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute bitwise XOR between two ciphertexts without checks.
The result is returned in a new ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(clear_1);
let ct_right = cks.encrypt(clear_2);
let ct_res = sks.unchecked_bitxor(&ct_left, &ct_right);
let res = cks.decrypt(&ct_res);
assert_eq!(clear_1 ^ clear_2, res);
Sourcepub fn unchecked_bitxor_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_bitxor_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Compute bitwise XOR between two ciphertexts without checks.
The result is assigned in the ct_left
ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 2;
let clear_2 = 0;
// Encrypt two messages
let mut ct_left = cks.encrypt(clear_1);
let ct_right = cks.encrypt(clear_2);
sks.unchecked_bitxor_assign(&mut ct_left, &ct_right);
let res = cks.decrypt(&ct_left);
assert_eq!(clear_1 ^ clear_2, res);
Sourcepub fn checked_bitxor(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_bitxor( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Compute bitwise XOR between two ciphertexts without checks.
If the operation can be performed, the result is returned a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically a xor:
let ct_res = sks.checked_bitxor(&ct1, &ct2).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, 0);
Sourcepub fn checked_bitxor_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> Result<(), CheckError>
pub fn checked_bitxor_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> Result<(), CheckError>
Compute bitwise XOR between two ciphertexts without checks.
If the operation can be performed, the result is stored in the ct_left
ciphertext.
Otherwise a CheckError is returned, and ct_left
is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct_left = cks.encrypt(msg);
let ct_right = cks.encrypt(msg);
// Compute homomorphically a xor:
sks.checked_bitxor_assign(&mut ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&ct_left);
assert_eq!(clear_res, 0);
Sourcepub fn smart_bitxor(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_bitxor( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically an XOR between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically a XOR:
let ct_res = sks.smart_bitxor(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn smart_bitxor_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_bitxor_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Compute homomorphically a XOR between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
The result is stored in the ct_left
cipher text.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let modulus = 4;
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let mut ct2 = cks.encrypt(msg2);
// Compute homomorphically a XOR:
sks.smart_bitxor_assign(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct1);
assert_eq!((msg2 ^ msg1) % modulus, res);
Sourcepub fn bitor(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn bitor(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically an OR between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.bitor(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg, res);
Sourcepub fn bitor_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn bitor_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Compute homomorphically an OR between two ciphertexts encrypting integer values.
The result is stored in the ct_left
cipher text.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let modulus = 4;
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let ct2 = cks.encrypt(msg2);
// Compute homomorphically an OR:
sks.bitor_assign(&mut ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct1);
assert_eq!((msg2 | msg1) % modulus, res);
Sourcepub fn unchecked_bitor(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_bitor( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute bitwise OR between two ciphertexts.
The result is returned in a new ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_left = 1;
let clear_right = 2;
// Encrypt two messages
let ct_left = cks.encrypt(clear_left);
let ct_right = cks.encrypt(clear_right);
let ct_res = sks.unchecked_bitor(&ct_left, &ct_right);
let res = cks.decrypt(&ct_res);
assert_eq!(clear_left | clear_right, res);
Sourcepub fn unchecked_bitor_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_bitor_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Compute bitwise OR between two ciphertexts.
The result is assigned in the ct_left
ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_left = 2;
let clear_right = 1;
// Encrypt two messages
let mut ct_left = cks.encrypt(clear_left);
let ct_right = cks.encrypt(clear_right);
sks.unchecked_bitor_assign(&mut ct_left, &ct_right);
let res = cks.decrypt(&ct_left);
assert_eq!(clear_left | clear_right, res);
Sourcepub fn checked_bitor(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_bitor( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Compute bitwise OR between two ciphertexts without checks.
If the operation can be performed, the result is returned a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically a or:
let ct_res = sks.checked_bitor(&ct1, &ct2).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, msg);
Sourcepub fn checked_bitor_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> Result<(), CheckError>
pub fn checked_bitor_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> Result<(), CheckError>
Compute bitwise OR between two ciphertexts without checks.
If the operation can be performed, the result is stored in the ct_left
ciphertext.
Otherwise a CheckError is returned, and ct_left
is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct_left = cks.encrypt(msg);
let ct_right = cks.encrypt(msg);
// Compute homomorphically an or:
sks.checked_bitor_assign(&mut ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&ct_left);
assert_eq!(clear_res, msg);
Sourcepub fn smart_bitor(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_bitor( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically an OR between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_bitor(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg, res);
Sourcepub fn smart_bitor_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_bitor_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Compute homomorphically an OR between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
The result is stored in the ct_left
cipher text.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let modulus = 4;
let msg1 = 15;
let msg2 = 3;
// Encrypt two messages:
let mut ct1 = cks.unchecked_encrypt(msg1);
let mut ct2 = cks.encrypt(msg2);
// Compute homomorphically an OR:
sks.smart_bitor_assign(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct1);
assert_eq!((msg2 | msg1) % modulus, res);
pub fn bitnot_assign(&self, ct: &mut Ciphertext)
pub fn bitnot(&self, ct: &Ciphertext) -> Ciphertext
Source§impl ServerKey
impl ServerKey
Sourcepub fn generate_lookup_table_bivariate_with_factor<F>(
&self,
f: F,
left_message_scaling: MessageModulus,
) -> BivariateLookupTableOwned
pub fn generate_lookup_table_bivariate_with_factor<F>( &self, f: F, left_message_scaling: MessageModulus, ) -> BivariateLookupTableOwned
Generates a bivariate accumulator
Sourcepub fn generate_lookup_table_bivariate<F>(
&self,
f: F,
) -> BivariateLookupTableOwned
pub fn generate_lookup_table_bivariate<F>( &self, f: F, ) -> BivariateLookupTableOwned
Constructs the lookup table for a given bivariate function as input.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 3;
let msg_2 = 2;
let ct1 = cks.encrypt(msg_1);
let ct2 = cks.encrypt(msg_2);
let f = |x, y| (x + y) % 4;
let acc = sks.generate_lookup_table_bivariate(f);
let ct_res = sks.apply_lookup_table_bivariate(&ct1, &ct2, &acc);
let dec = cks.decrypt(&ct_res);
assert_eq!(dec, f(msg_1, msg_2));
Sourcepub fn unchecked_apply_lookup_table_bivariate(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
acc: &BivariateLookupTableOwned,
) -> Ciphertext
pub fn unchecked_apply_lookup_table_bivariate( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, acc: &BivariateLookupTableOwned, ) -> Ciphertext
Compute a keyswitch and programmable bootstrap.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg: u64 = 3;
let msg2: u64 = 2;
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg2);
let modulus = cks.parameters.message_modulus().0;
// Generate the lookup table for the function f: x, y -> (x * y * x) mod 4
let acc = sks.generate_lookup_table_bivariate(|x, y| x * y * x % modulus);
let ct_res = sks.unchecked_apply_lookup_table_bivariate(&ct1, &ct2, &acc);
let dec = cks.decrypt(&ct_res);
assert_eq!(dec, (msg * msg2 * msg) % modulus);
pub fn unchecked_apply_lookup_table_bivariate_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, acc: &BivariateLookupTableOwned, )
Sourcepub fn apply_lookup_table_bivariate(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
acc: &BivariateLookupTableOwned,
) -> Ciphertext
pub fn apply_lookup_table_bivariate( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, acc: &BivariateLookupTableOwned, ) -> Ciphertext
Compute a keyswitch and programmable bootstrap.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg: u64 = 3;
let msg2: u64 = 2;
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg2);
let modulus = cks.parameters.message_modulus().0;
// Generate the lookup table for the function f: x, y -> (x * y * x) mod 4
let acc = sks.generate_lookup_table_bivariate(|x, y| x * y * x % modulus);
let ct_res = sks.apply_lookup_table_bivariate(&ct1, &ct2, &acc);
let dec = cks.decrypt(&ct_res);
assert_eq!(dec, (msg * msg2 * msg) % modulus);
pub fn apply_lookup_table_bivariate_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, acc: &BivariateLookupTableOwned, )
Sourcepub fn unchecked_evaluate_bivariate_function<F>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
f: F,
) -> Ciphertext
pub fn unchecked_evaluate_bivariate_function<F>( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, f: F, ) -> Ciphertext
Generic programmable bootstrap where messages are concatenated into one ciphertext to evaluate a bivariate function. This is used to apply many binary operations (comparisons, multiplications, division).
pub fn unchecked_evaluate_bivariate_function_assign<F>( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, f: F, )
Sourcepub fn is_functional_bivariate_pbs_possible(
&self,
ct1: CiphertextNoiseDegree,
ct2: CiphertextNoiseDegree,
lut: Option<&BivariateLookupTableOwned>,
) -> Result<(), CheckError>
pub fn is_functional_bivariate_pbs_possible( &self, ct1: CiphertextNoiseDegree, ct2: CiphertextNoiseDegree, lut: Option<&BivariateLookupTableOwned>, ) -> Result<(), CheckError>
Verify if a functional bivariate pbs can be applied on ct_left and ct_right. If the bivariate lookup table is already built, it must be passed to do the check with the correct scale. If the bivariate lookup table is going to be built (if this function returns true) assuming ct1 is going to be scaled by ct2.degree+1, None must be passed.
pub fn smart_evaluate_bivariate_function_assign<F>( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, f: F, )
pub fn smart_evaluate_bivariate_function<F>( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, f: F, ) -> Ciphertext
Source§impl ServerKey
impl ServerKey
Sourcepub fn greater(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn greater(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically a >
between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.greater(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn unchecked_greater(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_greater( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Implement the “greater” (>
) operator between two ciphertexts without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let ct_res = sks.unchecked_greater(&ct_left, &ct_right);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!((msg_1 > msg_2) as u64, res);
Sourcepub fn checked_greater(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_greater( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Implement the “greater” (>
) operator between two ciphertexts with checks.
If the operation can be performed, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages:
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let res = sks.checked_greater(&ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&res);
assert_eq!((msg_1 > msg_2) as u64, clear_res);
Sourcepub fn smart_greater(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_greater( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a >
between two ciphertexts encrypting integer values.
This checks that the operation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_greater(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn greater_or_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn greater_or_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute homomorphically a >=
between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.greater_or_equal(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn unchecked_greater_or_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_greater_or_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Implement the “greater or equal” (>=
) operator between two ciphertexts without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let ct_res = sks.unchecked_greater_or_equal(&ct_left, &ct_right);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!((msg_1 >= msg_2) as u64, res);
Sourcepub fn smart_greater_or_equal(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_greater_or_equal( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a >=
between two ciphertexts encrypting integer values.
This checks that the operation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_greater_or_equal(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn checked_greater_or_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_greater_or_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Implement the “greater or equal” (>=
) operator between two ciphertexts with checks.
If the operation can be performed, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages:
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let res = sks.checked_greater_or_equal(&ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&res);
assert_eq!((msg_1 >= msg_2) as u64, clear_res);
Sourcepub fn less(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn less(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically a <
between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.less(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn unchecked_less(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_less( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Implement the “less” (<
) operator between two ciphertexts without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
// Do the comparison
let ct_res = sks.unchecked_less(&ct_left, &ct_right);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!((msg_1 < msg_2) as u64, res);
Sourcepub fn checked_less(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_less( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Implement the “less” (<
) operator between two ciphertexts with checks.
If the operation can be performed, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages:
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let res = sks.checked_less(&ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&res);
assert_eq!((msg_1 < msg_2) as u64, clear_res);
Sourcepub fn smart_less(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_less( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a <
between two ciphertexts encrypting integer values.
This checks that the operation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_less(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn less_or_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn less_or_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute homomorphically a <=
between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.less_or_equal(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn unchecked_less_or_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_less_or_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Implement the “less or equal” (<=
) between two ciphertexts operator without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let ct_res = sks.unchecked_less_or_equal(&ct_left, &ct_right);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!((msg_1 <= msg_2) as u64, res);
Sourcepub fn checked_less_or_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_less_or_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Implement the “less or equal” (<=
) operator between two ciphertexts with checks.
If the operation can be performed, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages:
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let res = sks.checked_less_or_equal(&ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&res);
assert_eq!((msg_1 <= msg_2) as u64, clear_res);
Sourcepub fn smart_less_or_equal(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_less_or_equal( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a <=
between two ciphertexts encrypting integer values.
This checks that the operation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_less_or_equal(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn equal(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn equal(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically a ==
between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.equal(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn unchecked_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Implement the “equal” operator (==
) between two ciphertexts without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let msg_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let ct_res = sks.unchecked_equal(&ct_left, &ct_right);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, 1);
Sourcepub fn checked_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Implement the “equal” (==
) operator between two ciphertexts with checks.
If the operation can be performed, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages:
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let res = sks.checked_equal(&ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&res);
assert_eq!((msg_1 == msg_2) as u64, clear_res);
Sourcepub fn smart_equal(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_equal( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a ==
between two ciphertexts encrypting integer values.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_equal(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn not_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn not_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute homomorphically a !=
between two ciphertexts encrypting integer values.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let ct1 = cks.encrypt(msg);
let ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.not_equal(&ct1, &ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn unchecked_not_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_not_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Implement the “not equal” operator (!=
) between two ciphertexts without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let ct_res = sks.unchecked_not_equal(&ct_left, &ct_right);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, 1);
Sourcepub fn checked_not_equal(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_not_equal( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Implement the “not equal” (!=
) operator between two ciphertexts with checks.
If the operation can be performed, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 1;
let msg_2 = 2;
// Encrypt two messages:
let ct_left = cks.encrypt(msg_1);
let ct_right = cks.encrypt(msg_2);
let res = sks.checked_not_equal(&ct_left, &ct_right).unwrap();
let clear_res = cks.decrypt(&res);
assert_eq!((msg_1 != msg_2) as u64, clear_res);
Sourcepub fn smart_not_equal(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_not_equal( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a !=
between two ciphertexts encrypting integer values.
This checks that the operation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt two messages:
let mut ct1 = cks.encrypt(msg);
let mut ct2 = cks.encrypt(msg);
// Compute homomorphically an OR:
let ct_res = sks.smart_not_equal(&mut ct1, &mut ct2);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(0, res);
Sourcepub fn smart_scalar_equal(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn smart_scalar_equal( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Implement the “equal” operator (==
) between a ciphertext and a scalar without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let scalar = 2;
// Encrypt our message
let mut ct_left = cks.encrypt(msg_1);
let ct_res = sks.smart_scalar_equal(&mut ct_left, scalar);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, (msg_1 == scalar as u64) as u64);
Sourcepub fn scalar_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
Equality between a ciphertext and a clear
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
Sourcepub fn smart_scalar_not_equal(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn smart_scalar_not_equal( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Implement the “not equal” operator (!=
) between a ciphertext and a scalar without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let scalar = 2;
// Encrypt our message
let mut ct_left = cks.encrypt(msg_1);
let ct_res = sks.smart_scalar_not_equal(&mut ct_left, scalar);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, (msg_1 != scalar as u64) as u64);
Sourcepub fn scalar_not_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_not_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
Difference between a ciphertext and a clear
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
Sourcepub fn smart_scalar_greater_or_equal(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn smart_scalar_greater_or_equal( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Implement the “greater or equal” operator (>=
) between a ciphertext and a scalar without
checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let scalar = 2;
// Encrypt our message
let mut ct_left = cks.encrypt(msg_1);
let ct_res = sks.smart_scalar_greater_or_equal(&mut ct_left, scalar);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, (msg_1 >= scalar as u64) as u64);
Sourcepub fn scalar_greater_or_equal(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn scalar_greater_or_equal( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Alias of smart_scalar_greater_or_equal
provided
for convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
Sourcepub fn smart_scalar_less_or_equal(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn smart_scalar_less_or_equal( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Implement the “less or equal” operator (<=
) between a ciphertext and a scalar without
checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let scalar = 2;
// Encrypt our message
let mut ct_left = cks.encrypt(msg_1);
let ct_res = sks.smart_scalar_less_or_equal(&mut ct_left, scalar);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, (msg_1 <= scalar as u64) as u64);
Sourcepub fn scalar_less_or_equal(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn scalar_less_or_equal( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Alias of smart_scalar_less_or_equal
provided for
convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
Sourcepub fn smart_scalar_greater(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn smart_scalar_greater( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Implement the “greater” operator (>
) between a ciphertext and a scalar without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let scalar = 2;
// Encrypt our message
let mut ct_left = cks.encrypt(msg_1);
let ct_res = sks.smart_scalar_greater(&mut ct_left, scalar);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, (msg_1 > scalar as u64) as u64);
Sourcepub fn scalar_greater(&self, ct_left: &mut Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_greater(&self, ct_left: &mut Ciphertext, scalar: u8) -> Ciphertext
Alias of smart_scalar_greater
provided for convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
Sourcepub fn smart_scalar_less(
&self,
ct_left: &mut Ciphertext,
scalar: u8,
) -> Ciphertext
pub fn smart_scalar_less( &self, ct_left: &mut Ciphertext, scalar: u8, ) -> Ciphertext
Implement the “less” operator (<
) between a ciphertext and a scalar without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let scalar = 2;
// Encrypt our message
let mut ct_left = cks.encrypt(msg_1);
let ct_res = sks.smart_scalar_less(&mut ct_left, scalar);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(res, (msg_1 < scalar as u64) as u64);
Sourcepub fn scalar_less(&self, ct_left: &mut Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_less(&self, ct_left: &mut Ciphertext, scalar: u8) -> Ciphertext
Alias of smart_scalar_less
provided for convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
Source§impl ServerKey
impl ServerKey
Sourcepub fn div(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn div(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute a division between two ciphertexts.
The result is returned in a new ciphertext.
§Warning
/!\ A division by zero returns the input ciphertext maximum message value! For 2 bits of message it will therefore return 3.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
let ct_res = sks.div(&ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(clear_1 / clear_2, res);
Sourcepub fn div_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn div_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Compute a division between two ciphertexts.
The result is returned in a new ciphertext.
§Warning
/!\ A division by zero returns the input ciphertext maximum message value! For 2 bits of message it will therefore return 3.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let mut ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
sks.div_assign(&mut ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_1);
assert_eq!(clear_1 / clear_2, res);
Sourcepub fn unchecked_div(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_div( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Compute a division between two ciphertexts without checks.
The result is returned in a new ciphertext.
§Warning
/!\ A division by zero returns the input ciphertext maximum message value! For 2 bits of message it will therefore return 3.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
let ct_res = sks.unchecked_div(&ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(clear_1 / clear_2, res);
Sourcepub fn unchecked_div_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_div_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Compute a division between two ciphertexts without checks.
The result is assigned in ct_left
.
§Warning
/!\ A division by zero returns the input ciphertext maximum message value! For 2 bits of message it will therefore return 3.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let mut ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
sks.unchecked_div_assign(&mut ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_1);
assert_eq!(clear_1 / clear_2, res);
Sourcepub fn smart_div(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_div( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute a division between two ciphertexts.
The result is returned in a new ciphertext.
§Warning
/!\ A division by zero returns the input ciphertext maximum message value! For 2 bits of message it will therefore return 3.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let mut ct_1 = cks.encrypt(clear_1);
let mut ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
let ct_res = sks.smart_div(&mut ct_1, &mut ct_2);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(clear_1 / clear_2, res);
Sourcepub fn smart_div_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_div_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Compute a division between two ciphertexts without checks.
The result is assigned in ct_left
.
§Warning
/!\ A division by zero returns the input ciphertext maximum message value! For 2 bits of message it will therefore return 3.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 3;
let clear_2 = 2;
// Encrypt two messages
let mut ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
sks.unchecked_div_assign(&mut ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_1);
assert_eq!(clear_1 / clear_2, res);
Source§impl ServerKey
impl ServerKey
Sourcepub fn switch_modulus_and_compress(
&self,
ct: &Ciphertext,
) -> CompressedModulusSwitchedCiphertext
pub fn switch_modulus_and_compress( &self, ct: &Ciphertext, ) -> CompressedModulusSwitchedCiphertext
Compresses a ciphertext to have a smaller serialization size
See CompressedModulusSwitchedCiphertext
for usage
Sourcepub fn decompress(
&self,
compressed_ct: &CompressedModulusSwitchedCiphertext,
) -> Ciphertext
pub fn decompress( &self, compressed_ct: &CompressedModulusSwitchedCiphertext, ) -> Ciphertext
Decompresses a compressed ciphertext
The degree from before the compression is conserved.
This operation uses a PBS. For the same cost, it’s possible to apply a lookup table by
calling decompress_and_apply_lookup_table
instead.
See CompressedModulusSwitchedCiphertext
for usage
Sourcepub fn decompress_and_apply_lookup_table(
&self,
compressed_ct: &CompressedModulusSwitchedCiphertext,
acc: &LookupTableOwned,
) -> Ciphertext
pub fn decompress_and_apply_lookup_table( &self, compressed_ct: &CompressedModulusSwitchedCiphertext, acc: &LookupTableOwned, ) -> Ciphertext
Decompresses a compressed ciphertext
This operation uses a PBS so we can apply a lookup table
An identity lookup table may be applied to get the pre compression ciphertext with a nominal
noise, however, it’s better to call decompress
for that because it conserves the degree
instead of setting it to the max of the lookup table
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear = 3;
let ctxt = cks.unchecked_encrypt(clear);
// Can be serialized in a smaller buffer
let compressed_ct = sks.switch_modulus_and_compress(&ctxt);
let lut = sks.generate_lookup_table(|a| a + 1);
let decompressed_ct = sks.decompress_and_apply_lookup_table(&compressed_ct, &lut);
let dec = cks.decrypt_message_and_carry(&decompressed_ct);
assert_eq!(clear + 1, dec);
Source§impl ServerKey
impl ServerKey
Sourcepub fn unchecked_mul_lsb(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_mul_lsb( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Multiply two ciphertexts together without checks.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
The result is returned in a new ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 1;
// Encrypt two messages
let ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
let ct_res = sks.unchecked_mul_lsb(&ct_1, &ct_2);
// 2*3 == 6 == 01_10 (base 2)
// Only the message part is returned (lsb) so `ct_res` is:
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Decrypt
let res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!((clear_1 * clear_2) % modulus, res);
Sourcepub fn unchecked_mul_lsb_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_mul_lsb_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Multiply two ciphertexts together without checks.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
The result is assigned in the first ciphertext
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 3;
let clear_2 = 2;
// Encrypt two messages
let mut ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
sks.unchecked_mul_lsb_assign(&mut ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_1);
let modulus = cks.parameters.message_modulus().0;
assert_eq!((clear_1 * clear_2) % modulus, res);
Sourcepub fn unchecked_mul_msb(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_mul_msb( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Multiply two ciphertexts together without checks.
Return the “most significant bits” of the multiplication, i.e., the part in the carry buffer.
The result is returned in a new ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 3;
let clear_2 = 2;
// Encrypt two messages
let ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
let ct_res = sks.unchecked_mul_msb(&ct_1, &ct_2);
// 2*3 == 6 == 01_10 (base 2)
// however the ciphertext will contain only the carry buffer
// as the message, the ct_res is actually:
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt
let res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!((clear_1 * clear_2) / modulus, res);
pub fn unchecked_mul_msb_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Sourcepub fn is_mul_possible(
&self,
ct1: CiphertextNoiseDegree,
ct2: CiphertextNoiseDegree,
) -> Result<(), CheckError>
pub fn is_mul_possible( &self, ct1: CiphertextNoiseDegree, ct2: CiphertextNoiseDegree, ) -> Result<(), CheckError>
Verify if two ciphertexts can be multiplied together.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt two messages:
let ct_1 = cks.encrypt(msg);
let ct_2 = cks.encrypt(msg);
// Check if we can perform a multiplication
sks.is_mul_possible(ct_1.noise_degree(), ct_2.noise_degree())
.unwrap();
Sourcepub fn checked_mul_lsb(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_mul_lsb( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Multiply two ciphertexts together with checks.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
If the operation can be performed, a new ciphertext with the result is returned. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let ct_1 = cks.encrypt(2);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a multiplication:
let ct_res = sks.checked_mul_lsb(&ct_1, &ct_2).unwrap();
let clear_res = cks.decrypt_message_and_carry(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res % modulus, 2);
Sourcepub fn checked_mul_lsb_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> Result<(), CheckError>
pub fn checked_mul_lsb_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> Result<(), CheckError>
Multiply two ciphertexts together with checks.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
If the operation can be performed, the result is assigned to the first ciphertext given as a parameter. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let mut ct_1 = cks.encrypt(2);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a multiplication:
sks.checked_mul_lsb_assign(&mut ct_1, &ct_2).unwrap();
let clear_res = cks.decrypt_message_and_carry(&ct_1);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res % modulus, 2);
Sourcepub fn checked_mul_msb(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_mul_msb( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Multiply two ciphertexts together without checks.
Return the “most significant bits” of the multiplication, i.e., the part in the carry buffer.
If the operation can be performed, a new ciphertext with the result is returned. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let msg_2 = 2;
// Encrypt two messages:
let ct_1 = cks.encrypt(msg_1);
let ct_2 = cks.encrypt(msg_2);
// Compute homomorphically a multiplication:
let ct_res = sks.checked_mul_msb(&ct_1, &ct_2).unwrap();
// 2*2 == 4 == 01_00 (base 2)
// however the ciphertext will contain only the carry buffer
// as the message, the ct_res is actually:
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
let clear_res = cks.decrypt(&ct_res);
assert_eq!(
clear_res,
(msg_1 * msg_2) / cks.parameters.message_modulus().0
);
Sourcepub fn unchecked_mul_lsb_small_carry(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_mul_lsb_small_carry( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Multiply two ciphertexts together using one bit of carry only.
The algorithm uses the (.)^2/4 trick. For more information: page 4, §Computing a multiplication in Chillotti, I., Joye, M., Ligier, D., Orfila, J. B., & Tap, S. (2020, December). CONCRETE: Concrete operates on ciphertexts rapidly by extending TfhE. In WAHC 2020–8th Workshop on Encrypted Computing & Applied Homomorphic Cryptography (Vol. 15).
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 1;
// Encrypt two messages
let ct_1 = cks.encrypt(clear_1);
let ct_2 = cks.encrypt(clear_2);
// Compute homomorphically a multiplication
let ct_res = sks.unchecked_mul_lsb_small_carry(&ct_1, &ct_2);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!((clear_2 * clear_1), res);
pub fn unchecked_mul_lsb_small_carry_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Sourcepub fn is_mul_small_carry_possible(
&self,
ct_left: CiphertextNoiseDegree,
ct_right: CiphertextNoiseDegree,
) -> Result<(), CheckError>
pub fn is_mul_small_carry_possible( &self, ct_left: CiphertextNoiseDegree, ct_right: CiphertextNoiseDegree, ) -> Result<(), CheckError>
Verify if two ciphertexts can be multiplied together in the case where the carry modulus is smaller than the message modulus.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::v1_0::V1_0_PARAM_MESSAGE_2_CARRY_1_KS_PBS_GAUSSIAN_2M128;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(V1_0_PARAM_MESSAGE_2_CARRY_1_KS_PBS_GAUSSIAN_2M128);
let msg = 2;
// Encrypt two messages:
let ct_1 = cks.encrypt(msg);
let ct_2 = cks.encrypt(msg);
// Check if we can perform a multiplication
sks.is_mul_small_carry_possible(ct_1.noise_degree(), ct_2.noise_degree())
.unwrap();
//Encryption with a full carry buffer
let large_msg = 7;
let ct_3 = cks.unchecked_encrypt(large_msg);
// Check if we can perform a multiplication
let res = sks.is_mul_small_carry_possible(ct_1.noise_degree(), ct_3.noise_degree());
assert!(res.is_err());
// Encrypt two messages:
let ct_1 = cks.encrypt(msg);
let ct_2 = cks.encrypt(msg);
// Check if we can perform a multiplication
sks.is_mul_small_carry_possible(ct_1.noise_degree(), ct_2.noise_degree())
.unwrap();
//Encryption with a full carry buffer
let large_msg = 7;
let ct_3 = cks.unchecked_encrypt(large_msg);
// Check if we can perform a multiplication
let res = sks.is_mul_small_carry_possible(ct_1.noise_degree(), ct_3.noise_degree());
assert!(res.is_err());
Sourcepub fn checked_mul_lsb_with_small_carry(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_mul_lsb_with_small_carry( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Compute homomorphically a multiplication between two ciphertexts encrypting integer values.
The operation is done using a small carry buffer.
If the operation can be performed, a new ciphertext with the result of the multiplication is returned. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg_1 = 2;
let msg_2 = 3;
// Encrypt two messages:
let ct_1 = cks.encrypt(msg_1);
let ct_2 = cks.encrypt(msg_2);
// Compute homomorphically a multiplication
let ct_res = sks.checked_mul_lsb_with_small_carry(&ct_1, &ct_2).unwrap();
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res % modulus, (msg_1 * msg_2) % modulus);
Sourcepub fn mul_lsb(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn mul_lsb(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Multiply two ciphertexts together
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 13;
// Encrypt two messages:
let ct_left = cks.unchecked_encrypt(msg1);
// | ct_left |
// | carry | message |
// |-------|---------|
// | 1 1 | 0 0 |
let ct_right = cks.unchecked_encrypt(msg2);
// | ct_right |
// | carry | message |
// |-------|---------|
// | 1 1 | 0 1 |
// Compute homomorphically a multiplication:
let ct_res = sks.mul_lsb(&ct_left, &ct_right);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 0 |
let res = cks.decrypt(&ct_res);
let modulus = sks.message_modulus.0;
assert_eq!(res, (msg1 * msg2) % modulus);
Sourcepub fn mul(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn mul(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Multiply two ciphertexts together
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 13;
// Encrypt two messages:
let ct_left = cks.unchecked_encrypt(msg1);
// | ct_left |
// | carry | message |
// |-------|---------|
// | 1 1 | 0 0 |
let ct_right = cks.unchecked_encrypt(msg2);
// | ct_right |
// | carry | message |
// |-------|---------|
// | 1 1 | 0 1 |
// Compute homomorphically a multiplication:
let ct_res = sks.mul(&ct_left, &ct_right);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 0 |
let res = cks.decrypt(&ct_res);
let modulus = sks.message_modulus.0;
assert_eq!(res, (msg1 * msg2) % modulus);
Sourcepub fn mul_lsb_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn mul_lsb_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Multiply two ciphertexts.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
The result is assigned in the first ciphertext
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128);
let msg1 = 5;
let msg2 = 3;
// Encrypt two messages:
let mut ct_1 = cks.unchecked_encrypt(msg1);
let ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication
sks.mul_lsb_assign(&mut ct_1, &ct_2);
let res = cks.decrypt(&ct_1);
let modulus = sks.message_modulus.0;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);
Sourcepub fn mul_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn mul_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Multiply two ciphertexts.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
The result is assigned in the first ciphertext
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128);
let msg1 = 5;
let msg2 = 3;
// Encrypt two messages:
let mut ct_1 = cks.unchecked_encrypt(msg1);
let ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication
sks.mul_assign(&mut ct_1, &ct_2);
let res = cks.decrypt(&ct_1);
let modulus = sks.message_modulus.0;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);
Sourcepub fn mul_msb_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn mul_msb_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Multiply two ciphertexts together
Return the “most significant bits” of the multiplication, i.e., the part in the carry buffer.
The result is assigned in the first ciphertext
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 12;
// Encrypt two messages:
let mut ct_1 = cks.unchecked_encrypt(msg1);
let ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication:
sks.mul_msb_assign(&mut ct_1, &ct_2);
let res = cks.decrypt(&ct_1);
let modulus = sks.message_modulus.0;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
Sourcepub fn mul_msb(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn mul_msb(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Multiply two ciphertexts together
Return the “most significant bits” of the multiplication, i.e., the part in the carry buffer.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 12;
// Encrypt two messages:
let ct_1 = cks.unchecked_encrypt(msg1);
let ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication:
let ct_res = sks.mul_msb(&ct_1, &ct_2);
let res = cks.decrypt(&ct_res);
let modulus = sks.message_modulus.0;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
Sourcepub fn smart_mul_lsb_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_mul_lsb_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Multiply two ciphertexts.
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
The result is assigned in the first ciphertext
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M128);
let msg1 = 5;
let msg2 = 3;
// Encrypt two messages:
let mut ct_1 = cks.unchecked_encrypt(msg1);
let mut ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication
sks.smart_mul_lsb_assign(&mut ct_1, &mut ct_2);
let res = cks.decrypt(&ct_1);
let modulus = sks.message_modulus.0;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);
Sourcepub fn smart_mul_msb_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_mul_msb_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Multiply two ciphertexts together
Return the “most significant bits” of the multiplication, i.e., the part in the carry buffer.
The result is assigned in the first ciphertext
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 12;
// Encrypt two messages:
let mut ct_1 = cks.unchecked_encrypt(msg1);
let mut ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication:
sks.smart_mul_msb_assign(&mut ct_1, &mut ct_2);
let res = cks.decrypt(&ct_1);
let modulus = sks.message_modulus.0;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
Sourcepub fn smart_mul_lsb(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_mul_lsb( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Multiply two ciphertexts together
Return the “least significant bits” of the multiplication, i.e., the result modulus the message_modulus.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 13;
// Encrypt two messages:
let mut ct_left = cks.unchecked_encrypt(msg1);
// | ct_left |
// | carry | message |
// |-------|---------|
// | 1 1 | 0 0 |
let mut ct_right = cks.unchecked_encrypt(msg2);
// | ct_right |
// | carry | message |
// |-------|---------|
// | 1 1 | 0 1 |
// Compute homomorphically a multiplication:
let ct_res = sks.smart_mul_lsb(&mut ct_left, &mut ct_right);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 0 |
let res = cks.decrypt(&ct_res);
let modulus = sks.message_modulus.0;
assert_eq!(res, (msg1 * msg2) % modulus);
Sourcepub fn smart_mul_msb(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_mul_msb( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Multiply two ciphertexts together
Return the “most significant bits” of the multiplication, i.e., the part in the carry buffer.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 12;
let msg2 = 12;
// Encrypt two messages:
let mut ct_1 = cks.unchecked_encrypt(msg1);
let mut ct_2 = cks.unchecked_encrypt(msg2);
// Compute homomorphically a multiplication:
let ct_res = sks.smart_mul_msb(&mut ct_1, &mut ct_2);
let res = cks.decrypt(&ct_res);
let modulus = sks.message_modulus.0;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
Source§impl ServerKey
impl ServerKey
Sourcepub fn neg(&self, ct: &Ciphertext) -> Ciphertext
pub fn neg(&self, ct: &Ciphertext) -> Ciphertext
Compute homomorphically a negation of a ciphertext.
This checks that the negation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
// Encrypt a message
let ct = cks.encrypt(msg);
// Compute homomorphically a negation
let ct_res = sks.neg(&ct);
// Decrypt
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res, modulus - msg);
Sourcepub fn neg_assign(&self, ct: &mut Ciphertext)
pub fn neg_assign(&self, ct: &mut Ciphertext)
Compute homomorphically a negation of a ciphertext.
This checks that the negation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a negation
sks.neg_assign(&mut ct);
// Decrypt
let clear_res = cks.decrypt(&ct);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res, modulus - msg);
Sourcepub fn unchecked_neg(&self, ct: &Ciphertext) -> Ciphertext
pub fn unchecked_neg(&self, ct: &Ciphertext) -> Ciphertext
Homomorphically negates a message without checks.
Negation here means the opposite value in the modulo set.
This function computes the opposite of a message without checking if it exceeds the capacity of the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt a message
let ct = cks.encrypt(msg);
// Compute homomorphically a negation
let ct_res = sks.unchecked_neg(&ct);
// Decrypt
let three = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(modulus - msg, three);
pub fn unchecked_neg_with_correcting_term( &self, ct: &Ciphertext, ) -> (Ciphertext, u64)
Sourcepub fn unchecked_neg_assign(&self, ct: &mut Ciphertext)
pub fn unchecked_neg_assign(&self, ct: &mut Ciphertext)
Homomorphically negates a message inplace without checks.
Negation here means the opposite value in the modulo set.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a negation
sks.unchecked_neg_assign(&mut ct);
// Decrypt
let modulus = cks.parameters.message_modulus().0;
assert_eq!(modulus - msg, cks.decrypt(&ct));
pub fn unchecked_neg_assign_with_correcting_term( &self, ct: &mut Ciphertext, ) -> u64
Sourcepub fn is_neg_possible(
&self,
ct: CiphertextNoiseDegree,
) -> Result<(), CheckError>
pub fn is_neg_possible( &self, ct: CiphertextNoiseDegree, ) -> Result<(), CheckError>
Verify if a ciphertext can be negated.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let ct = cks.encrypt(msg);
// Check if we can perform a negation
sks.is_neg_possible(ct.noise_degree()).unwrap();
Sourcepub fn checked_neg(&self, ct: &Ciphertext) -> Result<Ciphertext, CheckError>
pub fn checked_neg(&self, ct: &Ciphertext) -> Result<Ciphertext, CheckError>
Compute homomorphically a negation of a ciphertext.
If the operation can be performed, the result is returned a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt a message
let ct = cks.encrypt(msg);
// Compute homomorphically a negation:
let ct_res = sks.checked_neg(&ct).unwrap();
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res, modulus - msg);
Sourcepub fn checked_neg_assign(&self, ct: &mut Ciphertext) -> Result<(), CheckError>
pub fn checked_neg_assign(&self, ct: &mut Ciphertext) -> Result<(), CheckError>
Compute homomorphically a negation of a ciphertext.
If the operation is possible, the result is stored in the input ciphertext. Otherwise a CheckError is returned and the ciphertext is not .
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically the negation:
sks.checked_neg_assign(&mut ct).unwrap();
let clear_res = cks.decrypt(&ct);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res, modulus - msg);
Sourcepub fn smart_neg(&self, ct: &mut Ciphertext) -> Ciphertext
pub fn smart_neg(&self, ct: &mut Ciphertext) -> Ciphertext
Compute homomorphically a negation of a ciphertext.
This checks that the negation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a negation
let ct_res = sks.smart_neg(&mut ct);
// Decrypt
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res, modulus - msg);
Sourcepub fn smart_neg_assign(&self, ct: &mut Ciphertext)
pub fn smart_neg_assign(&self, ct: &mut Ciphertext)
Compute homomorphically a negation of a ciphertext.
This checks that the addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a negation
sks.smart_neg_assign(&mut ct);
// Decrypt
let clear_res = cks.decrypt(&ct);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res, modulus - msg);
Source§impl ServerKey
impl ServerKey
Sourcepub fn scalar_add(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_add(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically an addition between a ciphertext and a scalar.
The result is returned in a new ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 9_u8;
// Encrypt a message
let ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.scalar_add(&ct, scalar);
// The input ciphertext content is not changed
assert_eq!(cks.decrypt(&ct), msg);
// Our result is what we expect
let clear = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!((msg + scalar as u64) % modulus, clear);
Sourcepub fn scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically an addition of a ciphertext by a scalar.
The result is stored in the ct
ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 5_u8;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
sks.scalar_add_assign(&mut ct, scalar);
// Our result is what we expect
let clear = cks.decrypt(&ct);
assert_eq!(
(msg + scalar as u64) % cks.parameters.message_modulus().0,
clear
);
Sourcepub fn unchecked_scalar_add(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn unchecked_scalar_add(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically an addition between a ciphertext and a scalar.
The result is returned in a new ciphertext.
This function does not check whether the capacity of the ciphertext is exceeded.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(1);
// Compute homomorphically a scalar addition:
let ct_res = sks.unchecked_scalar_add(&ct, 2);
let clear = cks.decrypt(&ct_res);
assert_eq!(3, clear);
Sourcepub fn unchecked_scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn unchecked_scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically an addition between a ciphertext and a scalar.
The result it stored in the given ciphertext.
This function does not check whether the capacity of the ciphertext is exceeded.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let mut ct = cks.encrypt(1);
// Compute homomorphically a scalar addition:
sks.unchecked_scalar_add_assign(&mut ct, 2);
let clear = cks.decrypt(&ct);
assert_eq!(3, clear);
Sourcepub fn is_scalar_add_possible(
&self,
ct: CiphertextNoiseDegree,
scalar: u8,
) -> Result<(), CheckError>
pub fn is_scalar_add_possible( &self, ct: CiphertextNoiseDegree, scalar: u8, ) -> Result<(), CheckError>
Verify if a scalar can be added to the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(2);
// Verification if the scalar addition can be computed:
sks.is_scalar_add_possible(ct.noise_degree(), 3).unwrap();
Sourcepub fn checked_scalar_add(
&self,
ct: &Ciphertext,
scalar: u8,
) -> Result<Ciphertext, CheckError>
pub fn checked_scalar_add( &self, ct: &Ciphertext, scalar: u8, ) -> Result<Ciphertext, CheckError>
Compute homomorphically an addition between a ciphertext and a scalar.
If the operation is possible, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(1);
// Compute homomorphically a addition multiplication:
let ct_res = sks.checked_scalar_add(&ct, 2).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, 3);
Sourcepub fn checked_scalar_add_assign(
&self,
ct: &mut Ciphertext,
scalar: u8,
) -> Result<(), CheckError>
pub fn checked_scalar_add_assign( &self, ct: &mut Ciphertext, scalar: u8, ) -> Result<(), CheckError>
Compute homomorphically an addition between a ciphertext and a scalar.
If the operation is possible, the result is stored in the input ciphertext. Otherwise a CheckError is returned and the ciphertext is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let mut ct = cks.encrypt(1);
// Compute homomorphically a scalar addition:
sks.checked_scalar_add_assign(&mut ct, 2).unwrap();
let clear_res = cks.decrypt(&ct);
assert_eq!(clear_res, 3);
Sourcepub fn smart_scalar_add(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext
pub fn smart_scalar_add(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically an addition between a ciphertext and a scalar.
The result is returned in a new ciphertext.
This checks that the scalar addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 9_u8;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.smart_scalar_add(&mut ct, scalar);
// The input ciphertext content is not changed
assert_eq!(cks.decrypt(&ct), msg);
// Our result is what we expect
let clear = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(2, clear % modulus);
Sourcepub fn smart_scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn smart_scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically an addition of a ciphertext by a scalar.
The result is stored in the ct
ciphertext.
This checks that the scalar addition is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 5_u8;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
sks.smart_scalar_add_assign(&mut ct, scalar);
// Our result is what we expect
let clear = cks.decrypt_message_and_carry(&ct);
assert_eq!(6, clear);
Source§impl ServerKey
impl ServerKey
Sourcepub fn scalar_bitand(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
pub fn scalar_bitand(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
Compute homomorphically a bitwise AND between a ciphertext and a clear value
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 3u64;
let msg2 = 2u64;
// Encrypt two messages:
let ct1 = cks.encrypt(msg1);
// Compute homomorphically an AND:
let ct_res = sks.scalar_bitand(&ct1, msg2 as u8);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg1 & msg2, res);
pub fn scalar_bitand_assign(&self, lhs: &mut Ciphertext, rhs: u8)
pub fn unchecked_scalar_bitand(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
pub fn unchecked_scalar_bitand_assign(&self, lhs: &mut Ciphertext, rhs: u8)
pub fn smart_scalar_bitand(&self, lhs: &mut Ciphertext, rhs: u8) -> Ciphertext
pub fn smart_scalar_bitand_assign(&self, lhs: &mut Ciphertext, rhs: u8)
Sourcepub fn scalar_bitxor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
pub fn scalar_bitxor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
Compute homomorphically a bitwise XOR between a ciphertext and a clear value
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 3u64;
let msg2 = 2u64;
// Encrypt two messages:
let ct1 = cks.encrypt(msg1);
// Compute homomorphically a XOR:
let ct_res = sks.scalar_bitxor(&ct1, msg2 as u8);
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(msg1 ^ msg2, res);
pub fn scalar_bitxor_assign(&self, lhs: &mut Ciphertext, rhs: u8)
pub fn unchecked_scalar_bitxor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
pub fn unchecked_scalar_bitxor_assign(&self, lhs: &mut Ciphertext, rhs: u8)
pub fn smart_scalar_bitxor(&self, lhs: &mut Ciphertext, rhs: u8) -> Ciphertext
pub fn smart_scalar_bitxor_assign(&self, lhs: &mut Ciphertext, rhs: u8)
Sourcepub fn scalar_bitor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
pub fn scalar_bitor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
Compute homomorphically a bitwise OR between a ciphertext and a clear value
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg1 = 3u64;
let msg2 = 2u64;
// Encrypt two messages:
let ct1 = cks.encrypt(msg1);
// Compute homomorphically an OR:
let ct_res = sks.scalar_bitor(&ct1, msg2 as u8);
// Decrypt:
let res: u64 = cks.decrypt(&ct_res);
assert_eq!(msg1 | msg2, res);
pub fn scalar_bitor_assign(&self, lhs: &mut Ciphertext, rhs: u8)
pub fn unchecked_scalar_bitor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext
pub fn unchecked_scalar_bitor_assign(&self, lhs: &mut Ciphertext, rhs: u8)
pub fn smart_scalar_bitor(&self, lhs: &mut Ciphertext, rhs: u8) -> Ciphertext
pub fn smart_scalar_bitor_assign(&self, lhs: &mut Ciphertext, rhs: u8)
Source§impl ServerKey
impl ServerKey
Sourcepub fn scalar_div(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_div(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
Alias to unchecked_scalar_div
provided for convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Panics
This function will panic if scalar == 0
.
Sourcepub fn scalar_div_assign(&self, ct_left: &mut Ciphertext, scalar: u8)
pub fn scalar_div_assign(&self, ct_left: &mut Ciphertext, scalar: u8)
Alias to unchecked_scalar_div_assign
provided for
convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Panics
This function will panic if scalar == 0
.
Sourcepub fn unchecked_scalar_div(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn unchecked_scalar_div(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute a division of a ciphertext by a scalar without checks.
§Panics
This function will panic if scalar == 0
.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 3;
let clear_2 = 2;
// Encrypt one message
let ct_1 = cks.encrypt(clear_1);
// Compute homomorphically a multiplication
let ct_res = sks.unchecked_scalar_div(&ct_1, clear_2);
// Decrypt
let res = cks.decrypt(&ct_res);
assert_eq!(clear_1 / (clear_2 as u64), res);
pub fn unchecked_scalar_div_assign(&self, ct: &mut Ciphertext, scalar: u8)
Sourcepub fn scalar_mod(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_mod(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext
Alias to unchecked_scalar_mod
provided for convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Panics
This function will panic if scalar == 0
.
Sourcepub fn scalar_mod_assign(&self, ct_left: &mut Ciphertext, scalar: u8)
pub fn scalar_mod_assign(&self, ct_left: &mut Ciphertext, scalar: u8)
Alias to unchecked_scalar_mod_assign
provided for
convenience
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Panics
This function will panic if scalar == 0
.
Sourcepub fn unchecked_scalar_mod(&self, ct: &Ciphertext, modulus: u8) -> Ciphertext
pub fn unchecked_scalar_mod(&self, ct: &Ciphertext, modulus: u8) -> Ciphertext
Compute homomorphically a modular reduction without checks.
§Panics
This function will panic if modulus == 0
.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let ct = cks.encrypt(msg);
let modulus: u8 = 2;
// Compute homomorphically an addition:
let ct_res = sks.unchecked_scalar_mod(&ct, modulus);
// Decrypt:
let dec = cks.decrypt(&ct_res);
assert_eq!(1, dec);
pub fn unchecked_scalar_mod_assign(&self, ct: &mut Ciphertext, modulus: u8)
Source§impl ServerKey
impl ServerKey
Sourcepub fn scalar_mul(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_mul(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically a multiplication of a ciphertext by a scalar.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 3_u8;
// Encrypt a message
let ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.scalar_mul(&ct, scalar);
// Our result is what we expect
let clear = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(msg * scalar as u64 % modulus, clear);
Sourcepub fn scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically a multiplication of a ciphertext by a scalar.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 3_u8;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
sks.scalar_mul_assign(&mut ct, scalar);
// Our result is what we expect
let clear = cks.decrypt(&ct);
assert_eq!(
msg * scalar as u64 % cks.parameters.message_modulus().0,
clear
);
Sourcepub fn unchecked_scalar_mul(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn unchecked_scalar_mul(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically a multiplication of a ciphertext by a scalar.
The result is returned in a new ciphertext.
The operation is modulo the the precision bits to the power of two.
This function does not check whether the capacity of the ciphertext is exceeded.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(1);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.unchecked_scalar_mul(&ct, 3);
let clear = cks.decrypt(&ct_res);
assert_eq!(3, clear);
Sourcepub fn unchecked_scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn unchecked_scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically a multiplication of a ciphertext by a scalar.
The result it stored in the given ciphertext.
The operation is modulo the the precision bits to the power of two.
This function does not check whether the capacity of the ciphertext is exceeded.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let mut ct = cks.encrypt(1);
// Compute homomorphically a scalar multiplication:
sks.unchecked_scalar_mul_assign(&mut ct, 3);
let clear = cks.decrypt(&ct);
assert_eq!(3, clear);
Sourcepub fn unchecked_scalar_mul_lsb_small_carry_modulus_assign(
&self,
ct: &mut Ciphertext,
scalar: u8,
)
pub fn unchecked_scalar_mul_lsb_small_carry_modulus_assign( &self, ct: &mut Ciphertext, scalar: u8, )
Multiply one ciphertext with a scalar in the case the carry space cannot fit the product applying the message space modulus in the process.
This is a bootstrapped operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear_1 = 1;
let clear_2 = 2;
// Encrypt two messages
let mut ct_1 = cks.encrypt(clear_1);
// Compute homomorphically a multiplication
sks.unchecked_scalar_mul_lsb_small_carry_modulus_assign(&mut ct_1, clear_2 as u8);
// Decrypt
let res = cks.decrypt(&ct_1);
assert_eq!(clear_2 * clear_1, res);
Sourcepub fn is_scalar_mul_possible(
&self,
ct: CiphertextNoiseDegree,
scalar: u8,
) -> Result<(), CheckError>
pub fn is_scalar_mul_possible( &self, ct: CiphertextNoiseDegree, scalar: u8, ) -> Result<(), CheckError>
Verify if the ciphertext can be multiplied by a scalar.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(2);
// Verification if the scalar multiplication can be computed:
sks.is_scalar_mul_possible(ct.noise_degree(), 3).unwrap();
Sourcepub fn checked_scalar_mul(
&self,
ct: &Ciphertext,
scalar: u8,
) -> Result<Ciphertext, CheckError>
pub fn checked_scalar_mul( &self, ct: &Ciphertext, scalar: u8, ) -> Result<Ciphertext, CheckError>
Compute homomorphically a multiplication of a ciphertext by a scalar.
If the operation is possible, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
The operation is modulo the precision bits to the power of two.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(1);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.checked_scalar_mul(&ct, 3).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, 3);
Sourcepub fn checked_scalar_mul_assign(
&self,
ct: &mut Ciphertext,
scalar: u8,
) -> Result<(), CheckError>
pub fn checked_scalar_mul_assign( &self, ct: &mut Ciphertext, scalar: u8, ) -> Result<(), CheckError>
Compute homomorphically a multiplication of a ciphertext by a scalar.
If the operation is possible, the result is stored in the input ciphertext. Otherwise a CheckError is returned and the ciphertext is not .
The operation is modulo the precision bits to the power of two.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let mut ct = cks.encrypt(1);
// Compute homomorphically a scalar multiplication:
sks.checked_scalar_mul_assign(&mut ct, 3).unwrap();
let clear_res = cks.decrypt(&ct);
assert_eq!(clear_res, 3);
Sourcepub fn smart_scalar_mul(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext
pub fn smart_scalar_mul(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically a multiplication of a ciphertext by a scalar.
This checks that the multiplication is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 3_u8;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.smart_scalar_mul(&mut ct, scalar);
// The input ciphertext content is not changed
assert_eq!(cks.decrypt(&ct), msg);
// Our result is what we expect
let clear = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(3, clear % modulus);
Sourcepub fn smart_scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn smart_scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically a multiplication of a ciphertext by a scalar.
This checks that the multiplication is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1_u64;
let scalar = 3_u8;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
sks.smart_scalar_mul_assign(&mut ct, scalar);
// Our result is what we expect
let clear = cks.decrypt(&ct);
assert_eq!(3, clear);
Source§impl ServerKey
impl ServerKey
Sourcepub fn scalar_sub(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn scalar_sub(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically a subtraction of a ciphertext by a scalar.
The result is returned in a new ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let scalar = 3;
// Encrypt a message
let ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.scalar_sub(&ct, scalar);
// The input ciphertext content is not changed
assert_eq!(cks.decrypt(&ct), msg);
// Our result is what we expect
let clear = cks.decrypt(&ct_res);
assert_eq!(msg - scalar as u64, clear);
Sourcepub fn scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically a subtraction of a ciphertext by a scalar.
The result is stored in the ct
ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 5;
let scalar = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
sks.scalar_sub_assign(&mut ct, scalar);
// Our result is what we expect
let clear = cks.decrypt(&ct);
assert_eq!(msg - scalar as u64, clear);
Sourcepub fn unchecked_scalar_sub(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
pub fn unchecked_scalar_sub(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically a subtraction of a ciphertext by a scalar.
The result is returned in a new ciphertext.
This function does not check whether the capacity of the ciphertext is exceeded.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(5);
// Compute homomorphically a scalar subtraction:
let ct_res = sks.unchecked_scalar_sub(&ct, 6);
// 5 - 6 mod 4 = 3 mod 4
let clear = cks.decrypt(&ct_res);
assert_eq!(3, clear);
Sourcepub fn unchecked_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn unchecked_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically a subtraction of a ciphertext by a scalar.
The result it stored in the given ciphertext.
This function does not check whether the capacity of the ciphertext is exceeded.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let mut ct = cks.encrypt(5);
// Compute homomorphically a scalar subtraction:
sks.unchecked_scalar_sub_assign(&mut ct, 2);
let clear = cks.decrypt(&ct);
assert_eq!(3, clear);
pub fn unchecked_scalar_sub_assign_with_correcting_term( &self, ct: &mut Ciphertext, scalar: u8, )
pub fn unchecked_scalar_sub_with_correcting_term( &self, ct: &Ciphertext, scalar: u8, ) -> Ciphertext
Sourcepub fn is_scalar_sub_possible(
&self,
ct: CiphertextNoiseDegree,
scalar: u8,
) -> Result<(), CheckError>
pub fn is_scalar_sub_possible( &self, ct: CiphertextNoiseDegree, scalar: u8, ) -> Result<(), CheckError>
Verify if a scalar can be subtracted to the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(5);
// Verification if the scalar subtraction can be computed:
sks.is_scalar_sub_possible(ct.noise_degree(), 3).unwrap();
Sourcepub fn checked_scalar_sub(
&self,
ct: &Ciphertext,
scalar: u8,
) -> Result<Ciphertext, CheckError>
pub fn checked_scalar_sub( &self, ct: &Ciphertext, scalar: u8, ) -> Result<Ciphertext, CheckError>
Compute homomorphically a subtraction of a ciphertext by a scalar.
If the operation is possible, the result is returned in a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let ct = cks.encrypt(5);
// Compute homomorphically a subtraction multiplication:
let ct_res = sks.checked_scalar_sub(&ct, 2).unwrap();
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res, 3);
Sourcepub fn checked_scalar_sub_assign(
&self,
ct: &mut Ciphertext,
scalar: u8,
) -> Result<(), CheckError>
pub fn checked_scalar_sub_assign( &self, ct: &mut Ciphertext, scalar: u8, ) -> Result<(), CheckError>
Compute homomorphically a subtraction of a ciphertext by a scalar.
If the operation is possible, the result is stored in the input ciphertext. Otherwise a CheckError is returned and the ciphertext is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt a message
let mut ct = cks.encrypt(5);
// Compute homomorphically a scalar subtraction:
sks.checked_scalar_sub_assign(&mut ct, 2).unwrap();
let clear_res = cks.decrypt(&ct);
assert_eq!(clear_res, 3);
Sourcepub fn smart_scalar_sub(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext
pub fn smart_scalar_sub(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext
Compute homomorphically a subtraction of a ciphertext by a scalar.
The result is returned in a new ciphertext.
This checks that the scalar subtraction is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let scalar = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
let ct_res = sks.smart_scalar_sub(&mut ct, scalar);
// The input ciphertext content is not changed
assert_eq!(cks.decrypt(&ct), msg);
// Our result is what we expect
let clear = cks.decrypt(&ct_res);
assert_eq!(msg - scalar as u64, clear);
Sourcepub fn smart_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8)
pub fn smart_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8)
Compute homomorphically a subtraction of a ciphertext by a scalar.
The result is stored in the ct
ciphertext.
This checks that the scalar subtraction is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 5;
let scalar = 3;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// Compute homomorphically a scalar multiplication:
sks.smart_scalar_sub_assign(&mut ct, scalar);
// Our result is what we expect
let clear = cks.decrypt(&ct);
assert_eq!(msg - scalar as u64, clear);
Source§impl ServerKey
impl ServerKey
Sourcepub fn scalar_right_shift(&self, ct: &Ciphertext, shift: u8) -> Ciphertext
pub fn scalar_right_shift(&self, ct: &Ciphertext, shift: u8) -> Ciphertext
Compute homomorphically a right shift of the bits.
This returns a new ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Compute homomorphically a right shift
let shift: u8 = 1;
let ct_res = sks.scalar_right_shift(&ct, shift);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt:
let dec = cks.decrypt(&ct_res);
assert_eq!(msg >> shift, dec);
Sourcepub fn scalar_right_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
pub fn scalar_right_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
Compute homomorphically a right shift of the bits.
This stores the result in ct
.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Compute homomorphically a right shift
let shift: u8 = 1;
sks.scalar_right_shift_assign(&mut ct, shift);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt:
let dec = cks.decrypt(&ct);
assert_eq!(msg >> shift, dec);
Sourcepub fn unchecked_scalar_right_shift(
&self,
ct: &Ciphertext,
shift: u8,
) -> Ciphertext
pub fn unchecked_scalar_right_shift( &self, ct: &Ciphertext, shift: u8, ) -> Ciphertext
Compute homomorphically a right shift of the bits without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Compute homomorphically a right shift
let shift: u8 = 1;
let ct_res = sks.unchecked_scalar_right_shift(&ct, shift);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt:
let dec = cks.decrypt(&ct_res);
assert_eq!(msg >> shift, dec);
Sourcepub fn unchecked_scalar_right_shift_assign(
&self,
ct: &mut Ciphertext,
shift: u8,
)
pub fn unchecked_scalar_right_shift_assign( &self, ct: &mut Ciphertext, shift: u8, )
Compute homomorphically a right shift of the bits without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Compute homomorphically a right shift
let shift: u8 = 1;
sks.unchecked_scalar_right_shift_assign(&mut ct, shift);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt:
let dec = cks.decrypt(&ct);
assert_eq!(msg >> shift, dec);
Sourcepub fn scalar_left_shift(&self, ct: &Ciphertext, shift: u8) -> Ciphertext
pub fn scalar_left_shift(&self, ct: &Ciphertext, shift: u8) -> Ciphertext
Compute homomorphically a left shift of the bits.
This returns a new ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt a message
let ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
let shift: u8 = 1;
let ct_res = sks.scalar_left_shift(&ct, shift);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Decrypt:
let msg_only = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!((msg << shift) % modulus, msg_only);
Sourcepub fn scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
pub fn scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
Compute homomorphically a left shift of the bits.
This writes the result in ct
.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
let shift: u8 = 1;
sks.scalar_left_shift_assign(&mut ct, shift);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Decrypt:
let msg_only = cks.decrypt(&ct);
let modulus = cks.parameters.message_modulus().0;
assert_eq!((msg << shift) % modulus, msg_only);
Sourcepub fn unchecked_scalar_left_shift(
&self,
ct: &Ciphertext,
shift: u8,
) -> Ciphertext
pub fn unchecked_scalar_left_shift( &self, ct: &Ciphertext, shift: u8, ) -> Ciphertext
Compute homomorphically a left shift of the bits without checks.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Compute homomorphically a left shift
let shift: u8 = 1;
let ct_res = sks.unchecked_scalar_left_shift(&ct, shift);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 1 | 0 0 |
// Decrypt:
let msg_and_carry = cks.decrypt_message_and_carry(&ct_res);
let msg_only = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
Sourcepub fn unchecked_scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
pub fn unchecked_scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
Compute homomorphically a left shift of the bits without checks
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Compute homomorphically a left shift
let shift: u8 = 1;
sks.unchecked_scalar_left_shift_assign(&mut ct, shift);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 1 | 0 0 |
// Decrypt:
let msg_and_carry = cks.decrypt_message_and_carry(&ct);
let msg_only = cks.decrypt(&ct);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
Sourcepub fn is_scalar_left_shift_possible(
&self,
ct1: CiphertextNoiseDegree,
shift: u8,
) -> Result<(), CheckError>
pub fn is_scalar_left_shift_possible( &self, ct1: CiphertextNoiseDegree, shift: u8, ) -> Result<(), CheckError>
Checks if the left shift operation can be applied.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
let shift = 5;
// Encrypt a message
let ct1 = cks.encrypt(msg);
// Check if we can perform an addition
let res = sks.is_scalar_left_shift_possible(ct1.noise_degree(), shift);
assert!(res.is_err());
Sourcepub fn checked_scalar_left_shift(
&self,
ct: &Ciphertext,
shift: u8,
) -> Result<Ciphertext, CheckError>
pub fn checked_scalar_left_shift( &self, ct: &Ciphertext, shift: u8, ) -> Result<Ciphertext, CheckError>
Compute homomorphically a left shift of the bits.
If the operation can be performed, a new ciphertext with the result is returned. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let ct1 = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Shifting 3 times is not ok, as it exceeds the carry buffer
let ct_res = sks.checked_scalar_left_shift(&ct1, 3);
assert!(ct_res.is_err());
// Shifting 2 times is ok
let shift = 2;
let ct_res = sks.checked_scalar_left_shift(&ct1, shift).unwrap();
// | ct_res |
// | carry | message |
// |-------|---------|
// | 1 0 | 0 0 |
// Decrypt:
let msg_and_carry = cks.decrypt_message_and_carry(&ct_res);
let msg_only = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
pub fn checked_scalar_left_shift_assign( &self, ct: &mut Ciphertext, shift: u8, ) -> Result<(), CheckError>
Sourcepub fn smart_scalar_left_shift(
&self,
ct: &mut Ciphertext,
shift: u8,
) -> Ciphertext
pub fn smart_scalar_left_shift( &self, ct: &mut Ciphertext, shift: u8, ) -> Ciphertext
Compute homomorphically a left shift of the bits
This checks that the operation is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt a message
let mut ct = cks.encrypt(msg);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
let shift: u8 = 1;
let ct_res = sks.smart_scalar_left_shift(&mut ct, shift);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 1 | 0 0 |
// Decrypt:
let msg_and_carry = cks.decrypt_message_and_carry(&ct_res);
let msg_only = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
pub fn smart_scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8)
Source§impl ServerKey
impl ServerKey
Sourcepub fn sub(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
pub fn sub(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext
Compute homomorphically a subtraction between two ciphertexts.
This returns a new ciphertext.
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let ct_1 = cks.encrypt(3);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
let ct_res = sks.sub(&ct_1, &ct_2);
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res % modulus, 2);
Sourcepub fn sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
pub fn sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext)
Compute homomorphically a subtraction between two ciphertexts.
This stores the result in ct_left
This function, like all “default” operations (i.e. not smart, checked or unchecked), will check that the input ciphertext carries are empty and clears them if it’s not the case and the operation requires it. It outputs a ciphertext whose carry is always empty.
This means that when using only “default” operations, a given operation (like add for example) has always the same performance characteristics from one call to another and guarantees correctness by pre-emptively clearing carries of output ciphertexts.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let mut ct_1 = cks.encrypt(3);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
sks.sub_assign(&mut ct_1, &ct_2);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
Sourcepub fn unchecked_sub(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext
pub fn unchecked_sub( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Ciphertext
Homomorphically subtracts ct_right to ct_left.
The result is returned in a new ciphertext.
This function computes the subtraction without checking if it exceeds the capacity of the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let ct_1 = cks.encrypt(2);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
let ct_res = sks.unchecked_sub(&ct_1, &ct_2);
// Decrypt:
assert_eq!(cks.decrypt(&ct_res), 2 - 1);
Sourcepub fn unchecked_sub_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
)
pub fn unchecked_sub_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, )
Homomorphically subtracts ct_right to ct_left.
The result is assigned in the ct_left
ciphertext.
This function computes the subtraction without checking if it exceeds the capacity of the ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let mut ct_1 = cks.encrypt(2);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
sks.unchecked_sub_assign(&mut ct_1, &ct_2);
// Decrypt:
let modulus = cks.parameters.message_modulus().0;
assert_eq!(cks.decrypt(&ct_1) % modulus, 1);
Sourcepub fn is_sub_possible(
&self,
ct_left: CiphertextNoiseDegree,
ct_right: CiphertextNoiseDegree,
) -> Result<(), CheckError>
pub fn is_sub_possible( &self, ct_left: CiphertextNoiseDegree, ct_right: CiphertextNoiseDegree, ) -> Result<(), CheckError>
Verify if ct_right can be subtracted to ct_left.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 2;
// Encrypt two messages:
let ct_1 = cks.encrypt(msg);
let ct_2 = cks.encrypt(msg);
// Check if we can perform an subtraction
sks.is_sub_possible(ct_1.noise_degree(), ct_2.noise_degree())
.unwrap();
Sourcepub fn checked_sub(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError>
pub fn checked_sub( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> Result<Ciphertext, CheckError>
Compute homomorphically a subtraction between two ciphertexts encrypting integer values.
If the operation can be performed, the result is returned a new ciphertext. Otherwise a CheckError is returned.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let ct_1 = cks.encrypt(3);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
let ct_res = sks.checked_sub(&ct_1, &ct_2).unwrap();
let modulus = cks.parameters.message_modulus().0;
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res % modulus, 2);
Sourcepub fn checked_sub_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> Result<(), CheckError>
pub fn checked_sub_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> Result<(), CheckError>
Compute homomorphically a subtraction between two ciphertexts.
If the operation can be performed, the result is stored in the ct_left
ciphertext.
Otherwise a CheckError is returned, and ct_left
is not modified.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let mut ct_1 = cks.encrypt(3);
let ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
sks.checked_sub_assign(&mut ct_1, &ct_2).unwrap();
let modulus = cks.parameters.message_modulus().0;
let clear_res = cks.decrypt(&ct_1);
assert_eq!(clear_res % modulus, 2);
Sourcepub fn smart_sub(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext
pub fn smart_sub( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> Ciphertext
Compute homomorphically a subtraction between two ciphertexts.
This checks that the subtraction is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let mut ct_1 = cks.encrypt(3);
let mut ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
let ct_res = sks.smart_sub(&mut ct_1, &mut ct_2);
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(clear_res % modulus, 2);
Sourcepub fn smart_sub_assign(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
)
pub fn smart_sub_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, )
Compute homomorphically a subtraction between two ciphertexts.
This checks that the subtraction is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Encrypt two messages:
let mut ct_1 = cks.encrypt(3);
let mut ct_2 = cks.encrypt(1);
// Compute homomorphically a subtraction:
sks.smart_sub_assign(&mut ct_1, &mut ct_2);
let modulus = cks.parameters.message_modulus().0;
assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
Sourcepub fn unchecked_sub_with_correcting_term(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> (Ciphertext, u64)
pub fn unchecked_sub_with_correcting_term( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, ) -> (Ciphertext, u64)
Compute homomorphically a subtraction between two ciphertexts without checks, and returns a correcting term.
This checks that the subtraction is possible. In the case where the carry buffers are full, then it is automatically cleared to allow the operation.
§Warning
This is an advanced functionality, needed for internal requirements.
Sourcepub fn unchecked_sub_assign_with_correcting_term(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
) -> u64
pub fn unchecked_sub_assign_with_correcting_term( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, ) -> u64
Compute homomorphically a subtraction between two ciphertexts without checks, and returns a correcting term.
§Warning
This is an advanced functionality, needed for internal requirements.
Sourcepub fn smart_sub_with_correcting_term(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> (Ciphertext, u64)
pub fn smart_sub_with_correcting_term( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, ) -> (Ciphertext, u64)
Compute homomorphically a subtraction between two ciphertexts without checks, and returns a correcting term.
§Warning
This is an advanced functionality, needed for internal requirements.
Source§impl ServerKey
impl ServerKey
Sourcepub fn new(cks: &ClientKey) -> Self
pub fn new(cks: &ClientKey) -> Self
Generate a server key.
§Example
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
use tfhe::shortint::{gen_keys, ServerKey};
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
// Generate the server key:
let sks = ServerKey::new(&cks);
Sourcepub fn new_with_max_degree(cks: &ClientKey, max_degree: MaxDegree) -> Self
pub fn new_with_max_degree(cks: &ClientKey, max_degree: MaxDegree) -> Self
Generate a server key with a chosen maximum degree
pub fn ciphertext_lwe_dimension(&self) -> LweDimension
Sourcepub fn into_raw_parts(
self,
) -> (LweKeyswitchKeyOwned<u64>, ShortintBootstrappingKey, MessageModulus, CarryModulus, MaxDegree, MaxNoiseLevel, CiphertextModulus, PBSOrder)
pub fn into_raw_parts( self, ) -> (LweKeyswitchKeyOwned<u64>, ShortintBootstrappingKey, MessageModulus, CarryModulus, MaxDegree, MaxNoiseLevel, CiphertextModulus, PBSOrder)
Deconstruct a ServerKey
into its constituents.
Sourcepub fn from_raw_parts(
key_switching_key: LweKeyswitchKeyOwned<u64>,
bootstrapping_key: ShortintBootstrappingKey,
message_modulus: MessageModulus,
carry_modulus: CarryModulus,
max_degree: MaxDegree,
max_noise_level: MaxNoiseLevel,
ciphertext_modulus: CiphertextModulus,
pbs_order: PBSOrder,
) -> Self
pub fn from_raw_parts( key_switching_key: LweKeyswitchKeyOwned<u64>, bootstrapping_key: ShortintBootstrappingKey, message_modulus: MessageModulus, carry_modulus: CarryModulus, max_degree: MaxDegree, max_noise_level: MaxNoiseLevel, ciphertext_modulus: CiphertextModulus, pbs_order: PBSOrder, ) -> Self
pub fn conformance_params(&self) -> CiphertextConformanceParams
Sourcepub fn generate_lookup_table<F>(&self, f: F) -> LookupTableOwned
pub fn generate_lookup_table<F>(&self, f: F) -> LookupTableOwned
Constructs the lookup table given a function as input.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let ct = cks.encrypt(msg);
// Generate the lookup table for the function f: x -> x*x mod 4
let f = |x: u64| x.pow(2) % 4;
let lut = sks.generate_lookup_table(f);
let ct_res = sks.apply_lookup_table(&ct, &lut);
let dec = cks.decrypt(&ct_res);
// 3**2 mod 4 = 1
assert_eq!(dec, f(msg));
Sourcepub fn generate_msg_lookup_table<F>(
&self,
f: F,
modulus: MessageModulus,
) -> LookupTableOwned
pub fn generate_msg_lookup_table<F>( &self, f: F, modulus: MessageModulus, ) -> LookupTableOwned
Given a function as input, constructs the lookup table working on the message bits Carry bits are ignored
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let ct = cks.encrypt(msg);
// Generate the lookup table on message for the function f: x -> x*x
let f = |x: u64| x.pow(2);
let lut = sks.generate_msg_lookup_table(f, ct.message_modulus);
let ct_res = sks.apply_lookup_table(&ct, &lut);
let dec = cks.decrypt(&ct_res);
// 3^2 mod 4 = 1
assert_eq!(dec, f(msg) % 4);
Sourcepub fn generate_many_lookup_table(
&self,
functions: &[&dyn Fn(u64) -> u64],
) -> ManyLookupTableOwned
pub fn generate_many_lookup_table( &self, functions: &[&dyn Fn(u64) -> u64], ) -> ManyLookupTableOwned
Constructs the lookup table given a set of function as input.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let ct = cks.encrypt(msg);
// Generate the lookup table for the functions
// f1: x -> x*x mod 4
// f2: x -> count_ones(x as binary) mod 4
let f1 = |x: u64| x.pow(2) % 4;
let f2 = |x: u64| x.count_ones() as u64 % 4;
// Easy to use for generation
let luts = sks.generate_many_lookup_table(&[&f1, &f2]);
let vec_res = sks.apply_many_lookup_table(&ct, &luts);
// Need to manually help Rust to iterate over them easily
let functions: &[&dyn Fn(u64) -> u64] = &[&f1, &f2];
for (res, function) in vec_res.iter().zip(functions) {
let dec = cks.decrypt(res);
assert_eq!(dec, function(msg));
}
Sourcepub fn apply_lookup_table(
&self,
ct: &Ciphertext,
acc: &LookupTableOwned,
) -> Ciphertext
pub fn apply_lookup_table( &self, ct: &Ciphertext, acc: &LookupTableOwned, ) -> Ciphertext
Compute a keyswitch and programmable bootstrap.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg: u64 = 3;
let ct = cks.encrypt(msg);
let modulus = cks.parameters.message_modulus().0;
// Generate the lookup table for the function f: x -> x*x*x mod 4
let lut = sks.generate_lookup_table(|x| x * x * x % modulus);
let ct_res = sks.apply_lookup_table(&ct, &lut);
let dec = cks.decrypt(&ct_res);
// (3*3*3) mod 4 = 3
assert_eq!(dec, (msg * msg * msg) % modulus);
pub fn apply_lookup_table_assign( &self, ct: &mut Ciphertext, acc: &LookupTableOwned, )
Sourcepub fn apply_many_lookup_table(
&self,
ct: &Ciphertext,
acc: &ManyLookupTableOwned,
) -> Vec<Ciphertext>
pub fn apply_many_lookup_table( &self, ct: &Ciphertext, acc: &ManyLookupTableOwned, ) -> Vec<Ciphertext>
Compute a keyswitch and programmable bootstrap applying several functions on an input ciphertext, returning each result in a fresh ciphertext.
This requires the input ciphertext to have a degree inferior to the max degree stored in the
ManyLookupTable
returned by Self::generate_many_lookup_table
.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 3;
let ct = cks.encrypt(msg);
// Generate the lookup table for the functions
// f1: x -> x*x mod 4
// f2: x -> count_ones(x as binary) mod 4
let f1 = |x: u64| x.pow(2) % 4;
let f2 = |x: u64| x.count_ones() as u64 % 4;
// Easy to use for generation
let luts = sks.generate_many_lookup_table(&[&f1, &f2]);
let vec_res = sks.apply_many_lookup_table(&ct, &luts);
// Need to manually help Rust to iterate over them easily
let functions: &[&dyn Fn(u64) -> u64] = &[&f1, &f2];
for (res, function) in vec_res.iter().zip(functions) {
let dec = cks.decrypt(res);
assert_eq!(dec, function(msg));
}
Sourcepub fn evaluate_msg_univariate_function_assign<F>(
&self,
ct: &mut Ciphertext,
f: F,
)
pub fn evaluate_msg_univariate_function_assign<F>( &self, ct: &mut Ciphertext, f: F, )
Applies the given function to the message of a ciphertext The input is reduced to the message space before the function application Thee output of the function is also rduced to the message space such that the carry bits are clean on the output
Sourcepub fn evaluate_msg_univariate_function<F>(
&self,
ct: &Ciphertext,
f: F,
) -> Ciphertext
pub fn evaluate_msg_univariate_function<F>( &self, ct: &Ciphertext, f: F, ) -> Ciphertext
Applies the given function to the message of a ciphertext The input is reduced to the message space before the function application Thee output of the function is also rduced to the message space such that the carry bits are clean on the output
Sourcepub fn carry_extract_assign(&self, ct: &mut Ciphertext)
pub fn carry_extract_assign(&self, ct: &mut Ciphertext)
Replace the input encrypted message by the value of its carry buffer.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear = 9;
// Encrypt a message
let mut ct = cks.unchecked_encrypt(clear);
// | ct |
// | carry | message |
// |-------|---------|
// | 1 0 | 0 1 |
// Compute homomorphically carry extraction
sks.carry_extract_assign(&mut ct);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Decrypt:
let res = cks.decrypt_message_and_carry(&ct);
assert_eq!(2, res);
Sourcepub fn carry_extract(&self, ct: &Ciphertext) -> Ciphertext
pub fn carry_extract(&self, ct: &Ciphertext) -> Ciphertext
Extract a new ciphertext encrypting the input carry buffer.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear = 9;
// Encrypt a message
let ct = cks.unchecked_encrypt(clear);
// | ct |
// | carry | message |
// |-------|---------|
// | 1 0 | 0 1 |
// Compute homomorphically carry extraction
let ct_res = sks.carry_extract(&ct);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 1 0 |
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(2, res);
Sourcepub fn message_extract_assign(&self, ct: &mut Ciphertext)
pub fn message_extract_assign(&self, ct: &mut Ciphertext)
Clears the carry buffer of the input ciphertext.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear = 9;
// Encrypt a message
let mut ct = cks.unchecked_encrypt(clear);
// | ct |
// | carry | message |
// |-------|---------|
// | 1 0 | 0 1 |
// Compute homomorphically the message extraction
sks.message_extract_assign(&mut ct);
// | ct |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt:
let res = cks.decrypt(&ct);
assert_eq!(1, res);
Sourcepub fn message_extract(&self, ct: &Ciphertext) -> Ciphertext
pub fn message_extract(&self, ct: &Ciphertext) -> Ciphertext
Extract a new ciphertext containing only the message i.e., with a cleared carry buffer.
§Example
use tfhe::shortint::gen_keys;
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let clear = 9;
// Encrypt a message
let ct = cks.unchecked_encrypt(clear);
// | ct |
// | carry | message |
// |-------|---------|
// | 1 0 | 0 1 |
// Compute homomorphically the message extraction
let ct_res = sks.message_extract(&ct);
// | ct_res |
// | carry | message |
// |-------|---------|
// | 0 0 | 0 1 |
// Decrypt:
let res = cks.decrypt(&ct_res);
assert_eq!(1, res);
Sourcepub fn create_trivial(&self, value: u64) -> Ciphertext
pub fn create_trivial(&self, value: u64) -> Ciphertext
Compute a trivial shortint ciphertext with the dimension of the big LWE secret key from a given value.
§Example
use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
use tfhe::shortint::{gen_keys, Ciphertext};
// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
let msg = 1;
// Trivial encryption
let ct1: Ciphertext = sks.create_trivial(msg);
let ct_res = cks.decrypt(&ct1);
assert_eq!(1, ct_res);
pub fn unchecked_create_trivial(&self, value: u64) -> Ciphertext
pub fn create_trivial_assign(&self, ct: &mut Ciphertext, value: u64)
pub fn bootstrapping_key_size_elements(&self) -> usize
pub fn bootstrapping_key_size_bytes(&self) -> usize
pub fn key_switching_key_size_elements(&self) -> usize
pub fn key_switching_key_size_bytes(&self) -> usize
pub fn deterministic_pbs_execution(&self) -> bool
pub fn set_deterministic_pbs_execution( &mut self, new_deterministic_execution: bool, )
Trait Implementations§
Source§impl Deprecable for ServerKey
impl Deprecable for ServerKey
Source§impl<'de> Deserialize<'de> for ServerKey
impl<'de> Deserialize<'de> for ServerKey
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl ParameterSetConformant for ServerKey
impl ParameterSetConformant for ServerKey
type ParameterSet = (PBSParameters, MaxDegree)
fn is_conformant( &self, (parameter_set, expected_max_degree): &Self::ParameterSet, ) -> bool
Source§impl Unversionize for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
impl Unversionize for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
Source§fn unversionize(
versioned: Self::VersionedOwned,
) -> Result<Self, UnversionizeError>
fn unversionize( versioned: Self::VersionedOwned, ) -> Result<Self, UnversionizeError>
Source§impl UnversionizeVec for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
impl UnversionizeVec for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
fn unversionize_vec( versioned: Self::VersionedVec, ) -> Result<Vec<Self>, UnversionizeError>
Source§impl Version for ServerKeywhere
LweKeyswitchKeyOwned<u64>: VersionizeOwned + Unversionize + Versionize,
ShortintBootstrappingKey: VersionizeOwned + Unversionize + Versionize,
MessageModulus: VersionizeOwned + Unversionize + Versionize,
CarryModulus: VersionizeOwned + Unversionize + Versionize,
MaxDegree: VersionizeOwned + Unversionize + Versionize,
MaxNoiseLevel: VersionizeOwned + Unversionize + Versionize,
CiphertextModulus: VersionizeOwned + Unversionize + Versionize,
PBSOrder: VersionizeOwned + Unversionize + Versionize,
impl Version for ServerKeywhere
LweKeyswitchKeyOwned<u64>: VersionizeOwned + Unversionize + Versionize,
ShortintBootstrappingKey: VersionizeOwned + Unversionize + Versionize,
MessageModulus: VersionizeOwned + Unversionize + Versionize,
CarryModulus: VersionizeOwned + Unversionize + Versionize,
MaxDegree: VersionizeOwned + Unversionize + Versionize,
MaxNoiseLevel: VersionizeOwned + Unversionize + Versionize,
CiphertextModulus: VersionizeOwned + Unversionize + Versionize,
PBSOrder: VersionizeOwned + Unversionize + Versionize,
Source§impl Versionize for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
impl Versionize for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
Source§type Versioned<'vers> = <ServerKeyVersions as VersionsDispatch<ServerKey>>::Ref<'vers>
type Versioned<'vers> = <ServerKeyVersions as VersionsDispatch<ServerKey>>::Ref<'vers>
Source§fn versionize(&self) -> Self::Versioned<'_>
fn versionize(&self) -> Self::Versioned<'_>
Source§impl VersionizeOwned for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
impl VersionizeOwned for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
type VersionedOwned = <ServerKeyVersions as VersionsDispatch<ServerKey>>::Owned
Source§fn versionize_owned(self) -> Self::VersionedOwned
fn versionize_owned(self) -> Self::VersionedOwned
Source§impl VersionizeSlice for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
impl VersionizeSlice for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
type VersionedSlice<'vers> = Vec<<ServerKey as Versionize>::Versioned<'vers>>
fn versionize_slice(slice: &[Self]) -> Self::VersionedSlice<'_>
Source§impl VersionizeVec for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
impl VersionizeVec for ServerKeywhere
ServerKeyVersions: VersionsDispatch<Self>,
type VersionedVec = Vec<<ServerKey as VersionizeOwned>::VersionedOwned>
fn versionize_vec(vec: Vec<Self>) -> Self::VersionedVec
impl StructuralPartialEq for ServerKey
Auto Trait Implementations§
impl Freeze for ServerKey
impl RefUnwindSafe for ServerKey
impl Send for ServerKey
impl Sync for ServerKey
impl Unpin for ServerKey
impl UnwindSafe for ServerKey
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more