Struct tfhe::shortint::server_key::ServerKey

source ·
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,
}
Available on crate feature 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

source

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

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!((msg2 + msg1) % modulus, two);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!((msg2 + msg1) % modulus, two);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Same thing using the small key for encryption
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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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
 let can_be_added = sks
     .is_add_possible(ct_left.noise_degree(), ct_right.noise_degree())
     .unwrap();

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // Encrypt two messages:
 let ct_left = cks.encrypt(msg);
 let ct_right = cks.encrypt(msg);

 // Check if we can perform an addition
 let can_be_added = sks
     .is_add_possible(ct_left.noise_degree(), ct_right.noise_degree())
     .unwrap();
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!((msg2 + msg1) % modulus, two);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!((msg2 + msg1) % modulus, two);
source§

impl ServerKey

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 & msg, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 & msg, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 & msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 & msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 & msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 & msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 & msg, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 & msg, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!(msg ^ msg, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!(msg ^ msg, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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, msg ^ msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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, msg ^ msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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, msg ^ msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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, msg ^ msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!(msg ^ msg, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!(msg ^ msg, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 | msg, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 | msg, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 | msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 | msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 | msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 | msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 | msg, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 | msg, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

pub fn bitnot_assign(&self, ct: &mut Ciphertext)

source

pub fn bitnot(&self, ct: &Ciphertext) -> Ciphertext

source§

impl ServerKey

source

pub fn generate_lookup_table_bivariate_with_factor<F>( &self, f: F, left_message_scaling: MessageModulus ) -> BivariateLookupTableOwned
where F: Fn(u64, u64) -> u64,

Generates a bivariate accumulator

source

pub fn generate_lookup_table_bivariate<F>( &self, f: F ) -> BivariateLookupTableOwned
where F: Fn(u64, u64) -> u64,

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);
acc.is_bivariate_pbs_possible(&sks, ct1.noise_degree(), ct2.noise_degree())
    .unwrap();
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));
source

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 as u64;

// 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);
source

pub fn unchecked_apply_lookup_table_bivariate_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, acc: &BivariateLookupTableOwned )

source

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 as u64;

// 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);
source

pub fn apply_lookup_table_bivariate_assign( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, acc: &BivariateLookupTableOwned )

source

pub fn unchecked_evaluate_bivariate_function<F>( &self, ct_left: &Ciphertext, ct_right: &Ciphertext, f: F ) -> Ciphertext
where F: Fn(u64, u64) -> u64,

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).

source

pub fn unchecked_evaluate_bivariate_function_assign<F>( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext, f: F )
where F: Fn(u64, u64) -> u64,

source

pub fn is_functional_bivariate_pbs_possible( &self, ct1: CiphertextNoiseDegree, ct2: CiphertextNoiseDegree ) -> Result<(), CheckError>

Verify if a functional bivariate pbs can be applied on ct_left and ct_right.

source

pub fn smart_evaluate_bivariate_function_assign<F>( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, f: F )
where F: Fn(u64, u64) -> u64,

source

pub fn smart_evaluate_bivariate_function<F>( &self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext, f: F ) -> Ciphertext
where F: Fn(u64, u64) -> u64,

source§

impl ServerKey

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg > msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg > msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg > msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg > msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg >= msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg >= msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg >= msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg >= msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg < msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg < msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg < msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg < msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg <= msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg <= msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg <= msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg <= msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg == msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg == msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg == msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg == msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg != msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg != msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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!((msg != msg) as u64, res);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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!((msg != msg) as u64, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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 mut 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // Encrypt two messages
 let mut ct_1 = cks.encrypt(clear_1);
 let mut 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

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.

source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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 mut ct_1 = cks.encrypt(clear_1);

 // Compute homomorphically a multiplication
 let ct_res = sks.unchecked_scalar_div(&mut ct_1, clear_2);

 // Decrypt
 let res = cks.decrypt(&ct_res);
 assert_eq!(clear_1 / (clear_2 as u64), res);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // Encrypt one message
 let mut ct_1 = cks.encrypt(clear_1);

 // Compute homomorphically a multiplication
 let ct_res = sks.unchecked_scalar_div(&mut ct_1, clear_2);

 // Decrypt
 let res = cks.decrypt(&ct_res);
 assert_eq!(clear_1 / (clear_2 as u64), res);
source

pub fn unchecked_scalar_div_assign(&self, ct: &mut Ciphertext, scalar: u8)

source

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.

source

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.

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);

let msg = 3;

let mut ct = cks.encrypt(msg);

let modulus: u8 = 2;
// Compute homomorphically an addition:
let ct_res = sks.unchecked_scalar_mod(&mut ct, modulus);

// Decrypt:
let dec = cks.decrypt(&ct_res);
assert_eq!(1, dec);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

let mut ct = cks.encrypt(msg);

let modulus: u8 = 2;
// Compute homomorphically an addition:
let ct_res = sks.unchecked_scalar_mod(&mut ct, modulus);

// Decrypt:
let dec = cks.decrypt(&ct_res);
assert_eq!(1, dec);
source

pub fn unchecked_scalar_mod_assign(&self, ct: &mut Ciphertext, modulus: u8)

source§

impl ServerKey

source

pub fn switch_modulus_and_compress( &self, ct: &Ciphertext ) -> CompressedModulusSwitchedCiphertext

Compresses a ciphertext to have a smaller serialization size

See CompressedModulusSwitchedCiphertext for usage

source

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. Fot the same cost, it’s possible to apply a lookup table by calling decompress_and_apply_lookup_table instead.

See CompressedModulusSwitchedCiphertext for usage

source

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

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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 as u64;
 assert_eq!((clear_1 * clear_2) % modulus, res);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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 as u64;
 assert_eq!((clear_1 * clear_2) % modulus, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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 as u64;
 assert_eq!((clear_1 * clear_2) % modulus, res);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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 as u64;
 assert_eq!((clear_1 * clear_2) % modulus, res);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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 mut 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 as u64;
 assert_eq!((clear_1 * clear_2) / modulus, res);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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.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 as u64;
 assert_eq!((clear_1 * clear_2) / modulus, res);
source

pub fn unchecked_mul_msb_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext )

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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
 let res = sks
     .is_mul_possible(ct_1.noise_degree(), ct_2.noise_degree())
     .unwrap();

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // Encrypt two messages:
 let ct_1 = cks.encrypt(msg);
 let ct_2 = cks.encrypt(msg);

 // Check if we can perform a multiplication
 let res = sks
     .is_mul_possible(ct_1.noise_degree(), ct_2.noise_degree())
     .unwrap();
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res % modulus, 2);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res % modulus, 2);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res % modulus, 2);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res % modulus, 2);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64
);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64
);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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 mut ct_1 = cks.encrypt(clear_1);
 let mut ct_2 = cks.encrypt(clear_2);

 // Compute homomorphically a multiplication
 let ct_res = sks.unchecked_mul_lsb_small_carry(&mut ct_1, &mut ct_2);

 // Decrypt
 let res = cks.decrypt(&ct_res);
 assert_eq!((clear_2 * clear_1), res);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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.unchecked_mul_lsb_small_carry(&mut ct_1, &mut ct_2);

 // Decrypt
 let res = cks.decrypt(&ct_res);
 assert_eq!((clear_2 * clear_1), res);
source

pub fn unchecked_mul_lsb_small_carry_assign( &self, ct_left: &mut Ciphertext, ct_right: &Ciphertext )

source

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::PARAM_MESSAGE_2_CARRY_1_KS_PBS;

 // Generate the client key and the server key:
 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_1_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_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());
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 mut ct_1 = cks.encrypt(msg_1);
let mut ct_2 = cks.encrypt(msg_2);

// Compute homomorphically a multiplication
let ct_res = sks
    .checked_mul_lsb_with_small_carry(&mut ct_1, &mut ct_2)
    .unwrap();

let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(clear_res % modulus, (msg_1 * msg_2) % modulus);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Encrypt two messages:
let mut ct_1 = cks.encrypt(msg_1);
let mut ct_2 = cks.encrypt(msg_2);

// Compute homomorphically a multiplication
let ct_res = sks
    .checked_mul_lsb_with_small_carry(&mut ct_1, &mut ct_2)
    .unwrap();

let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(clear_res % modulus, (msg_1 * msg_2) % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64);
source

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_1_KS_PBS, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_1_KS_PBS);

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 as u64;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);
source

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_1_KS_PBS, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_1_KS_PBS);

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 as u64;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);

let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
source

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_1_KS_PBS, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_1_KS_PBS);

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 as u64;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);

// Generate the client key and the server key:
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res % modulus, (msg1 * msg2) % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);

let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(res, ((msg1 * msg2) / modulus) % modulus);
source§

impl ServerKey

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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.neg(&mut ct);

// Decrypt
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(clear_res, modulus - msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Encrypt a message
let mut ct = cks.encrypt(msg);

// Compute homomorphically a negation
let ct_res = sks.neg(&mut ct);

// Decrypt
let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(clear_res, modulus - msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res, modulus - msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res, modulus - msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 mut ct_res = sks.unchecked_neg(&ct);

// Decrypt
let three = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(modulus - msg, three);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Encrypt a message
let ct = cks.encrypt(msg);

// Compute homomorphically a negation
let mut ct_res = sks.unchecked_neg(&ct);

// Decrypt
let three = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(modulus - msg, three);
source

pub fn unchecked_neg_with_correcting_term( &self, ct: &Ciphertext ) -> (Ciphertext, u64)

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(modulus - msg, cks.decrypt(&ct));

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(modulus - msg, cks.decrypt(&ct));
source

pub fn unchecked_neg_assign_with_correcting_term( &self, ct: &mut Ciphertext ) -> u64

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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
 let can_be_negated = sks.is_neg_possible(ct.noise_degree()).unwrap();

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // Encrypt a message
 let ct = cks.encrypt(msg);

 // Check if we can perform a negation
 let can_be_negated = sks.is_neg_possible(ct.noise_degree()).unwrap();
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res, modulus - msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res, modulus - msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res, modulus - msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res, modulus - msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res, modulus - msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res, modulus - msg);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(clear_res, modulus - msg);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(clear_res, modulus - msg);
source§

impl ServerKey

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!((msg + scalar as u64) % modulus, clear);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!((msg + scalar as u64) % modulus, clear);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64,
    clear
);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64,
    clear
);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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();

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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();
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(2, clear % modulus);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(2, clear % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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

source

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);
source

pub fn scalar_bitand_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

pub fn unchecked_scalar_bitand(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext

source

pub fn unchecked_scalar_bitand_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

pub fn smart_scalar_bitand(&self, lhs: &mut Ciphertext, rhs: u8) -> Ciphertext

source

pub fn smart_scalar_bitand_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

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);
source

pub fn scalar_bitxor_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

pub fn unchecked_scalar_bitxor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext

source

pub fn unchecked_scalar_bitxor_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

pub fn smart_scalar_bitxor(&self, lhs: &mut Ciphertext, rhs: u8) -> Ciphertext

source

pub fn smart_scalar_bitxor_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

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);
source

pub fn scalar_bitor_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

pub fn unchecked_scalar_bitor(&self, lhs: &Ciphertext, rhs: u8) -> Ciphertext

source

pub fn unchecked_scalar_bitor_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source

pub fn smart_scalar_bitor(&self, lhs: &mut Ciphertext, rhs: u8) -> Ciphertext

source

pub fn smart_scalar_bitor_assign(&self, lhs: &mut Ciphertext, rhs: u8)

source§

impl ServerKey

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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.scalar_mul(&mut ct, scalar);

// Our result is what we expect
let clear = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg * scalar as u64 % modulus, clear);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Encrypt a message
let mut ct = cks.encrypt(msg);

// Compute homomorphically a scalar multiplication:
let ct_res = sks.scalar_mul(&mut ct, scalar);

// Our result is what we expect
let clear = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg * scalar as u64 % modulus, clear);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64,
    clear
);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64,
    clear
);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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);

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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();

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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();
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;
assert_eq!(3, clear % modulus);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;
assert_eq!(3, clear % modulus);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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.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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Encrypt a message
let mut ct = cks.encrypt(msg);

// Compute homomorphically a scalar multiplication:
let ct_res = sks.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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

pub fn unchecked_scalar_sub_assign_with_correcting_term( &self, ct: &mut Ciphertext, scalar: u8 )

source

pub fn unchecked_scalar_sub_with_correcting_term( &self, ct: &Ciphertext, scalar: u8 ) -> Ciphertext

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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();

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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();
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};
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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};
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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(msg >> shift, dec);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};
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;
let ct_res = sks.scalar_left_shift(&mut 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 as u64;

assert_eq!((msg << shift) % modulus, msg_only);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// Encrypt a message
let mut ct = cks.encrypt(msg);
// |       ct        |
// | carry | message |
// |-------|---------|
// |  0 0  |   0 1   |

let shift: u8 = 1;
let ct_res = sks.scalar_left_shift(&mut 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 as u64;

assert_eq!((msg << shift) % modulus, msg_only);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};
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 as u64;

assert_eq!((msg << shift) % modulus, msg_only);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;

assert_eq!((msg << shift) % modulus, msg_only);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};
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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
 };

 // 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());

 let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

 // 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());
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

// 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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
source

pub fn checked_scalar_left_shift_assign( &self, ct: &mut Ciphertext, shift: u8 ) -> Result<(), CheckError>

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};
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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);

let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

// 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 as u64;

assert_eq!(msg << shift, msg_and_carry);
assert_eq!((msg << shift) % modulus, msg_only);
source

pub fn smart_scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8)

source§

impl ServerKey

source

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 mut ct_1 = cks.encrypt(3);
let ct_2 = cks.encrypt(1);

// Compute homomorphically a subtraction:
let ct_res = sks.sub(&mut ct_1, &ct_2);

let clear_res = cks.decrypt(&ct_res);
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(clear_res % modulus, 2);
source

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 as u64;
assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
source

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:
let modulus = cks.parameters.message_modulus().0 as u64;
assert_eq!(cks.decrypt(&ct_res), 2 - 1);
source

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 as u64;
assert_eq!(cks.decrypt(&ct_1) % modulus, 1);
source

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();
source

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 as u64;
let clear_res = cks.decrypt(&ct_res);
assert_eq!(clear_res % modulus, 2);
source

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 as u64;
let clear_res = cks.decrypt(&ct_1);
assert_eq!(clear_res % modulus, 2);
source

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 as u64;
assert_eq!(clear_res % modulus, 2);
source

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 as u64;
assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
source

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.

source

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.

source

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

source§

impl ServerKey

source

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);
source

pub fn new_with_max_degree(cks: &ClientKey, max_degree: MaxDegree) -> Self

Generate a server key with a chosen maximum degree

source

pub fn ciphertext_lwe_dimension(&self) -> LweDimension

source

pub fn into_raw_parts( self ) -> (LweKeyswitchKeyOwned<u64>, ShortintBootstrappingKey, MessageModulus, CarryModulus, MaxDegree, MaxNoiseLevel, CiphertextModulus, PBSOrder)

Deconstruct a ServerKey into its constituents.

source

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

Construct a ServerKey from its constituents.

§Panics

Panics if the constituents are not compatible with each others.

source

pub fn generate_lookup_table<F>(&self, f: F) -> LookupTableOwned
where F: Fn(u64) -> u64,

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));
source

pub fn generate_msg_lookup_table<F>( &self, f: F, modulus: MessageModulus ) -> LookupTableOwned
where F: Fn(u64) -> u64,

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);
source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

{
    // 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));
    }
}
{
    // Generate the client key and the server key:
    let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

    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));
    }
}
source

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 as u64;

// 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);
source

pub fn apply_lookup_table_assign( &self, ct: &mut Ciphertext, acc: &LookupTableOwned )

source

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, PARAM_MESSAGE_2_CARRY_2_PBS_KS,
};

{
    // 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));
    }
}
{
    // Generate the client key and the server key:
    let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_PBS_KS);

    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));
    }
}
source

pub fn evaluate_msg_univariate_function_assign<F>( &self, ct: &mut Ciphertext, f: F )
where F: Fn(u64) -> u64,

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

source

pub fn evaluate_msg_univariate_function<F>( &self, ct: &Ciphertext, f: F ) -> Ciphertext
where F: Fn(u64) -> u64,

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

source

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);
source

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);
source

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);
source

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);
source

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);
source

pub fn unchecked_create_trivial(&self, value: u64) -> Ciphertext

source

pub fn create_trivial_assign(&self, ct: &mut Ciphertext, value: u64)

source

pub fn bootstrapping_key_size_elements(&self) -> usize

source

pub fn bootstrapping_key_size_bytes(&self) -> usize

source

pub fn key_switching_key_size_elements(&self) -> usize

source

pub fn key_switching_key_size_bytes(&self) -> usize

source

pub fn deterministic_pbs_execution(&self) -> bool

source

pub fn set_deterministic_pbs_execution( &mut self, new_deterministic_execution: bool )

Trait Implementations§

source§

impl AsRef<ServerKey> for ServerKey

Available on crate feature integer only.
source§

fn as_ref(&self) -> &ServerKey

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Clone for ServerKey

source§

fn clone(&self) -> ServerKey

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ServerKey

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'de> Deserialize<'de> for ServerKey

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl From<ServerKey> for ServerKey

Available on crate feature integer only.
source§

fn from(key: ServerKey) -> Self

Converts to this type from the input type.
source§

impl PartialEq for ServerKey

source§

fn eq(&self, other: &ServerKey) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Serialize for ServerKey

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl StructuralPartialEq for ServerKey

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Input, Output> CastInto<Output> for Input
where Output: CastFrom<Input>,

source§

fn cast_into(self) -> Output

source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Pointable for T

source§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,