feat(shortint): add support for small LWE key encryption

This commit is contained in:
Arthur Meyre
2023-02-21 17:24:10 +01:00
parent 42b569bcd7
commit a04d68f1fb
86 changed files with 6218 additions and 2150 deletions

View File

@@ -116,7 +116,7 @@ fn main() {
let acc = server_key.generate_accumulator(f);
// Compute the function over the ciphertext using the PBS
let ct_res = server_key.keyswitch_programmable_bootstrap(&ct_add, &acc);
let ct_res = server_key.apply_lookup_table(&ct_add, &acc);
// Decrypt the ciphertext using the (private) client key
let output = client_key.decrypt(&ct_res);

View File

@@ -48,4 +48,12 @@ if [[ "${BUILD_ONLY}" == "1" ]]; then
exit 0
fi
make "test"
nproc_bin=nproc
# macOS detects CPUs differently
if [[ $(uname) == "Darwin" ]]; then
nproc_bin="sysctl -n hw.logicalcpu"
fi
# Let's go parallel
ARGS="-j$("${nproc_bin}")" make test

View File

@@ -1,7 +1,7 @@
use criterion::{criterion_group, criterion_main, Criterion};
use tfhe::shortint::keycache::NamedParam;
use tfhe::shortint::parameters::*;
use tfhe::shortint::{Ciphertext, Parameters, ServerKey};
use tfhe::shortint::{CiphertextBig, Parameters, ServerKey};
use rand::Rng;
use tfhe::shortint::keycache::KEY_CACHE;
@@ -40,7 +40,7 @@ fn bench_server_key_unary_function<F>(
unary_op: F,
params: &[Parameters],
) where
F: Fn(&ServerKey, &mut Ciphertext),
F: Fn(&ServerKey, &mut CiphertextBig),
{
let mut bench_group = c.benchmark_group(bench_name);
@@ -73,7 +73,7 @@ fn bench_server_key_binary_function<F>(
binary_op: F,
params: &[Parameters],
) where
F: Fn(&ServerKey, &mut Ciphertext, &mut Ciphertext),
F: Fn(&ServerKey, &mut CiphertextBig, &mut CiphertextBig),
{
let mut bench_group = c.benchmark_group(bench_name);
@@ -108,7 +108,7 @@ fn bench_server_key_binary_scalar_function<F>(
binary_op: F,
params: &[Parameters],
) where
F: Fn(&ServerKey, &mut Ciphertext, u8),
F: Fn(&ServerKey, &mut CiphertextBig, u8),
{
let mut bench_group = c.benchmark_group(bench_name);
@@ -142,7 +142,7 @@ fn bench_server_key_binary_scalar_division_function<F>(
binary_op: F,
params: &[Parameters],
) where
F: Fn(&ServerKey, &mut Ciphertext, u8),
F: Fn(&ServerKey, &mut CiphertextBig, u8),
{
let mut bench_group = c.benchmark_group(bench_name);
@@ -192,7 +192,7 @@ fn carry_extract(c: &mut Criterion) {
let bench_id = format!("ServerKey::carry_extract::{}", param.name());
bench_group.bench_function(&bench_id, |b| {
b.iter(|| {
sks.carry_extract(&ct_0);
let _ = sks.carry_extract(&ct_0);
})
});
}
@@ -221,7 +221,7 @@ fn programmable_bootstrapping(c: &mut Criterion) {
bench_group.bench_function(&id, |b| {
b.iter(|| {
sks.keyswitch_programmable_bootstrap(&ctxt, &acc);
let _ = sks.apply_lookup_table(&ctxt, &acc);
})
});
}
@@ -247,7 +247,7 @@ fn bench_wopbs_param_message_8_norm2_5(c: &mut Criterion) {
bench_group.bench_function(&id, |b| {
b.iter(|| {
wopbs_key.programmable_bootstrapping_native_crt(&mut ct, &vec_lut);
let _ = wopbs_key.programmable_bootstrapping_native_crt(&mut ct, &vec_lut);
})
});
@@ -261,7 +261,7 @@ macro_rules! define_server_key_unary_bench_fn (
c,
concat!("ServerKey::", stringify!($server_key_method)),
|server_key, lhs| {
server_key.$server_key_method(lhs);},
let _ = server_key.$server_key_method(lhs);},
$params)
}
}
@@ -274,7 +274,7 @@ macro_rules! define_server_key_bench_fn (
c,
concat!("ServerKey::", stringify!($server_key_method)),
|server_key, lhs, rhs| {
server_key.$server_key_method(lhs, rhs);},
let _ = server_key.$server_key_method(lhs, rhs);},
$params)
}
}
@@ -287,7 +287,7 @@ macro_rules! define_server_key_scalar_bench_fn (
c,
concat!("ServerKey::", stringify!($server_key_method)),
|server_key, lhs, rhs| {
server_key.$server_key_method(lhs, rhs);},
let _ = server_key.$server_key_method(lhs, rhs);},
$params)
}
}
@@ -300,7 +300,7 @@ macro_rules! define_server_key_scalar_div_bench_fn (
c,
concat!("ServerKey::", stringify!($server_key_method)),
|server_key, lhs, rhs| {
server_key.$server_key_method(lhs, rhs);},
let _ = server_key.$server_key_method(lhs, rhs);},
$params)
}
}

View File

@@ -88,7 +88,7 @@ void test_server_key_trivial_encrypt(void) {
int gen_keys_ok = shortint_gen_keys_with_parameters(params, &cks, &sks);
assert(gen_keys_ok == 0);
int encrypt_ok = shortint_server_key_create_trivial(sks, 3, &ct);
int encrypt_ok = shortint_server_key_create_trivial(sks, 3, ShortintCiphertextBig, &ct);
assert(encrypt_ok == 0);
uint64_t result = -1;
@@ -121,7 +121,7 @@ void test_custom_keygen(void) {
destroy_shortint_server_key(sks);
}
void test_public_keygen(void) {
void test_public_keygen(ShortintPublicKeyKind pk_kind) {
ShortintClientKey *cks = NULL;
ShortintPublicKey *pks = NULL;
ShortintPublicKey *pks_deser = NULL;
@@ -135,7 +135,7 @@ void test_public_keygen(void) {
int gen_keys_ok = shortint_gen_client_key(params, &cks);
assert(gen_keys_ok == 0);
int gen_pks = shortint_gen_public_key(cks, &pks);
int gen_pks = shortint_gen_public_key(cks, pk_kind, &pks);
assert(gen_pks == 0);
int pks_ser = shortint_serialize_public_key(pks, &pks_ser_buff);
@@ -164,7 +164,7 @@ void test_public_keygen(void) {
destroy_shortint_ciphertext(ct);
}
void test_compressed_public_keygen(void) {
void test_compressed_public_keygen(ShortintPublicKeyKind pk_kind) {
ShortintClientKey *cks = NULL;
ShortintCompressedPublicKey *cpks = NULL;
ShortintPublicKey *pks = NULL;
@@ -177,7 +177,7 @@ void test_compressed_public_keygen(void) {
int gen_keys_ok = shortint_gen_client_key(params, &cks);
assert(gen_keys_ok == 0);
int gen_cpks = shortint_gen_compressed_public_key(cks, &cpks);
int gen_cpks = shortint_gen_compressed_public_key(cks, pk_kind, &cpks);
assert(gen_cpks == 0);
uint64_t msg = 2;
@@ -213,8 +213,10 @@ void test_compressed_public_keygen(void) {
int main(void) {
test_predefined_keygen_w_serde();
test_custom_keygen();
test_public_keygen();
test_compressed_public_keygen();
test_public_keygen(ShortintPublicKeyBig);
test_public_keygen(ShortintPublicKeySmall);
test_compressed_public_keygen(ShortintPublicKeyBig);
test_compressed_public_keygen(ShortintPublicKeySmall);
test_server_key_trivial_encrypt();
return EXIT_SUCCESS;
}

View File

@@ -38,7 +38,7 @@ uint64_t get_max_value_of_bivariate_accumulator_generator(uint64_t (*accumulator
}
void test_shortint_pbs_2_bits_message(void) {
ShortintPBSAccumulator *accumulator = NULL;
ShortintPBSLookupTable *accumulator = NULL;
ShortintClientKey *cks = NULL;
ShortintServerKey *sks = NULL;
ShortintParameters *params = NULL;
@@ -115,7 +115,7 @@ void test_shortint_pbs_2_bits_message(void) {
}
void test_shortint_bivariate_pbs_2_bits_message(void) {
ShortintBivariatePBSAccumulator *accumulator = NULL;
ShortintBivariatePBSLookupTable *accumulator = NULL;
ShortintClientKey *cks = NULL;
ShortintServerKey *sks = NULL;
ShortintParameters *params = NULL;

View File

@@ -5,250 +5,365 @@
#include <stdlib.h>
#include <tgmath.h>
typedef int (*BinaryCallback)(const ShortintServerKey *, ShortintCiphertext *, ShortintCiphertext *,
ShortintCiphertext **);
typedef int (*BinaryAssignCallback)(const ShortintServerKey *, ShortintCiphertext *,
ShortintCiphertext *);
typedef int (*BinaryScalarCallback)(const ShortintServerKey *, ShortintCiphertext *, uint8_t,
ShortintCiphertext **);
typedef int (*UnaryCallback)(const ShortintServerKey *, ShortintCiphertext *,
ShortintCiphertext **);
typedef int (*UnaryAssignCallback)(const ShortintServerKey *, ShortintCiphertext *);
void test_shortint_unary_op(const ShortintClientKey *cks, const ShortintServerKey *sks,
const ShortintClientKey *cks_small, const ShortintServerKey *sks_small,
const uint32_t message_bits, const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t),
int (*api_fun)(const ShortintServerKey *, ShortintCiphertext *,
ShortintCiphertext **)) {
uint64_t (*c_fun)(uint64_t), UnaryCallback api_fun) {
int message_max = 1 << message_bits;
for (int val_in = 0; val_in < message_max; ++val_in) {
ShortintCiphertext *ct_in = NULL;
ShortintCiphertext *ct_result = NULL;
uint64_t in = (uint64_t)val_in;
uint64_t expected = c_fun(in) % message_max;
int encrypt_left_ok = shortint_client_key_encrypt(cks, in, &ct_in);
assert(encrypt_left_ok == 0);
int api_call_ok = api_fun(sks, ct_in, &ct_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks, ct_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_in);
destroy_shortint_ciphertext(ct_result);
}
}
void test_shortint_unary_op_assign(const ShortintClientKey *cks, const ShortintServerKey *sks,
const uint32_t message_bits, const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t),
int (*api_fun)(const ShortintServerKey *,
ShortintCiphertext *)) {
int message_max = 1 << message_bits;
for (int in = 0; in < message_max; ++in) {
ShortintCiphertext *ct_in_and_result = NULL;
uint64_t in = (uint64_t)in;
uint64_t expected = c_fun(in) % message_max;
int encrypt_left_ok = shortint_client_key_encrypt(cks, in, &ct_in_and_result);
assert(encrypt_left_ok == 0);
int api_call_ok = api_fun(sks, ct_in_and_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks, ct_in_and_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_in_and_result);
}
}
void test_shortint_binary_op(const ShortintClientKey *cks, const ShortintServerKey *sks,
const uint32_t message_bits, const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t, uint64_t),
int (*api_fun)(const ShortintServerKey *, ShortintCiphertext *,
ShortintCiphertext *, ShortintCiphertext **)) {
int message_max = 1 << message_bits;
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left = NULL;
ShortintCiphertext *ct_right = NULL;
for (int is_big = 0; is_big < 2; ++is_big) {
for (int val_in = 0; val_in < message_max; ++val_in) {
ShortintCiphertext *ct_in = NULL;
ShortintCiphertext *ct_result = NULL;
const ShortintClientKey *cks_in_use = NULL;
const ShortintServerKey *sks_in_use = NULL;
uint64_t left = (uint64_t)val_left;
uint64_t right = (uint64_t)val_right;
uint64_t in = (uint64_t)val_in;
uint64_t expected = c_fun(left, right) % message_max;
uint64_t expected = c_fun(in) % message_max;
int encrypt_left_ok = shortint_client_key_encrypt(cks, left, &ct_left);
assert(encrypt_left_ok == 0);
if (is_big == 1) {
cks_in_use = cks;
sks_in_use = sks;
int encrypt_right_ok = shortint_client_key_encrypt(cks, right, &ct_right);
assert(encrypt_right_ok == 0);
int encrypt_left_ok = shortint_client_key_encrypt(cks_in_use, in, &ct_in);
assert(encrypt_left_ok == 0);
} else {
cks_in_use = cks_small;
sks_in_use = sks_small;
int api_call_ok = api_fun(sks, ct_left, ct_right, &ct_result);
int encrypt_left_ok = shortint_client_key_encrypt_small(cks_in_use, in, &ct_in);
assert(encrypt_left_ok == 0);
}
int api_call_ok = api_fun(sks_in_use, ct_in, &ct_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks, ct_result, &decrypted_result);
int decrypt_ok = shortint_client_key_decrypt(cks_in_use, ct_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left);
destroy_shortint_ciphertext(ct_right);
destroy_shortint_ciphertext(ct_in);
destroy_shortint_ciphertext(ct_result);
}
}
}
void test_shortint_unary_op_assign(const ShortintClientKey *cks, const ShortintServerKey *sks,
const ShortintClientKey *cks_small,
const ShortintServerKey *sks_small, const uint32_t message_bits,
const uint32_t carry_bits, uint64_t (*c_fun)(uint64_t),
UnaryAssignCallback api_fun) {
int message_max = 1 << message_bits;
for (int is_big = 0; is_big < 2; ++is_big) {
for (int in = 0; in < message_max; ++in) {
ShortintCiphertext *ct_in_and_result = NULL;
const ShortintClientKey *cks_in_use = NULL;
const ShortintServerKey *sks_in_use = NULL;
uint64_t in = (uint64_t)in;
uint64_t expected = c_fun(in) % message_max;
if (is_big == 1) {
cks_in_use = cks;
sks_in_use = sks;
int encrypt_left_ok = shortint_client_key_encrypt(cks_in_use, in, &ct_in_and_result);
assert(encrypt_left_ok == 0);
} else {
cks_in_use = cks_small;
sks_in_use = sks_small;
int encrypt_left_ok = shortint_client_key_encrypt_small(cks_in_use, in, &ct_in_and_result);
assert(encrypt_left_ok == 0);
}
int api_call_ok = api_fun(sks_in_use, ct_in_and_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks_in_use, ct_in_and_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_in_and_result);
}
}
}
void test_shortint_binary_op(const ShortintClientKey *cks, const ShortintServerKey *sks,
const ShortintClientKey *cks_small, const ShortintServerKey *sks_small,
const uint32_t message_bits, const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t, uint64_t), BinaryCallback api_fun) {
int message_max = 1 << message_bits;
for (int is_big = 0; is_big < 2; ++is_big) {
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left = NULL;
ShortintCiphertext *ct_right = NULL;
ShortintCiphertext *ct_result = NULL;
const ShortintClientKey *cks_in_use = NULL;
const ShortintServerKey *sks_in_use = NULL;
uint64_t left = (uint64_t)val_left;
uint64_t right = (uint64_t)val_right;
uint64_t expected = c_fun(left, right) % message_max;
if (is_big == 1) {
cks_in_use = cks;
sks_in_use = sks;
int encrypt_left_ok = shortint_client_key_encrypt(cks_in_use, left, &ct_left);
assert(encrypt_left_ok == 0);
int encrypt_right_ok = shortint_client_key_encrypt(cks_in_use, right, &ct_right);
assert(encrypt_right_ok == 0);
} else {
cks_in_use = cks_small;
sks_in_use = sks_small;
int encrypt_left_ok = shortint_client_key_encrypt_small(cks_in_use, left, &ct_left);
assert(encrypt_left_ok == 0);
int encrypt_right_ok = shortint_client_key_encrypt_small(cks_in_use, right, &ct_right);
assert(encrypt_right_ok == 0);
}
int api_call_ok = api_fun(sks_in_use, ct_left, ct_right, &ct_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks_in_use, ct_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left);
destroy_shortint_ciphertext(ct_right);
destroy_shortint_ciphertext(ct_result);
}
}
}
}
void test_shortint_binary_op_assign(const ShortintClientKey *cks, const ShortintServerKey *sks,
const uint32_t message_bits, const uint32_t carry_bits,
const ShortintClientKey *cks_small,
const ShortintServerKey *sks_small, const uint32_t message_bits,
const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t, uint64_t),
int (*api_fun)(const ShortintServerKey *, ShortintCiphertext *,
ShortintCiphertext *)) {
BinaryAssignCallback api_fun) {
int message_max = 1 << message_bits;
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left_and_result = NULL;
ShortintCiphertext *ct_right = NULL;
for (int is_big = 0; is_big < 2; ++is_big) {
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left_and_result = NULL;
ShortintCiphertext *ct_right = NULL;
const ShortintClientKey *cks_in_use = NULL;
const ShortintServerKey *sks_in_use = NULL;
uint64_t left = (uint64_t)val_left;
uint64_t right = (uint64_t)val_right;
uint64_t left = (uint64_t)val_left;
uint64_t right = (uint64_t)val_right;
uint64_t expected = c_fun(left, right) % message_max;
uint64_t expected = c_fun(left, right) % message_max;
int encrypt_left_ok = shortint_client_key_encrypt(cks, left, &ct_left_and_result);
assert(encrypt_left_ok == 0);
if (is_big == 1) {
cks_in_use = cks;
sks_in_use = sks;
int encrypt_right_ok = shortint_client_key_encrypt(cks, right, &ct_right);
assert(encrypt_right_ok == 0);
int encrypt_left_ok = shortint_client_key_encrypt(cks_in_use, left, &ct_left_and_result);
assert(encrypt_left_ok == 0);
int api_call_ok = api_fun(sks, ct_left_and_result, ct_right);
assert(api_call_ok == 0);
int encrypt_right_ok = shortint_client_key_encrypt(cks_in_use, right, &ct_right);
assert(encrypt_right_ok == 0);
} else {
cks_in_use = cks_small;
sks_in_use = sks_small;
uint64_t decrypted_result = -1;
int encrypt_left_ok =
shortint_client_key_encrypt_small(cks_in_use, left, &ct_left_and_result);
assert(encrypt_left_ok == 0);
int decrypt_ok = shortint_client_key_decrypt(cks, ct_left_and_result, &decrypted_result);
assert(decrypt_ok == 0);
int encrypt_right_ok = shortint_client_key_encrypt_small(cks_in_use, right, &ct_right);
assert(encrypt_right_ok == 0);
}
assert(decrypted_result == expected);
int api_call_ok = api_fun(sks_in_use, ct_left_and_result, ct_right);
assert(api_call_ok == 0);
destroy_shortint_ciphertext(ct_left_and_result);
destroy_shortint_ciphertext(ct_right);
uint64_t decrypted_result = -1;
int decrypt_ok =
shortint_client_key_decrypt(cks_in_use, ct_left_and_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left_and_result);
destroy_shortint_ciphertext(ct_right);
}
}
}
}
void test_shortint_binary_scalar_op(
const ShortintClientKey *cks, const ShortintServerKey *sks, const uint32_t message_bits,
const uint32_t carry_bits, uint64_t (*c_fun)(uint64_t, uint8_t),
const ShortintClientKey *cks, const ShortintServerKey *sks, const ShortintClientKey *cks_small,
const ShortintServerKey *sks_small, const uint32_t message_bits, const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t, uint8_t),
int (*api_fun)(const ShortintServerKey *, ShortintCiphertext *, uint8_t, ShortintCiphertext **),
uint8_t forbidden_scalar_values[], size_t forbidden_scalar_values_len) {
int message_max = 1 << message_bits;
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left = NULL;
ShortintCiphertext *ct_result = NULL;
for (int is_big = 0; is_big < 2; ++is_big) {
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left = NULL;
ShortintCiphertext *ct_result = NULL;
const ShortintClientKey *cks_in_use = NULL;
const ShortintServerKey *sks_in_use = NULL;
uint64_t left = (uint64_t)val_left;
uint8_t scalar_right = (uint8_t)val_right;
uint64_t left = (uint64_t)val_left;
uint8_t scalar_right = (uint8_t)val_right;
if (forbidden_scalar_values != NULL) {
bool found_forbidden_value = false;
for (int idx = 0; idx < forbidden_scalar_values_len; ++idx) {
if (forbidden_scalar_values[idx] == scalar_right) {
found_forbidden_value = true;
break;
if (forbidden_scalar_values != NULL) {
bool found_forbidden_value = false;
for (int idx = 0; idx < forbidden_scalar_values_len; ++idx) {
if (forbidden_scalar_values[idx] == scalar_right) {
found_forbidden_value = true;
break;
}
}
if (found_forbidden_value) {
continue;
}
}
if (found_forbidden_value) {
continue;
uint64_t expected = c_fun(left, scalar_right) % message_max;
if (is_big == 1) {
cks_in_use = cks;
sks_in_use = sks;
int encrypt_left_ok = shortint_client_key_encrypt(cks_in_use, left, &ct_left);
assert(encrypt_left_ok == 0);
} else {
cks_in_use = cks_small;
sks_in_use = sks_small;
int encrypt_left_ok = shortint_client_key_encrypt_small(cks_in_use, left, &ct_left);
assert(encrypt_left_ok == 0);
}
int api_call_ok = api_fun(sks_in_use, ct_left, scalar_right, &ct_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks_in_use, ct_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left);
destroy_shortint_ciphertext(ct_result);
}
uint64_t expected = c_fun(left, scalar_right) % message_max;
int encrypt_left_ok = shortint_client_key_encrypt(cks, left, &ct_left);
assert(encrypt_left_ok == 0);
int api_call_ok = api_fun(sks, ct_left, scalar_right, &ct_result);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks, ct_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left);
destroy_shortint_ciphertext(ct_result);
}
}
}
void test_shortint_binary_scalar_op_assign(
const ShortintClientKey *cks, const ShortintServerKey *sks, const uint32_t message_bits,
const uint32_t carry_bits, uint64_t (*c_fun)(uint64_t, uint8_t),
const ShortintClientKey *cks, const ShortintServerKey *sks, const ShortintClientKey *cks_small,
const ShortintServerKey *sks_small, const uint32_t message_bits, const uint32_t carry_bits,
uint64_t (*c_fun)(uint64_t, uint8_t),
int (*api_fun)(const ShortintServerKey *, ShortintCiphertext *, uint8_t),
uint8_t forbidden_scalar_values[], size_t forbidden_scalar_values_len) {
int message_max = 1 << message_bits;
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left_and_result = NULL;
for (int is_big = 0; is_big < 2; ++is_big) {
for (int val_left = 0; val_left < message_max; ++val_left) {
for (int val_right = 0; val_right < message_max; ++val_right) {
ShortintCiphertext *ct_left_and_result = NULL;
const ShortintClientKey *cks_in_use = NULL;
const ShortintServerKey *sks_in_use = NULL;
uint64_t left = (uint64_t)val_left;
uint8_t scalar_right = (uint8_t)val_right;
uint64_t left = (uint64_t)val_left;
uint8_t scalar_right = (uint8_t)val_right;
if (forbidden_scalar_values != NULL) {
bool found_forbidden_value = false;
for (int idx = 0; idx < forbidden_scalar_values_len; ++idx) {
if (forbidden_scalar_values[idx] == scalar_right) {
found_forbidden_value = true;
break;
if (forbidden_scalar_values != NULL) {
bool found_forbidden_value = false;
for (int idx = 0; idx < forbidden_scalar_values_len; ++idx) {
if (forbidden_scalar_values[idx] == scalar_right) {
found_forbidden_value = true;
break;
}
}
if (found_forbidden_value) {
continue;
}
}
if (found_forbidden_value) {
continue;
uint64_t expected = c_fun(left, scalar_right) % message_max;
if (is_big == 1) {
cks_in_use = cks;
sks_in_use = sks;
int encrypt_left_ok = shortint_client_key_encrypt(cks_in_use, left, &ct_left_and_result);
assert(encrypt_left_ok == 0);
} else {
cks_in_use = cks_small;
sks_in_use = sks_small;
int encrypt_left_ok =
shortint_client_key_encrypt_small(cks_in_use, left, &ct_left_and_result);
assert(encrypt_left_ok == 0);
}
int api_call_ok = api_fun(sks_in_use, ct_left_and_result, scalar_right);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok =
shortint_client_key_decrypt(cks_in_use, ct_left_and_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left_and_result);
}
uint64_t expected = c_fun(left, scalar_right) % message_max;
int encrypt_left_ok = shortint_client_key_encrypt(cks, left, &ct_left_and_result);
assert(encrypt_left_ok == 0);
int api_call_ok = api_fun(sks, ct_left_and_result, scalar_right);
assert(api_call_ok == 0);
uint64_t decrypted_result = -1;
int decrypt_ok = shortint_client_key_decrypt(cks, ct_left_and_result, &decrypted_result);
assert(decrypt_ok == 0);
assert(decrypted_result == expected);
destroy_shortint_ciphertext(ct_left_and_result);
}
}
}
@@ -305,6 +420,9 @@ void test_server_key(void) {
Buffer sks_ser_buffer = {.pointer = NULL, .length = 0};
ShortintServerKey *deser_sks = NULL;
ShortintParameters *params = NULL;
ShortintClientKey *cks_small = NULL;
ShortintServerKey *sks_small = NULL;
ShortintParameters *params_small = NULL;
const uint32_t message_bits = 2;
const uint32_t carry_bits = 2;
@@ -312,9 +430,18 @@ void test_server_key(void) {
int get_params_ok = shortint_get_parameters(message_bits, carry_bits, &params);
assert(get_params_ok == 0);
int get_params_small_ok = shortint_get_parameters(message_bits, carry_bits, &params_small);
assert(get_params_small_ok == 0);
int gen_cks_ok = shortint_gen_client_key(params, &cks);
assert(gen_cks_ok == 0);
int gen_cks_small_ok = shortint_gen_client_key(params_small, &cks_small);
assert(gen_cks_small_ok == 0);
int gen_sks_small_ok = shortint_gen_server_key(cks_small, &sks_small);
assert(gen_sks_small_ok == 0);
int gen_csks_ok = shortint_gen_compressed_server_key(cks, &csks);
assert(gen_csks_ok == 0);
@@ -348,225 +475,269 @@ void test_server_key(void) {
assert(deser_sks_ok == 0);
printf("add\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, add,
shortint_server_key_smart_add);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, add,
shortint_server_key_unchecked_add);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, add,
shortint_server_key_smart_add_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, add,
shortint_server_key_unchecked_add_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, add,
(BinaryCallback)shortint_server_key_smart_add);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, add,
(BinaryCallback)shortint_server_key_unchecked_add);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, add,
(BinaryAssignCallback)shortint_server_key_smart_add_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, add,
(BinaryAssignCallback)shortint_server_key_unchecked_add_assign);
printf("sub\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, sub,
shortint_server_key_smart_sub);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, sub,
shortint_server_key_unchecked_sub);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, sub,
shortint_server_key_smart_sub_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, sub,
shortint_server_key_unchecked_sub_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, sub,
(BinaryCallback)shortint_server_key_smart_sub);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, sub,
(BinaryCallback)shortint_server_key_unchecked_sub);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, sub,
(BinaryAssignCallback)shortint_server_key_smart_sub_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, sub,
(BinaryAssignCallback)shortint_server_key_unchecked_sub_assign);
printf("mul\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, mul,
shortint_server_key_smart_mul);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, mul,
shortint_server_key_unchecked_mul);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, mul,
shortint_server_key_smart_mul_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, mul,
shortint_server_key_unchecked_mul_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, mul,
(BinaryCallback)shortint_server_key_smart_mul);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, mul,
(BinaryCallback)shortint_server_key_unchecked_mul);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, mul,
(BinaryAssignCallback)shortint_server_key_smart_mul_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, mul,
(BinaryAssignCallback)shortint_server_key_unchecked_mul_assign);
printf("left_shift\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, left_shift,
shortint_server_key_smart_scalar_left_shift, NULL, 0);
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, left_shift,
shortint_server_key_unchecked_scalar_left_shift, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, left_shift,
shortint_server_key_smart_scalar_left_shift_assign, NULL,
0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, left_shift,
shortint_server_key_unchecked_scalar_left_shift_assign,
NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, left_shift,
(BinaryScalarCallback)shortint_server_key_smart_scalar_left_shift, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, left_shift,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_left_shift, NULL, 0);
test_shortint_binary_scalar_op_assign(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, left_shift,
shortint_server_key_smart_scalar_left_shift_assign, NULL, 0);
test_shortint_binary_scalar_op_assign(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, left_shift,
shortint_server_key_unchecked_scalar_left_shift_assign, NULL, 0);
printf("right_shift\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, right_shift,
shortint_server_key_smart_scalar_right_shift, NULL, 0);
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, right_shift,
shortint_server_key_unchecked_scalar_right_shift, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, right_shift,
shortint_server_key_smart_scalar_right_shift_assign, NULL,
0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, right_shift,
shortint_server_key_unchecked_scalar_right_shift_assign,
NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, right_shift,
(BinaryScalarCallback)shortint_server_key_smart_scalar_right_shift, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, right_shift,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_right_shift, NULL, 0);
test_shortint_binary_scalar_op_assign(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, right_shift,
shortint_server_key_smart_scalar_right_shift_assign, NULL, 0);
test_shortint_binary_scalar_op_assign(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, right_shift,
shortint_server_key_unchecked_scalar_right_shift_assign, NULL, 0);
printf("scalar_add\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_add,
shortint_server_key_smart_scalar_add, NULL, 0);
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_add,
shortint_server_key_unchecked_scalar_add, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_add,
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_add,
(BinaryScalarCallback)shortint_server_key_smart_scalar_add, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_add,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_add, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_add,
shortint_server_key_smart_scalar_add_assign, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_add,
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_add,
shortint_server_key_unchecked_scalar_add_assign, NULL, 0);
printf("scalar_sub\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_sub,
shortint_server_key_smart_scalar_sub, NULL, 0);
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_sub,
shortint_server_key_unchecked_scalar_sub, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_sub,
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_sub,
(BinaryScalarCallback)shortint_server_key_smart_scalar_sub, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_sub,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_sub, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_sub,
shortint_server_key_smart_scalar_sub_assign, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_sub,
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_sub,
shortint_server_key_unchecked_scalar_sub_assign, NULL, 0);
printf("scalar_mul\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_mul,
shortint_server_key_smart_scalar_mul, NULL, 0);
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_mul,
shortint_server_key_unchecked_scalar_mul, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_mul,
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_mul,
(BinaryScalarCallback)shortint_server_key_smart_scalar_mul, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_mul,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_mul, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_mul,
shortint_server_key_smart_scalar_mul_assign, NULL, 0);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_mul,
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_mul,
shortint_server_key_unchecked_scalar_mul_assign, NULL, 0);
printf("bitand\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, bitand,
shortint_server_key_smart_bitand);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, bitand,
shortint_server_key_unchecked_bitand);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, bitand,
shortint_server_key_smart_bitand_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, bitand,
shortint_server_key_unchecked_bitand_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitand, (BinaryCallback)shortint_server_key_smart_bitand);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitand, (BinaryCallback)shortint_server_key_unchecked_bitand);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitand,
(BinaryAssignCallback)shortint_server_key_smart_bitand_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitand,
(BinaryAssignCallback)shortint_server_key_unchecked_bitand_assign);
printf("bitxor\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, bitxor,
shortint_server_key_smart_bitxor);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, bitxor,
shortint_server_key_unchecked_bitxor);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, bitxor,
shortint_server_key_smart_bitxor_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, bitxor,
shortint_server_key_unchecked_bitxor_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
bitxor, (BinaryCallback)shortint_server_key_smart_bitxor);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
bitxor, (BinaryCallback)shortint_server_key_unchecked_bitxor);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitxor,
(BinaryAssignCallback)shortint_server_key_smart_bitxor_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitxor,
(BinaryAssignCallback)shortint_server_key_unchecked_bitxor_assign);
printf("bitor\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, bitor,
shortint_server_key_smart_bitor);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, bitor,
shortint_server_key_unchecked_bitor);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, bitor,
shortint_server_key_smart_bitor_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, bitor,
shortint_server_key_unchecked_bitor_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
bitor, (BinaryCallback)shortint_server_key_smart_bitor);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
bitor, (BinaryCallback)shortint_server_key_unchecked_bitor);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitor,
(BinaryAssignCallback)shortint_server_key_smart_bitor_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, bitor,
(BinaryAssignCallback)shortint_server_key_unchecked_bitor_assign);
printf("greater\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, greater,
shortint_server_key_smart_greater);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, greater,
shortint_server_key_unchecked_greater);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
greater, (BinaryCallback)shortint_server_key_smart_greater);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
greater, (BinaryCallback)shortint_server_key_unchecked_greater);
printf("greater_or_equal\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, greater_or_equal,
shortint_server_key_smart_greater_or_equal);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, greater_or_equal,
shortint_server_key_unchecked_greater_or_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
greater_or_equal,
(BinaryCallback)shortint_server_key_smart_greater_or_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
greater_or_equal,
(BinaryCallback)shortint_server_key_unchecked_greater_or_equal);
printf("less\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, less,
shortint_server_key_smart_less);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, less,
shortint_server_key_unchecked_less);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
less, (BinaryCallback)shortint_server_key_smart_less);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
less, (BinaryCallback)shortint_server_key_unchecked_less);
printf("less_or_equal\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, less_or_equal,
shortint_server_key_smart_less_or_equal);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, less_or_equal,
shortint_server_key_unchecked_less_or_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
less_or_equal, (BinaryCallback)shortint_server_key_smart_less_or_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
less_or_equal,
(BinaryCallback)shortint_server_key_unchecked_less_or_equal);
printf("equal\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, equal,
shortint_server_key_smart_equal);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, equal,
shortint_server_key_unchecked_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
equal, (BinaryCallback)shortint_server_key_smart_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
equal, (BinaryCallback)shortint_server_key_unchecked_equal);
printf("not_equal\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, not_equal,
shortint_server_key_smart_not_equal);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, not_equal,
shortint_server_key_unchecked_not_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
not_equal, (BinaryCallback)shortint_server_key_smart_not_equal);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
not_equal, (BinaryCallback)shortint_server_key_unchecked_not_equal);
printf("scalar_greater\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_greater,
shortint_server_key_smart_scalar_greater, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_greater,
(BinaryScalarCallback)shortint_server_key_smart_scalar_greater, NULL, 0);
printf("scalar_greater_or_equal\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits,
scalar_greater_or_equal,
shortint_server_key_smart_scalar_greater_or_equal, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_greater_or_equal,
(BinaryScalarCallback)shortint_server_key_smart_scalar_greater_or_equal, NULL, 0);
printf("scalar_less\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_less,
shortint_server_key_smart_scalar_less, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_less,
(BinaryScalarCallback)shortint_server_key_smart_scalar_less, NULL, 0);
printf("scalar_less_or_equal\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits,
scalar_less_or_equal,
shortint_server_key_smart_scalar_less_or_equal, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_less_or_equal,
(BinaryScalarCallback)shortint_server_key_smart_scalar_less_or_equal, NULL, 0);
printf("scalar_equal\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_equal,
shortint_server_key_smart_scalar_equal, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_equal,
(BinaryScalarCallback)shortint_server_key_smart_scalar_equal, NULL, 0);
printf("scalar_not_equal\n");
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_not_equal,
shortint_server_key_smart_scalar_not_equal, NULL, 0);
test_shortint_binary_scalar_op(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_not_equal,
(BinaryScalarCallback)shortint_server_key_smart_scalar_not_equal, NULL, 0);
printf("neg\n");
test_shortint_unary_op(deser_cks, deser_sks, message_bits, carry_bits, neg,
shortint_server_key_smart_neg);
test_shortint_unary_op(deser_cks, deser_sks, message_bits, carry_bits, neg,
shortint_server_key_unchecked_neg);
test_shortint_unary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, neg,
shortint_server_key_smart_neg_assign);
test_shortint_unary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, neg,
shortint_server_key_unchecked_neg_assign);
test_shortint_unary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, neg,
(UnaryCallback)shortint_server_key_smart_neg);
test_shortint_unary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, neg,
(UnaryCallback)shortint_server_key_unchecked_neg);
test_shortint_unary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, neg,
(UnaryAssignCallback)shortint_server_key_smart_neg_assign);
test_shortint_unary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, neg,
(UnaryAssignCallback)shortint_server_key_unchecked_neg_assign);
printf("div\n");
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, homomorphic_div,
shortint_server_key_smart_div);
test_shortint_binary_op(deser_cks, deser_sks, message_bits, carry_bits, homomorphic_div,
shortint_server_key_unchecked_div);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, homomorphic_div,
shortint_server_key_smart_div_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, message_bits, carry_bits, homomorphic_div,
shortint_server_key_unchecked_div_assign);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
homomorphic_div, (BinaryCallback)shortint_server_key_smart_div);
test_shortint_binary_op(deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits,
homomorphic_div, (BinaryCallback)shortint_server_key_unchecked_div);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, homomorphic_div,
(BinaryAssignCallback)shortint_server_key_smart_div_assign);
test_shortint_binary_op_assign(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, homomorphic_div,
(BinaryAssignCallback)shortint_server_key_unchecked_div_assign);
printf("scalar_div\n");
uint8_t forbidden_scalar_div_values[1] = {0};
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_div,
shortint_server_key_unchecked_scalar_div,
test_shortint_binary_scalar_op(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_div,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_div,
forbidden_scalar_div_values, 1);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_div,
shortint_server_key_unchecked_scalar_div_assign,
forbidden_scalar_div_values, 1);
test_shortint_binary_scalar_op_assign(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_div,
shortint_server_key_unchecked_scalar_div_assign, forbidden_scalar_div_values, 1);
printf("scalar_mod\n");
uint8_t forbidden_scalar_mod_values[1] = {0};
test_shortint_binary_scalar_op(deser_cks, deser_sks, message_bits, carry_bits, scalar_mod,
shortint_server_key_unchecked_scalar_mod,
test_shortint_binary_scalar_op(deser_cks, deser_sks, cks_small, sks_small, message_bits,
carry_bits, scalar_mod,
(BinaryScalarCallback)shortint_server_key_unchecked_scalar_mod,
forbidden_scalar_mod_values, 1);
test_shortint_binary_scalar_op_assign(deser_cks, deser_sks, message_bits, carry_bits, scalar_mod,
shortint_server_key_unchecked_scalar_mod_assign,
forbidden_scalar_mod_values, 1);
test_shortint_binary_scalar_op_assign(
deser_cks, deser_sks, cks_small, sks_small, message_bits, carry_bits, scalar_mod,
shortint_server_key_unchecked_scalar_mod_assign, forbidden_scalar_mod_values, 1);
destroy_shortint_client_key(cks);
destroy_shortint_client_key(cks_small);
destroy_shortint_compressed_server_key(csks);
destroy_shortint_server_key(sks);
destroy_shortint_server_key(sks_small);
destroy_shortint_client_key(deser_cks);
destroy_shortint_compressed_server_key(deser_csks);
destroy_shortint_server_key(deser_sks);
destroy_shortint_parameters(params);
destroy_shortint_parameters(params_small);
destroy_buffer(&cks_ser_buffer);
destroy_buffer(&csks_ser_buffer);
destroy_buffer(&sks_ser_buffer);

View File

@@ -103,7 +103,7 @@ uint64_t get_max_value_of_accumulator_generator(uint64_t (*accumulator_func)(uin
int main(void)
{
ShortintPBSAccumulator *accumulator = NULL;
ShortintPBSLookupTable *accumulator = NULL;
ShortintClientKey *cks = NULL;
ShortintServerKey *sks = NULL;
ShortintParameters *params = NULL;

View File

@@ -181,7 +181,7 @@ use tfhe::shortint::prelude::*;
fn main() {
// Generate the client key and the server key:
let (cks, _) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
let pks = PublicKey::new(&cks);
let pks = PublicKeyBig::new(&cks);
let msg = 2;
// Encryption of one message:
@@ -307,7 +307,7 @@ fn main() {
let acc = server_key.generate_accumulator(|n| n.count_ones().into());
// add the two ciphertexts
let ct_res = server_key.keyswitch_programmable_bootstrap(&ct_1, &acc);
let ct_res = server_key.apply_lookup_table(&ct_1, &acc);
// We use the client key to decrypt the output of the circuit:
@@ -336,13 +336,13 @@ fn main() {
// We use the private client key to encrypt two messages:
let ct_1 = client_key.encrypt(msg1);
let ct_2 = client_key.encrypt(msg2);
let mut ct_2 = client_key.encrypt(msg2);
// Compute the accumulator for the bivariate functions
let acc = server_key.generate_accumulator_bivariate(|x,y| (x.count_ones()
+ y.count_ones()) as u64 % modulus );
let ct_res = server_key.keyswitch_programmable_bootstrap_bivariate(&ct_1, &ct_2, &acc);
let ct_res = server_key.smart_apply_lookup_table_bivariate(&ct_1, &mut ct_2, &acc);
// We use the client key to decrypt the output of the circuit:
let output = client_key.decrypt(&ct_res);

View File

@@ -39,7 +39,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Simulate sending serialized data to a server and getting
// back the serialized result
let serialized_result = server_function(&serialized_data)?;
let result: Ciphertext = bincode::deserialize(&serialized_result)?;
let result: CiphertextBig = bincode::deserialize(&serialized_result)?;
let output = client_key.decrypt(&result);
assert_eq!(output, msg1 + msg2);
@@ -50,8 +50,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
fn server_function(serialized_data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut serialized_data = Cursor::new(serialized_data);
let server_key: ServerKey = bincode::deserialize_from(&mut serialized_data)?;
let ct_1: Ciphertext = bincode::deserialize_from(&mut serialized_data)?;
let ct_2: Ciphertext = bincode::deserialize_from(&mut serialized_data)?;
let ct_1: CiphertextBig = bincode::deserialize_from(&mut serialized_data)?;
let ct_2: CiphertextBig = bincode::deserialize_from(&mut serialized_data)?;
let result = server_key.unchecked_add(&ct_1, &ct_2);

View File

@@ -54,7 +54,7 @@ use tfhe::shortint::prelude::*;
fn main() {
// We generate a set of client/server keys, using the default parameters:
let (client_key, _) = gen_keys(Parameters::default());
let public_key = PublicKey::new(&client_key);
let public_key = PublicKeyBig::new(&client_key);
let msg1 = 1;
let msg2 = 0;

View File

@@ -107,6 +107,18 @@ test('shortint_encrypt_decrypt', (t) => {
let deserialized_sks = Shortint.deserialize_compressed_server_key(serialized_sks);
// No equality tests here, as wasm stores pointers which will always differ
// Encryption using small keys
let params_small = Shortint.get_parameters_small(2, 2);
let cks_small = Shortint.new_client_key(params_small);
let ct_small = Shortint.encrypt_small(cks_small, BigInt(3));
let serialized_ct_small = Shortint.serialize_ciphertext(ct_small);
let deserialized_ct_small = Shortint.deserialize_ciphertext(serialized_ct_small);
let decrypted_small = Shortint.decrypt(cks_small, deserialized_ct_small);
assert.deepStrictEqual(decrypted_small, BigInt(3));
});
test('shortint_compressed_encrypt_decrypt', (t) => {
@@ -124,6 +136,20 @@ test('shortint_compressed_encrypt_decrypt', (t) => {
let decrypted = Shortint.decrypt(deserialized_cks, decompressed_ct);
assert.deepStrictEqual(decrypted, BigInt(3));
// Encryption using small keys
let params_small = Shortint.get_parameters_small(2, 2);
let cks_small = Shortint.new_client_key(params_small);
let ct_small = Shortint.encrypt_compressed_small(cks_small, BigInt(3));
let serialized_ct_small = Shortint.serialize_compressed_ciphertext(ct_small);
let deserialized_ct_small = Shortint.deserialize_compressed_ciphertext(serialized_ct_small);
let decompressed_ct_small = Shortint.decompress_ciphertext(deserialized_ct_small);
let decrypted_small = Shortint.decrypt(cks_small, decompressed_ct_small);
assert.deepStrictEqual(decrypted_small, BigInt(3));
});
test('shortint_public_encrypt_decrypt', (t) => {
@@ -138,6 +164,20 @@ test('shortint_public_encrypt_decrypt', (t) => {
let decrypted = Shortint.decrypt(cks, deserialized_ct);
assert.deepStrictEqual(decrypted, BigInt(3));
// Small
let params_small = Shortint.get_parameters_small(2, 2);
let cks_small = Shortint.new_client_key(params_small);
let pk_small = Shortint.new_public_key_small(cks_small);
let ct_small = Shortint.encrypt_with_public_key(pk_small, BigInt(3));
let serialized_ct_small = Shortint.serialize_ciphertext(ct_small);
let deserialized_ct_small = Shortint.deserialize_ciphertext(serialized_ct_small);
let decrypted_small = Shortint.decrypt(cks_small, deserialized_ct_small);
assert.deepStrictEqual(decrypted_small, BigInt(3));
});
test('shortint_compressed_public_encrypt_decrypt', (t) => {
@@ -155,6 +195,23 @@ test('shortint_compressed_public_encrypt_decrypt', (t) => {
let decrypted = Shortint.decrypt(cks, deserialized_ct);
assert.deepStrictEqual(decrypted, BigInt(1));
// Small
let params_small = Shortint.get_parameters_small(2, 2);
let cks_small = Shortint.new_client_key(params_small);
let pk_small = Shortint.new_compressed_public_key_small(cks_small);
let serialized_pk_small = Shortint.serialize_compressed_public_key(pk_small);
let deserialized_pk_small = Shortint.deserialize_compressed_public_key(serialized_pk_small);
let ct_small = Shortint.encrypt_with_compressed_public_key(deserialized_pk_small, BigInt(1));
let serialized_ct_small = Shortint.serialize_ciphertext(ct_small);
let deserialized_ct_small = Shortint.deserialize_ciphertext(serialized_ct_small);
let decrypted_small = Shortint.decrypt(cks_small, deserialized_ct_small);
assert.deepStrictEqual(decrypted_small, BigInt(1));
});
test('shortint_deterministic_keygen', (t) => {

View File

@@ -4,10 +4,50 @@ use std::os::raw::c_int;
use crate::shortint;
pub struct ShortintCiphertext(pub(in crate::c_api) shortint::ciphertext::Ciphertext);
pub struct ShortintCompressedCiphertext(
pub(in crate::c_api) shortint::ciphertext::CompressedCiphertext,
);
#[derive(serde::Serialize, serde::Deserialize)]
pub(in crate::c_api) enum ShortintCiphertextInner {
Big(shortint::ciphertext::CiphertextBig),
Small(shortint::ciphertext::CiphertextSmall),
}
impl From<shortint::ciphertext::CiphertextBig> for ShortintCiphertextInner {
fn from(value: shortint::ciphertext::CiphertextBig) -> Self {
ShortintCiphertextInner::Big(value)
}
}
impl From<shortint::ciphertext::CiphertextSmall> for ShortintCiphertextInner {
fn from(value: shortint::ciphertext::CiphertextSmall) -> Self {
ShortintCiphertextInner::Small(value)
}
}
pub struct ShortintCiphertext(pub(in crate::c_api) ShortintCiphertextInner);
#[derive(serde::Serialize, serde::Deserialize)]
pub(in crate::c_api) enum ShortintCompressedCiphertextInner {
Big(shortint::ciphertext::CompressedCiphertextBig),
Small(shortint::ciphertext::CompressedCiphertextSmall),
}
impl From<shortint::ciphertext::CompressedCiphertextBig> for ShortintCompressedCiphertextInner {
fn from(value: shortint::ciphertext::CompressedCiphertextBig) -> Self {
ShortintCompressedCiphertextInner::Big(value)
}
}
impl From<shortint::ciphertext::CompressedCiphertextSmall> for ShortintCompressedCiphertextInner {
fn from(value: shortint::ciphertext::CompressedCiphertextSmall) -> Self {
ShortintCompressedCiphertextInner::Small(value)
}
}
pub struct ShortintCompressedCiphertext(pub(in crate::c_api) ShortintCompressedCiphertextInner);
#[repr(C)]
pub enum ShortintCiphertextKind {
ShortintCiphertextBig,
ShortintCiphertextSmall,
}
#[no_mangle]
pub unsafe extern "C" fn shortint_ciphertext_set_degree(
@@ -17,7 +57,12 @@ pub unsafe extern "C" fn shortint_ciphertext_set_degree(
catch_panic(|| {
let ciphertext = get_mut_checked(ciphertext).unwrap();
ciphertext.0.degree.0 = degree;
let inner = &mut ciphertext.0;
match inner {
ShortintCiphertextInner::Big(inner_ct) => inner_ct.degree.0 = degree,
ShortintCiphertextInner::Small(inner_ct) => inner_ct.degree.0 = degree,
}
})
}
@@ -31,7 +76,12 @@ pub unsafe extern "C" fn shortint_ciphertext_get_degree(
let ciphertext = get_ref_checked(ciphertext).unwrap();
*result = ciphertext.0.degree.0;
let inner = &ciphertext.0;
*result = match inner {
ShortintCiphertextInner::Big(inner_ct) => inner_ct.degree.0,
ShortintCiphertextInner::Small(inner_ct) => inner_ct.degree.0,
};
})
}
@@ -63,8 +113,7 @@ pub unsafe extern "C" fn shortint_deserialize_ciphertext(
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let ciphertext: shortint::ciphertext::Ciphertext =
bincode::deserialize(buffer_view.into()).unwrap();
let ciphertext = bincode::deserialize(buffer_view.into()).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(ciphertext));
@@ -74,7 +123,7 @@ pub unsafe extern "C" fn shortint_deserialize_ciphertext(
#[no_mangle]
pub unsafe extern "C" fn shortint_decompress_ciphertext(
compressed_ciphertext: *mut ShortintCompressedCiphertext,
compressed_ciphertext: *const ShortintCompressedCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
@@ -84,9 +133,16 @@ pub unsafe extern "C" fn shortint_decompress_ciphertext(
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let compressed_ciphertext = get_mut_checked(compressed_ciphertext).unwrap();
let compressed_ciphertext = get_ref_checked(compressed_ciphertext).unwrap();
let ciphertext = compressed_ciphertext.0.clone().into();
let ciphertext = match &compressed_ciphertext.0 {
ShortintCompressedCiphertextInner::Big(inner) => {
ShortintCiphertextInner::Big(inner.clone().into())
}
ShortintCompressedCiphertextInner::Small(inner) => {
ShortintCiphertextInner::Small(inner.clone().into())
}
};
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(ciphertext));
@@ -122,7 +178,7 @@ pub unsafe extern "C" fn shortint_deserialize_compressed_ciphertext(
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let ciphertext: shortint::ciphertext::CompressedCiphertext =
let ciphertext: ShortintCompressedCiphertextInner =
bincode::deserialize(buffer_view.into()).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCompressedCiphertext(ciphertext));

View File

@@ -45,8 +45,9 @@ pub unsafe extern "C" fn shortint_client_key_encrypt(
let client_key = get_ref_checked(client_key).unwrap();
let heap_allocated_ciphertext =
Box::new(ShortintCiphertext(client_key.0.encrypt(value_to_encrypt)));
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(
client_key.0.encrypt(value_to_encrypt).into(),
));
*result = Box::into_raw(heap_allocated_ciphertext);
})
@@ -68,7 +69,56 @@ pub unsafe extern "C" fn shortint_client_key_encrypt_compressed(
let client_key = get_ref_checked(client_key).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCompressedCiphertext(
client_key.0.encrypt_compressed(value_to_encrypt),
client_key.0.encrypt_compressed(value_to_encrypt).into(),
));
*result = Box::into_raw(heap_allocated_ciphertext);
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_client_key_encrypt_small(
client_key: *const ShortintClientKey,
value_to_encrypt: u64,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
// First fill the result with a null ptr so that if we fail and the return code is not
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let client_key = get_ref_checked(client_key).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(
client_key.0.encrypt_small(value_to_encrypt).into(),
));
*result = Box::into_raw(heap_allocated_ciphertext);
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_client_key_encrypt_compressed_small(
client_key: *const ShortintClientKey,
value_to_encrypt: u64,
result: *mut *mut ShortintCompressedCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
// First fill the result with a null ptr so that if we fail and the return code is not
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let client_key = get_ref_checked(client_key).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCompressedCiphertext(
client_key
.0
.encrypt_compressed_small(value_to_encrypt)
.into(),
));
*result = Box::into_raw(heap_allocated_ciphertext);
@@ -86,8 +136,16 @@ pub unsafe extern "C" fn shortint_client_key_decrypt(
let client_key = get_ref_checked(client_key).unwrap();
let ciphertext_to_decrypt = get_ref_checked(ciphertext_to_decrypt).unwrap();
let inner = &ciphertext_to_decrypt.0;
*result = client_key.0.decrypt(&ciphertext_to_decrypt.0);
*result = match inner {
super::ciphertext::ShortintCiphertextInner::Big(inner_ct) => {
client_key.0.decrypt(inner_ct)
}
super::ciphertext::ShortintCiphertextInner::Small(inner_ct) => {
client_key.0.decrypt(inner_ct)
}
};
})
}

View File

@@ -3,9 +3,9 @@ use std::os::raw::c_int;
use super::parameters::ShortintParameters;
use super::{
ShortintBivariatePBSAccumulator, ShortintCiphertext, ShortintClientKey,
ShortintBivariatePBSLookupTable, ShortintCiphertext, ShortintClientKey,
ShortintCompressedCiphertext, ShortintCompressedPublicKey, ShortintCompressedServerKey,
ShortintPBSAccumulator, ShortintPublicKey, ShortintServerKey,
ShortintPBSLookupTable, ShortintPublicKey, ShortintServerKey,
};
#[no_mangle]
@@ -92,7 +92,7 @@ pub unsafe extern "C" fn destroy_shortint_compressed_ciphertext(
#[no_mangle]
pub unsafe extern "C" fn destroy_shortint_pbs_accumulator(
pbs_accumulator: *mut ShortintPBSAccumulator,
pbs_accumulator: *mut ShortintPBSLookupTable,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(pbs_accumulator).unwrap();
@@ -103,7 +103,7 @@ pub unsafe extern "C" fn destroy_shortint_pbs_accumulator(
#[no_mangle]
pub unsafe extern "C" fn destroy_shortint_bivariate_pbs_accumulator(
pbs_accumulator: *mut ShortintBivariatePBSAccumulator,
pbs_accumulator: *mut ShortintBivariatePBSLookupTable,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(pbs_accumulator).unwrap();

View File

@@ -10,10 +10,11 @@ use std::os::raw::c_int;
use crate::shortint;
pub use ciphertext::{ShortintCiphertext, ShortintCompressedCiphertext};
pub(in crate::c_api) use ciphertext::ShortintCiphertextInner;
pub use ciphertext::{ShortintCiphertext, ShortintCiphertextKind, ShortintCompressedCiphertext};
pub use client_key::ShortintClientKey;
pub use public_key::{ShortintCompressedPublicKey, ShortintPublicKey};
pub use server_key::pbs::{ShortintBivariatePBSAccumulator, ShortintPBSAccumulator};
pub use server_key::pbs::{ShortintBivariatePBSLookupTable, ShortintPBSLookupTable};
pub use server_key::{ShortintCompressedServerKey, ShortintServerKey};
#[no_mangle]

View File

@@ -67,6 +67,32 @@ pub unsafe extern "C" fn shortint_get_parameters(
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_get_parameters_small(
message_bits: u32,
carry_bits: u32,
result: *mut *mut ShortintParameters,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let params: Option<_> = match (message_bits, carry_bits) {
(1, 1) => Some(crate::shortint::parameters::PARAM_SMALL_MESSAGE_1_CARRY_1),
(2, 2) => Some(crate::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2),
(3, 3) => Some(crate::shortint::parameters::PARAM_SMALL_MESSAGE_3_CARRY_3),
(4, 4) => Some(crate::shortint::parameters::PARAM_SMALL_MESSAGE_4_CARRY_4),
_ => None,
};
match params {
Some(params) => {
let params = Box::new(ShortintParameters(params));
*result = Box::into_raw(params);
}
None => *result = std::ptr::null_mut(),
}
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_create_parameters(
lwe_dimension: usize,

View File

@@ -7,14 +7,32 @@ use crate::shortint;
use super::{ShortintCiphertext, ShortintClientKey};
pub struct ShortintPublicKey(pub(in crate::c_api) shortint::public_key::PublicKey);
pub struct ShortintCompressedPublicKey(
pub(in crate::c_api) shortint::public_key::CompressedPublicKey,
);
#[repr(C)]
pub enum ShortintPublicKeyKind {
ShortintPublicKeyBig,
ShortintPublicKeySmall,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub(in crate::c_api) enum ShortintPublicKeyInner {
Big(shortint::public_key::PublicKeyBig),
Small(shortint::public_key::PublicKeySmall),
}
pub struct ShortintPublicKey(pub(in crate::c_api) ShortintPublicKeyInner);
#[derive(serde::Serialize, serde::Deserialize)]
pub(in crate::c_api) enum ShortintCompressedPublicKeyInner {
Big(shortint::public_key::CompressedPublicKeyBig),
Small(shortint::public_key::CompressedPublicKeySmall),
}
pub struct ShortintCompressedPublicKey(pub(in crate::c_api) ShortintCompressedPublicKeyInner);
#[no_mangle]
pub unsafe extern "C" fn shortint_gen_public_key(
client_key: *const ShortintClientKey,
public_key_kind: ShortintPublicKeyKind,
result: *mut *mut ShortintPublicKey,
) -> c_int {
catch_panic(|| {
@@ -26,9 +44,16 @@ pub unsafe extern "C" fn shortint_gen_public_key(
let client_key = get_ref_checked(client_key).unwrap();
let heap_allocated_public_key = Box::new(ShortintPublicKey(
shortint::public_key::PublicKey::new(&client_key.0),
));
let heap_allocated_public_key = match public_key_kind {
ShortintPublicKeyKind::ShortintPublicKeyBig => Box::new(ShortintPublicKey(
ShortintPublicKeyInner::Big(shortint::public_key::PublicKeyBig::new(&client_key.0)),
)),
ShortintPublicKeyKind::ShortintPublicKeySmall => {
Box::new(ShortintPublicKey(ShortintPublicKeyInner::Small(
shortint::public_key::PublicKeySmall::new(&client_key.0),
)))
}
};
*result = Box::into_raw(heap_allocated_public_key);
})
@@ -49,8 +74,14 @@ pub unsafe extern "C" fn shortint_public_key_encrypt(
let public_key = get_ref_checked(public_key).unwrap();
let heap_allocated_ciphertext =
Box::new(ShortintCiphertext(public_key.0.encrypt(value_to_encrypt)));
let heap_allocated_ciphertext = match &public_key.0 {
ShortintPublicKeyInner::Big(inner) => {
Box::new(ShortintCiphertext(inner.encrypt(value_to_encrypt).into()))
}
ShortintPublicKeyInner::Small(inner) => {
Box::new(ShortintCiphertext(inner.encrypt(value_to_encrypt).into()))
}
};
*result = Box::into_raw(heap_allocated_ciphertext);
})
@@ -84,8 +115,7 @@ pub unsafe extern "C" fn shortint_deserialize_public_key(
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let public_key: shortint::public_key::PublicKey =
bincode::deserialize(buffer_view.into()).unwrap();
let public_key: ShortintPublicKeyInner = bincode::deserialize(buffer_view.into()).unwrap();
let heap_allocated_public_key = Box::new(ShortintPublicKey(public_key));
@@ -96,6 +126,7 @@ pub unsafe extern "C" fn shortint_deserialize_public_key(
#[no_mangle]
pub unsafe extern "C" fn shortint_gen_compressed_public_key(
client_key: *const ShortintClientKey,
public_key_kind: ShortintPublicKeyKind,
result: *mut *mut ShortintCompressedPublicKey,
) -> c_int {
catch_panic(|| {
@@ -107,9 +138,18 @@ pub unsafe extern "C" fn shortint_gen_compressed_public_key(
let client_key = get_ref_checked(client_key).unwrap();
let heap_allocated_compressed_public_key = Box::new(ShortintCompressedPublicKey(
shortint::public_key::CompressedPublicKey::new(&client_key.0),
));
let heap_allocated_compressed_public_key = match public_key_kind {
ShortintPublicKeyKind::ShortintPublicKeyBig => Box::new(ShortintCompressedPublicKey(
ShortintCompressedPublicKeyInner::Big(
shortint::public_key::CompressedPublicKeyBig::new(&client_key.0),
),
)),
ShortintPublicKeyKind::ShortintPublicKeySmall => Box::new(ShortintCompressedPublicKey(
ShortintCompressedPublicKeyInner::Small(
shortint::public_key::CompressedPublicKeySmall::new(&client_key.0),
),
)),
};
*result = Box::into_raw(heap_allocated_compressed_public_key);
})
@@ -130,9 +170,14 @@ pub unsafe extern "C" fn shortint_compressed_public_key_encrypt(
let compressed_public_key = get_ref_checked(compressed_public_key).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(
compressed_public_key.0.encrypt(value_to_encrypt),
));
let heap_allocated_ciphertext = match &compressed_public_key.0 {
ShortintCompressedPublicKeyInner::Big(inner) => {
Box::new(ShortintCiphertext(inner.encrypt(value_to_encrypt).into()))
}
ShortintCompressedPublicKeyInner::Small(inner) => {
Box::new(ShortintCiphertext(inner.encrypt(value_to_encrypt).into()))
}
};
*result = Box::into_raw(heap_allocated_ciphertext);
})
@@ -166,8 +211,7 @@ pub unsafe extern "C" fn shortint_deserialize_compressed_public_key(
// checked, then any access to the result pointer will segfault (mimics malloc on failure)
*result = std::ptr::null_mut();
let compressed_public_key: shortint::public_key::CompressedPublicKey =
bincode::deserialize(buffer_view.into()).unwrap();
let compressed_public_key = bincode::deserialize(buffer_view.into()).unwrap();
let heap_allocated_public_key =
Box::new(ShortintCompressedPublicKey(compressed_public_key));
@@ -190,9 +234,14 @@ pub unsafe extern "C" fn shortint_decompress_public_key(
let compressed_public_key = get_ref_checked(compressed_public_key).unwrap();
let heap_allocated_public_key = Box::new(ShortintPublicKey(
shortint::public_key::PublicKey::from(compressed_public_key.0.clone()),
));
let heap_allocated_public_key = match &compressed_public_key.0 {
ShortintCompressedPublicKeyInner::Big(inner) => Box::new(ShortintPublicKey(
ShortintPublicKeyInner::Big(inner.clone().into()),
)),
ShortintCompressedPublicKeyInner::Small(inner) => Box::new(ShortintPublicKey(
ShortintPublicKeyInner::Small(inner.clone().into()),
)),
};
*result = Box::into_raw(heap_allocated_public_key);
})

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_add(
@@ -17,9 +17,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_add(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_add(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_add, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -28,20 +29,20 @@ pub unsafe extern "C" fn shortint_server_key_smart_add(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_add(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_add(&ct_left.0, &ct_right.0),
));
let res = dispatch_binary_server_key_call!(server_key, unchecked_add, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -58,9 +59,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_add_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_add_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_add_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -68,15 +72,18 @@ pub unsafe extern "C" fn shortint_server_key_smart_add_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_add_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_add_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_add_assign,
&mut ct_left_and_result,
&ct_right
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_bitand(
@@ -17,9 +17,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitand(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_bitand(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_bitand, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -28,20 +29,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitand(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_bitand(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_bitand(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_bitand, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -58,9 +60,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitand_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_bitand_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_bitand_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -68,16 +73,19 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitand_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_bitand_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_bitand_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_bitand_assign,
&mut ct_left_and_result,
&ct_right
);
})
}
@@ -95,9 +103,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitxor(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_bitxor(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_bitxor, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -106,20 +115,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitxor(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_bitxor(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_bitxor(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_bitxor, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -136,9 +146,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitxor_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_bitxor_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_bitxor_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -146,16 +159,19 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitxor_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_bitxor_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_bitxor_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_bitxor_assign,
&mut ct_left_and_result,
&ct_right
);
})
}
@@ -173,9 +189,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitor(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_bitor(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_bitor, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -184,20 +201,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitor(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_bitor(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_bitor(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_bitor, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -214,9 +232,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitor_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_bitor_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_bitor_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -224,15 +245,18 @@ pub unsafe extern "C" fn shortint_server_key_smart_bitor_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_bitor_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_bitor_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_bitor_assign,
&mut ct_left_and_result,
&ct_right
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_greater(
@@ -17,9 +17,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_greater(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_greater(&mut ct_left.0, &mut ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_greater,
&mut ct_left,
&mut ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -28,20 +33,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_greater(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_greater(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_greater(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_greater, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -61,11 +67,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_greater_or_equal(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key
.0
.smart_greater_or_equal(&mut ct_left.0, &mut ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_greater_or_equal,
&mut ct_left,
&mut ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -74,22 +83,25 @@ pub unsafe extern "C" fn shortint_server_key_smart_greater_or_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_greater_or_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key
.0
.unchecked_greater_or_equal(&ct_left.0, &ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
unchecked_greater_or_equal,
&ct_left,
&ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -109,9 +121,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_less(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_less(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_less, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -120,20 +133,20 @@ pub unsafe extern "C" fn shortint_server_key_smart_less(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_less(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_less(&ct_left.0, &ct_right.0),
));
let res = dispatch_binary_server_key_call!(server_key, unchecked_less, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -153,11 +166,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_less_or_equal(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key
.0
.smart_less_or_equal(&mut ct_left.0, &mut ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_less_or_equal,
&mut ct_left,
&mut ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -166,22 +182,25 @@ pub unsafe extern "C" fn shortint_server_key_smart_less_or_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_less_or_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key
.0
.unchecked_less_or_equal(&ct_left.0, &ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
unchecked_less_or_equal,
&ct_left,
&ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -201,9 +220,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_equal(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_equal(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_equal, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -212,20 +232,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_equal(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_equal, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -245,11 +266,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_not_equal(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key
.0
.smart_not_equal(&mut ct_left.0, &mut ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_not_equal,
&mut ct_left,
&mut ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -258,20 +282,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_not_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_not_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_not_equal(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_not_equal, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -280,7 +305,7 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_not_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_greater(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -288,11 +313,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_greater(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_greater(&ct_left.0, right),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_scalar_greater, &ct_left, right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -301,7 +327,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_greater(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_greater_or_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -309,13 +335,16 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_greater_or_equal(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key
.0
.smart_scalar_greater_or_equal(&ct_left.0, right),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_scalar_greater_or_equal,
&ct_left,
right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -324,7 +353,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_greater_or_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_less(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -332,11 +361,11 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_less(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_less(&ct_left.0, right),
));
let res = dispatch_binary_server_key_call!(server_key, smart_scalar_less, &ct_left, right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -345,7 +374,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_less(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_less_or_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -353,11 +382,16 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_less_or_equal(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_less_or_equal(&ct_left.0, right),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_scalar_less_or_equal,
&ct_left,
right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -366,7 +400,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_less_or_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -374,11 +408,11 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_equal(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_equal(&ct_left.0, right),
));
let res = dispatch_binary_server_key_call!(server_key, smart_scalar_equal, &ct_left, right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -387,7 +421,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_equal(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_not_equal(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -395,11 +429,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_not_equal(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_not_equal(&ct_left.0, right),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_scalar_not_equal, &ct_left, right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_div(
@@ -17,9 +17,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_div(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_div(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_div, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -28,20 +29,20 @@ pub unsafe extern "C" fn shortint_server_key_smart_div(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_div(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_div(&ct_left.0, &ct_right.0),
));
let res = dispatch_binary_server_key_call!(server_key, unchecked_div, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -58,9 +59,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_div_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_div_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_div_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -68,23 +72,26 @@ pub unsafe extern "C" fn shortint_server_key_smart_div_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_div_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_div_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_div_assign,
&mut ct_left_and_result,
&ct_right
);
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_div(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -92,11 +99,12 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_div(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_div(&ct_left.0, right),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_scalar_div, &ct_left, right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -112,16 +120,19 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_div_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.unchecked_scalar_div_assign(&mut ct_left_and_result.0, right);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_div_assign,
&mut ct_left_and_result,
right
);
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_mod(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -129,11 +140,12 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_mod(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_mod(&ct_left.0, right),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_scalar_mod, &ct_left, right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -149,8 +161,11 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_mod_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.unchecked_scalar_mod_assign(&mut ct_left_and_result.0, right);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_mod_assign,
&mut ct_left_and_result,
right
);
})
}

View File

@@ -4,7 +4,7 @@ use std::os::raw::c_int;
use crate::shortint;
use super::ShortintCiphertext;
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintCiphertextKind};
pub mod add;
pub mod bitwise_op;
@@ -50,6 +50,7 @@ pub unsafe extern "C" fn shortint_gen_server_key(
pub unsafe extern "C" fn shortint_server_key_create_trivial(
server_key: *const ShortintServerKey,
value_to_trivially_encrypt: u64,
ciphertext_kind: ShortintCiphertextKind,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
@@ -57,9 +58,18 @@ pub unsafe extern "C" fn shortint_server_key_create_trivial(
let server_key = get_ref_checked(server_key).unwrap();
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(
server_key.0.create_trivial(value_to_trivially_encrypt),
));
let res = match ciphertext_kind {
ShortintCiphertextKind::ShortintCiphertextBig => ShortintCiphertextInner::Big(
server_key.0.create_trivial(value_to_trivially_encrypt),
),
ShortintCiphertextKind::ShortintCiphertextSmall => ShortintCiphertextInner::Small(
server_key
.0
.create_trivial_small(value_to_trivially_encrypt),
),
};
let heap_allocated_ciphertext = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ciphertext);
})

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_mul(
@@ -17,9 +17,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_mul(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_mul_lsb(&mut ct_left.0, &mut ct_right.0),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_mul_lsb,
&mut ct_left,
&mut ct_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -28,20 +33,21 @@ pub unsafe extern "C" fn shortint_server_key_smart_mul(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_mul(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_mul_lsb(&ct_left.0, &ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_mul_lsb, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -58,9 +64,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_mul_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_mul_lsb_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_mul_lsb_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -68,15 +77,18 @@ pub unsafe extern "C" fn shortint_server_key_smart_mul_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_mul_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_mul_lsb_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_mul_lsb_assign,
&mut ct_left_and_result,
&ct_right
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_neg(
@@ -15,8 +15,9 @@ pub unsafe extern "C" fn shortint_server_key_smart_neg(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let heap_allocated_ct_result =
Box::new(ShortintCiphertext(server_key.0.smart_neg(&mut ct_left.0)));
let res = dispatch_unary_server_key_call!(server_key, smart_neg, &mut ct_left);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -25,17 +26,18 @@ pub unsafe extern "C" fn shortint_server_key_smart_neg(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_neg(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result =
Box::new(ShortintCiphertext(server_key.0.unchecked_neg(&ct_left.0)));
let res = dispatch_unary_server_key_call!(server_key, unchecked_neg, &ct_left);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -50,7 +52,11 @@ pub unsafe extern "C" fn shortint_server_key_smart_neg_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key.0.smart_neg_assign(&mut ct_left_and_result.0);
dispatch_unary_assign_server_key_call!(
server_key,
smart_neg_assign,
&mut ct_left_and_result
);
})
}
@@ -63,6 +69,10 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_neg_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key.0.unchecked_neg_assign(&mut ct_left_and_result.0);
dispatch_unary_assign_server_key_call!(
server_key,
unchecked_neg_assign,
&mut ct_left_and_result
);
})
}

View File

@@ -1,22 +1,24 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
// This is the accepted way to declare a pointer to a C function/callback in cbindgen
pub type AccumulatorCallback = Option<extern "C" fn(u64) -> u64>;
pub type BivariateAccumulatorCallback = Option<extern "C" fn(u64, u64) -> u64>;
pub type LookupTableCallback = Option<extern "C" fn(u64) -> u64>;
pub type BivariateLookupTableCallback = Option<extern "C" fn(u64, u64) -> u64>;
pub struct ShortintPBSAccumulator(pub(in crate::c_api) crate::shortint::server_key::Accumulator);
pub struct ShortintBivariatePBSAccumulator(
pub(in crate::c_api) crate::shortint::server_key::BivariateAccumulator,
pub struct ShortintPBSLookupTable(
pub(in crate::c_api) crate::shortint::server_key::LookupTableOwned,
);
pub struct ShortintBivariatePBSLookupTable(
pub(in crate::c_api) crate::shortint::server_key::BivariateLookupTableOwned,
);
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_generate_pbs_accumulator(
server_key: *const ShortintServerKey,
accumulator_callback: AccumulatorCallback,
result: *mut *mut ShortintPBSAccumulator,
accumulator_callback: LookupTableCallback,
result: *mut *mut ShortintPBSLookupTable,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
@@ -31,7 +33,7 @@ pub unsafe extern "C" fn shortint_server_key_generate_pbs_accumulator(
// Closure is required as extern "C" fn does not implement the Fn trait
#[allow(clippy::redundant_closure)]
let heap_allocated_accumulator = Box::new(ShortintPBSAccumulator(
let heap_allocated_accumulator = Box::new(ShortintPBSLookupTable(
server_key
.0
.generate_accumulator(|x: u64| accumulator_callback(x)),
@@ -44,7 +46,7 @@ pub unsafe extern "C" fn shortint_server_key_generate_pbs_accumulator(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_programmable_bootstrap(
server_key: *const ShortintServerKey,
accumulator: *const ShortintPBSAccumulator,
accumulator: *const ShortintPBSLookupTable,
ct_in: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -59,11 +61,16 @@ pub unsafe extern "C" fn shortint_server_key_programmable_bootstrap(
let accumulator = get_ref_checked(accumulator).unwrap();
let ct_in = get_ref_checked(ct_in).unwrap();
let heap_allocated_result = Box::new(ShortintCiphertext(
server_key
.0
.keyswitch_programmable_bootstrap(&ct_in.0, &accumulator.0),
));
let res = match &ct_in.0 {
ShortintCiphertextInner::Big(inner) => {
ShortintCiphertextInner::Big(server_key.0.apply_lookup_table(inner, &accumulator.0))
}
ShortintCiphertextInner::Small(inner) => ShortintCiphertextInner::Small(
server_key.0.apply_lookup_table(inner, &accumulator.0),
),
};
let heap_allocated_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_result);
})
@@ -72,7 +79,7 @@ pub unsafe extern "C" fn shortint_server_key_programmable_bootstrap(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_programmable_bootstrap_assign(
server_key: *const ShortintServerKey,
accumulator: *const ShortintPBSAccumulator,
accumulator: *const ShortintPBSLookupTable,
ct_in_and_result: *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
@@ -80,17 +87,23 @@ pub unsafe extern "C" fn shortint_server_key_programmable_bootstrap_assign(
let accumulator = get_ref_checked(accumulator).unwrap();
let ct_in_and_result = get_mut_checked(ct_in_and_result).unwrap();
server_key
.0
.keyswitch_programmable_bootstrap_assign(&mut ct_in_and_result.0, &accumulator.0);
match &mut ct_in_and_result.0 {
ShortintCiphertextInner::Big(inner) => server_key
.0
.apply_lookup_table_assign(inner, &accumulator.0),
ShortintCiphertextInner::Small(inner) => server_key
.0
.apply_lookup_table_assign(inner, &accumulator.0),
};
})
}
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_generate_bivariate_pbs_accumulator(
server_key: *const ShortintServerKey,
accumulator_callback: BivariateAccumulatorCallback,
result: *mut *mut ShortintBivariatePBSAccumulator,
accumulator_callback: BivariateLookupTableCallback,
result: *mut *mut ShortintBivariatePBSLookupTable,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
@@ -105,7 +118,7 @@ pub unsafe extern "C" fn shortint_server_key_generate_bivariate_pbs_accumulator(
// Closure is required as extern "C" fn does not implement the Fn trait
#[allow(clippy::redundant_closure)]
let heap_allocated_accumulator = Box::new(ShortintBivariatePBSAccumulator(
let heap_allocated_accumulator = Box::new(ShortintBivariatePBSLookupTable(
server_key
.0
.generate_accumulator_bivariate(|x: u64, y: u64| accumulator_callback(x, y)),
@@ -118,7 +131,7 @@ pub unsafe extern "C" fn shortint_server_key_generate_bivariate_pbs_accumulator(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_bivariate_programmable_bootstrap(
server_key: *const ShortintServerKey,
accumulator: *const ShortintBivariatePBSAccumulator,
accumulator: *const ShortintBivariatePBSLookupTable,
ct_left: *const ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
@@ -135,13 +148,45 @@ pub unsafe extern "C" fn shortint_server_key_bivariate_programmable_bootstrap(
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_result = Box::new(ShortintCiphertext(
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_bivariate_pbs(&server_key.0, &ct_left.0, &mut ct_right.0, &accumulator.0)
.unwrap()
}),
));
let res = match (&ct_left.0, &mut ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => ShortintCiphertextInner::Big(
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_apply_lookup_table_bivariate(
&server_key.0,
inner_left,
inner_right,
&accumulator.0,
)
.unwrap()
}),
),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => ShortintCiphertextInner::Small(
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_apply_lookup_table_bivariate(
&server_key.0,
inner_left,
inner_right,
&accumulator.0,
)
.unwrap()
}),
),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
};
let heap_allocated_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_result);
})
@@ -150,7 +195,7 @@ pub unsafe extern "C" fn shortint_server_key_bivariate_programmable_bootstrap(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_bivariate_programmable_bootstrap_assign(
server_key: *const ShortintServerKey,
accumulator: *const ShortintBivariatePBSAccumulator,
accumulator: *const ShortintBivariatePBSLookupTable,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
) -> c_int {
@@ -160,15 +205,38 @@ pub unsafe extern "C" fn shortint_server_key_bivariate_programmable_bootstrap_as
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_bivariate_pbs_assign(
&server_key.0,
&mut ct_left_and_result.0,
&mut ct_right.0,
&accumulator.0,
)
.unwrap()
});
match (&mut ct_left_and_result.0, &mut ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_apply_lookup_table_bivariate_assign(
&server_key.0,
inner_left,
inner_right,
&accumulator.0,
)
.unwrap()
}),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_apply_lookup_table_bivariate_assign(
&server_key.0,
inner_left,
inner_right,
&accumulator.0,
)
.unwrap()
}),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
};
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_add(
@@ -16,9 +16,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_add(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_add(&mut ct_left.0, scalar_right),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_scalar_add,
&mut ct_left,
scalar_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -27,7 +32,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_add(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_add(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
scalar_right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -35,11 +40,16 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_add(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_add(&ct_left.0, scalar_right),
));
let res = dispatch_binary_server_key_call!(
server_key,
unchecked_scalar_add,
&ct_left,
scalar_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -55,9 +65,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_add_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.smart_scalar_add_assign(&mut ct_left_and_result.0, scalar_right);
dispatch_binary_assign_server_key_call!(
server_key,
smart_scalar_add_assign,
&mut ct_left_and_result,
scalar_right
);
})
}
@@ -71,8 +84,11 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_add_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.unchecked_scalar_add_assign(&mut ct_left_and_result.0, scalar_right);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_add_assign,
&mut ct_left_and_result,
scalar_right
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_mul(
@@ -16,9 +16,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_mul(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_mul(&mut ct_left.0, scalar_right),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_scalar_mul,
&mut ct_left,
scalar_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -27,7 +32,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_mul(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_mul(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
scalar_right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -35,11 +40,16 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_mul(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_mul(&ct_left.0, scalar_right),
));
let res = dispatch_binary_server_key_call!(
server_key,
unchecked_scalar_mul,
&ct_left,
scalar_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -55,9 +65,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_mul_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.smart_scalar_mul_assign(&mut ct_left_and_result.0, scalar_right);
dispatch_binary_assign_server_key_call!(
server_key,
smart_scalar_mul_assign,
&mut ct_left_and_result,
scalar_right
);
})
}
@@ -71,8 +84,11 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_mul_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.unchecked_scalar_mul_assign(&mut ct_left_and_result.0, scalar_right);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_mul_assign,
&mut ct_left_and_result,
scalar_right
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_sub(
@@ -16,9 +16,14 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_sub(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_sub(&mut ct_left.0, scalar_right),
));
let res = dispatch_binary_server_key_call!(
server_key,
smart_scalar_sub,
&mut ct_left,
scalar_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -27,7 +32,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_sub(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_sub(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
scalar_right: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -35,11 +40,16 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_sub(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_sub(&ct_left.0, scalar_right),
));
let res = dispatch_binary_server_key_call!(
server_key,
unchecked_scalar_sub,
&ct_left,
scalar_right
);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -55,9 +65,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_sub_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.smart_scalar_sub_assign(&mut ct_left_and_result.0, scalar_right);
dispatch_binary_assign_server_key_call!(
server_key,
smart_scalar_sub_assign,
&mut ct_left_and_result,
scalar_right
);
})
}
@@ -71,8 +84,11 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_sub_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
server_key
.0
.unchecked_scalar_sub_assign(&mut ct_left_and_result.0, scalar_right);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_sub_assign,
&mut ct_left_and_result,
scalar_right
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_scalar_left_shift(
@@ -16,9 +16,9 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_left_shift(
let server_key = get_ref_checked(server_key).unwrap();
let ct = get_mut_checked(ct).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_scalar_left_shift(&mut ct.0, shift),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_scalar_left_shift, &mut ct, shift);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -27,7 +27,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_left_shift(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_left_shift(
server_key: *const ShortintServerKey,
ct: *mut ShortintCiphertext,
ct: *const ShortintCiphertext,
shift: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -35,11 +35,12 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_left_shift(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct = get_mut_checked(ct).unwrap();
let ct = get_ref_checked(ct).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_left_shift(&ct.0, shift),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_scalar_left_shift, &ct, shift);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -58,7 +59,7 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_right_shift(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_right_shift(
server_key: *const ShortintServerKey,
ct: *mut ShortintCiphertext,
ct: *const ShortintCiphertext,
shift: u8,
result: *mut *mut ShortintCiphertext,
) -> c_int {
@@ -66,11 +67,12 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_right_shift(
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct = get_mut_checked(ct).unwrap();
let ct = get_ref_checked(ct).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_scalar_right_shift(&ct.0, shift),
));
let res =
dispatch_binary_server_key_call!(server_key, unchecked_scalar_right_shift, &ct, shift);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -86,9 +88,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_scalar_left_shift_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct = get_mut_checked(ct).unwrap();
server_key
.0
.smart_scalar_left_shift_assign(&mut ct.0, shift);
dispatch_binary_assign_server_key_call!(
server_key,
smart_scalar_left_shift_assign,
&mut ct,
shift
);
})
}
@@ -102,9 +107,12 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_left_shift_assign(
let server_key = get_ref_checked(server_key).unwrap();
let ct = get_mut_checked(ct).unwrap();
server_key
.0
.unchecked_scalar_left_shift_assign(&mut ct.0, shift);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_left_shift_assign,
&mut ct,
shift
);
})
}
@@ -127,8 +135,11 @@ pub unsafe extern "C" fn shortint_server_key_unchecked_scalar_right_shift_assign
let server_key = get_ref_checked(server_key).unwrap();
let ct = get_mut_checked(ct).unwrap();
server_key
.0
.unchecked_scalar_right_shift_assign(&mut ct.0, shift);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_scalar_right_shift_assign,
&mut ct,
shift
);
})
}

View File

@@ -1,7 +1,7 @@
use crate::c_api::utils::*;
use std::os::raw::c_int;
use super::{ShortintCiphertext, ShortintServerKey};
use super::{ShortintCiphertext, ShortintCiphertextInner, ShortintServerKey};
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_smart_sub(
@@ -17,9 +17,10 @@ pub unsafe extern "C" fn shortint_server_key_smart_sub(
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.smart_sub(&mut ct_left.0, &mut ct_right.0),
));
let res =
dispatch_binary_server_key_call!(server_key, smart_sub, &mut ct_left, &mut ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -28,20 +29,20 @@ pub unsafe extern "C" fn shortint_server_key_smart_sub(
#[no_mangle]
pub unsafe extern "C" fn shortint_server_key_unchecked_sub(
server_key: *const ShortintServerKey,
ct_left: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_left: *const ShortintCiphertext,
ct_right: *const ShortintCiphertext,
result: *mut *mut ShortintCiphertext,
) -> c_int {
catch_panic(|| {
check_ptr_is_non_null_and_aligned(result).unwrap();
let server_key = get_ref_checked(server_key).unwrap();
let ct_left = get_mut_checked(ct_left).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_left = get_ref_checked(ct_left).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
let heap_allocated_ct_result = Box::new(ShortintCiphertext(
server_key.0.unchecked_sub(&ct_left.0, &ct_right.0),
));
let res = dispatch_binary_server_key_call!(server_key, unchecked_sub, &ct_left, &ct_right);
let heap_allocated_ct_result = Box::new(ShortintCiphertext(res));
*result = Box::into_raw(heap_allocated_ct_result);
})
@@ -58,9 +59,12 @@ pub unsafe extern "C" fn shortint_server_key_smart_sub_assign(
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
server_key
.0
.smart_sub_assign(&mut ct_left_and_result.0, &mut ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
smart_sub_assign,
&mut ct_left_and_result,
&mut ct_right
);
})
}
@@ -68,15 +72,18 @@ pub unsafe extern "C" fn shortint_server_key_smart_sub_assign(
pub unsafe extern "C" fn shortint_server_key_unchecked_sub_assign(
server_key: *const ShortintServerKey,
ct_left_and_result: *mut ShortintCiphertext,
ct_right: *mut ShortintCiphertext,
ct_right: *const ShortintCiphertext,
) -> c_int {
catch_panic(|| {
let server_key = get_ref_checked(server_key).unwrap();
let ct_left_and_result = get_mut_checked(ct_left_and_result).unwrap();
let ct_right = get_mut_checked(ct_right).unwrap();
let ct_right = get_ref_checked(ct_right).unwrap();
server_key
.0
.unchecked_sub_assign(&mut ct_left_and_result.0, &ct_right.0);
dispatch_binary_assign_server_key_call!(
server_key,
unchecked_sub_assign,
&mut ct_left_and_result,
&ct_right
);
})
}

View File

@@ -44,3 +44,164 @@ pub fn get_ref_checked<'a, T>(ptr: *const T) -> Result<&'a T, String> {
Err(e) => Err(e),
}
}
macro_rules! dispatch_binary_server_key_call {
($server_key:ident, $method:tt, &mut $ct_left:ident, &mut $ct_right:ident) => {
match (&mut $ct_left.0, &mut $ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => ShortintCiphertextInner::Big($server_key.0.$method(inner_left, inner_right)),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => ShortintCiphertextInner::Small($server_key.0.$method(inner_left, inner_right)),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
}
};
($server_key:ident, $method:tt, &mut $ct_left:ident, &$ct_right:ident) => {
match (&mut $ct_left.0, &$ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => ShortintCiphertextInner::Big($server_key.0.$method(inner_left, inner_right)),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => ShortintCiphertextInner::Small($server_key.0.$method(inner_left, inner_right)),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
}
};
($server_key:ident, $method:tt, &$ct_left:ident, &$ct_right:ident) => {
match (&$ct_left.0, &$ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => ShortintCiphertextInner::Big($server_key.0.$method(inner_left, inner_right)),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => ShortintCiphertextInner::Small($server_key.0.$method(inner_left, inner_right)),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
}
};
($server_key:ident, $method:tt, &mut $ct_left:ident, $scalar_right:ident) => {
match &mut $ct_left.0 {
ShortintCiphertextInner::Big(inner_left) => {
ShortintCiphertextInner::Big($server_key.0.$method(inner_left, $scalar_right))
}
ShortintCiphertextInner::Small(inner_left) => {
ShortintCiphertextInner::Small($server_key.0.$method(inner_left, $scalar_right))
}
}
};
($server_key:ident, $method:tt, &$ct_left:ident, $scalar_right:ident) => {
match &$ct_left.0 {
ShortintCiphertextInner::Big(inner_left) => {
ShortintCiphertextInner::Big($server_key.0.$method(inner_left, $scalar_right))
}
ShortintCiphertextInner::Small(inner_left) => {
ShortintCiphertextInner::Small($server_key.0.$method(inner_left, $scalar_right))
}
}
};
}
pub(in crate::c_api) use dispatch_binary_server_key_call;
macro_rules! dispatch_binary_assign_server_key_call {
($server_key:ident, $method:tt, &mut $ct_left_and_result:ident, &mut $ct_right:ident) => {
match (&mut $ct_left_and_result.0, &mut $ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => $server_key.0.$method(inner_left, inner_right),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => $server_key.0.$method(inner_left, inner_right),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
}
};
($server_key:ident, $method:tt, &mut $ct_left_and_result:ident, &$ct_right:ident) => {
match (&mut $ct_left_and_result.0, &$ct_right.0) {
(
ShortintCiphertextInner::Big(inner_left),
ShortintCiphertextInner::Big(inner_right),
) => $server_key.0.$method(inner_left, inner_right),
(
ShortintCiphertextInner::Small(inner_left),
ShortintCiphertextInner::Small(inner_right),
) => $server_key.0.$method(inner_left, inner_right),
_ => Err(
"Got mixed Big and Small ciphertexts, this is not supported, \
did you mistakenly use a Small ciphertext with a Big ciphertext?",
)
.unwrap(),
}
};
($server_key:ident, $method:tt, &mut $ct_left_and_result:ident, $scalar_right:ident) => {
match (&mut $ct_left_and_result.0) {
ShortintCiphertextInner::Big(inner_left) => {
$server_key.0.$method(inner_left, $scalar_right)
}
ShortintCiphertextInner::Small(inner_left) => {
$server_key.0.$method(inner_left, $scalar_right)
}
}
};
}
pub(in crate::c_api) use dispatch_binary_assign_server_key_call;
macro_rules! dispatch_unary_server_key_call {
($server_key:ident, $method:tt, &mut $ct_left:ident) => {
match (&mut $ct_left.0) {
ShortintCiphertextInner::Big(inner_left) => {
ShortintCiphertextInner::Big($server_key.0.$method(inner_left))
}
ShortintCiphertextInner::Small(inner_left) => {
ShortintCiphertextInner::Small($server_key.0.$method(inner_left))
}
}
};
($server_key:ident, $method:tt, & $ct_left:ident) => {
match (&$ct_left.0) {
ShortintCiphertextInner::Big(inner_left) => {
ShortintCiphertextInner::Big($server_key.0.$method(inner_left))
}
ShortintCiphertextInner::Small(inner_left) => {
ShortintCiphertextInner::Small($server_key.0.$method(inner_left))
}
}
};
}
pub(in crate::c_api) use dispatch_unary_server_key_call;
macro_rules! dispatch_unary_assign_server_key_call {
($server_key:ident, $method:tt, &mut $ct_left_and_result:ident) => {
match (&mut $ct_left_and_result.0) {
ShortintCiphertextInner::Big(inner_left) => $server_key.0.$method(inner_left),
ShortintCiphertextInner::Small(inner_left) => $server_key.0.$method(inner_left),
}
};
}
pub(in crate::c_api) use dispatch_unary_assign_server_key_call;

View File

@@ -1,6 +1,6 @@
//! This module implements the ciphertext structures.
use crate::shortint::{
Ciphertext as ShortintCiphertext, CompressedCiphertext as CompressedShortintCiphertext,
CiphertextBig as ShortintCiphertext, CompressedCiphertextBig as CompressedShortintCiphertext,
};
use serde::{Deserialize, Serialize};

View File

@@ -14,7 +14,7 @@ use crate::integer::client_key::utils::i_crt;
use crate::integer::encryption::{encrypt_crt, encrypt_words_radix_impl, AsLittleEndianWords};
use crate::shortint::parameters::MessageModulus;
use crate::shortint::{
Ciphertext as ShortintCiphertext, ClientKey as ShortintClientKey,
CiphertextBig as ShortintCiphertext, ClientKey as ShortintClientKey,
Parameters as ShortintParameters,
};
use serde::{Deserialize, Serialize};
@@ -288,7 +288,7 @@ impl ClientKey {
decrypt_block: F,
) where
T: AsLittleEndianWords,
F: Fn(&crate::shortint::ClientKey, &crate::shortint::Ciphertext) -> u64,
F: Fn(&crate::shortint::ClientKey, &crate::shortint::CiphertextBig) -> u64,
{
// limit to know when we have at least 64 bits
// of decrypted data

View File

@@ -2,7 +2,7 @@
use super::ClientKey;
use crate::integer::RadixCiphertext;
use crate::shortint::{Ciphertext as ShortintCiphertext, Parameters as ShortintParameters};
use crate::shortint::{CiphertextBig as ShortintCiphertext, Parameters as ShortintParameters};
use serde::{Deserialize, Serialize};

View File

@@ -119,13 +119,17 @@ impl BlockEncryptionKey for crate::shortint::ClientKey {
}
}
impl BlockEncryptionKey for crate::shortint::PublicKey {
impl<OpOrder: crate::shortint::PBSOrderMarker> BlockEncryptionKey
for crate::shortint::PublicKeyBase<OpOrder>
{
fn parameters(&self) -> &crate::shortint::Parameters {
&self.parameters
}
}
impl BlockEncryptionKey for crate::shortint::CompressedPublicKey {
impl<OpOrder: crate::shortint::PBSOrderMarker> BlockEncryptionKey
for crate::shortint::CompressedPublicKeyBase<OpOrder>
{
fn parameters(&self) -> &crate::shortint::Parameters {
&self.parameters
}

View File

@@ -2,7 +2,7 @@ use crate::integer::ciphertext::{CrtCiphertext, RadixCiphertext};
use crate::integer::client_key::ClientKey;
use crate::integer::encryption::{encrypt_crt, encrypt_words_radix_impl, AsLittleEndianWords};
use crate::shortint::parameters::MessageModulus;
use crate::shortint::CompressedPublicKey as ShortintCompressedPublicKey;
use crate::shortint::CompressedPublicKeyBig as ShortintCompressedPublicKey;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct CompressedPublicKey {
@@ -24,11 +24,7 @@ impl CompressedPublicKey {
message: T,
num_blocks: usize,
) -> RadixCiphertext {
self.encrypt_words_radix(
message,
num_blocks,
crate::shortint::CompressedPublicKey::encrypt,
)
self.encrypt_words_radix(message, num_blocks, ShortintCompressedPublicKey::encrypt)
}
pub fn encrypt_radix_without_padding(
@@ -39,7 +35,7 @@ impl CompressedPublicKey {
self.encrypt_words_radix(
message,
num_blocks,
crate::shortint::CompressedPublicKey::encrypt_without_padding,
ShortintCompressedPublicKey::encrypt_without_padding,
)
}
@@ -51,7 +47,7 @@ impl CompressedPublicKey {
) -> RadixCiphertextType
where
T: AsLittleEndianWords,
F: Fn(&crate::shortint::CompressedPublicKey, u64) -> Block,
F: Fn(&ShortintCompressedPublicKey, u64) -> Block,
RadixCiphertextType: From<Vec<Block>>,
{
encrypt_words_radix_impl(&self.key, message_words, num_blocks, encrypt_block)
@@ -61,7 +57,7 @@ impl CompressedPublicKey {
self.encrypt_crt_impl(
message,
base_vec,
crate::shortint::CompressedPublicKey::encrypt_with_message_modulus,
ShortintCompressedPublicKey::encrypt_with_message_modulus,
)
}
@@ -78,7 +74,7 @@ impl CompressedPublicKey {
encrypt_block: F,
) -> CrtCiphertextType
where
F: Fn(&crate::shortint::CompressedPublicKey, u64, MessageModulus) -> Block,
F: Fn(&ShortintCompressedPublicKey, u64, MessageModulus) -> Block,
CrtCiphertextType: From<(Vec<Block>, Vec<u64>)>,
{
encrypt_crt(&self.key, message, base_vec, encrypt_block)

View File

@@ -2,7 +2,7 @@ use crate::integer::ciphertext::{CrtCiphertext, RadixCiphertext};
use crate::integer::client_key::ClientKey;
use crate::integer::encryption::{encrypt_crt, encrypt_words_radix_impl, AsLittleEndianWords};
use crate::shortint::parameters::MessageModulus;
use crate::shortint::PublicKey as ShortintPublicKey;
use crate::shortint::PublicKeyBig as ShortintPublicKey;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PublicKey {
@@ -24,7 +24,7 @@ impl PublicKey {
message: T,
num_blocks: usize,
) -> RadixCiphertext {
self.encrypt_words_radix(message, num_blocks, crate::shortint::PublicKey::encrypt)
self.encrypt_words_radix(message, num_blocks, ShortintPublicKey::encrypt)
}
pub fn encrypt_radix_without_padding(
@@ -35,7 +35,7 @@ impl PublicKey {
self.encrypt_words_radix(
message,
num_blocks,
crate::shortint::PublicKey::encrypt_without_padding,
ShortintPublicKey::encrypt_without_padding,
)
}
@@ -47,7 +47,7 @@ impl PublicKey {
) -> RadixCiphertextType
where
T: AsLittleEndianWords,
F: Fn(&crate::shortint::PublicKey, u64) -> Block,
F: Fn(&ShortintPublicKey, u64) -> Block,
RadixCiphertextType: From<Vec<Block>>,
{
encrypt_words_radix_impl(&self.key, message_words, num_blocks, encrypt_block)
@@ -57,7 +57,7 @@ impl PublicKey {
self.encrypt_crt_impl(
message,
base_vec,
crate::shortint::PublicKey::encrypt_with_message_modulus,
ShortintPublicKey::encrypt_with_message_modulus,
)
}
@@ -74,7 +74,7 @@ impl PublicKey {
encrypt_block: F,
) -> CrtCiphertextType
where
F: Fn(&crate::shortint::PublicKey, u64, MessageModulus) -> Block,
F: Fn(&ShortintPublicKey, u64, MessageModulus) -> Block,
CrtCiphertextType: From<(Vec<Block>, Vec<u64>)>,
{
encrypt_crt(&self.key, message, base_vec, encrypt_block)

View File

@@ -2,7 +2,7 @@ use rayon::prelude::*;
use super::ServerKey;
use crate::integer::RadixCiphertext;
use crate::shortint::server_key::Accumulator;
use crate::shortint::server_key::LookupTableOwned;
/// Simple enum to select whether we are looking for the min or the max
enum MinMaxSelector {
@@ -22,11 +22,11 @@ fn has_non_zero_carries(ct: &RadixCiphertext) -> bool {
/// during the comparisons and min/max algorithms
pub struct Comparator<'a> {
server_key: &'a ServerKey,
sign_accumulator: Accumulator,
selection_accumulator: Accumulator,
mask_accumulator: Accumulator,
x_accumulator: Accumulator,
y_accumulator: Accumulator,
sign_accumulator: LookupTableOwned,
selection_accumulator: LookupTableOwned,
mask_accumulator: LookupTableOwned,
x_accumulator: LookupTableOwned,
y_accumulator: LookupTableOwned,
}
impl<'a> Comparator<'a> {
@@ -127,8 +127,8 @@ impl<'a> Comparator<'a> {
/// Expects the carry buffer to be empty
fn pack_block_chunk(
&self,
chunk: &[crate::shortint::Ciphertext],
) -> crate::shortint::Ciphertext {
chunk: &[crate::shortint::CiphertextBig],
) -> crate::shortint::CiphertextBig {
let low = &chunk[0];
let mut high = chunk[1].clone();
debug_assert!(high.degree.0 < high.message_modulus.0);
@@ -145,8 +145,8 @@ impl<'a> Comparator<'a> {
/// Expects the carry buffer to be empty
fn pack_block_assign(
&self,
low: &crate::shortint::Ciphertext,
high: &mut crate::shortint::Ciphertext,
low: &crate::shortint::CiphertextBig,
high: &mut crate::shortint::CiphertextBig,
) {
debug_assert!(high.degree.0 < high.message_modulus.0);
self.server_key
@@ -161,8 +161,8 @@ impl<'a> Comparator<'a> {
// - 2 if lhs > rhs
fn compare_block_assign(
&self,
lhs: &mut crate::shortint::Ciphertext,
rhs: &crate::shortint::Ciphertext,
lhs: &mut crate::shortint::CiphertextBig,
rhs: &crate::shortint::CiphertextBig,
) {
// When rhs > lhs, the subtraction will overflow, and the bit of padding will be set to 1
// meaning that the output of the pbs will be the negative (modulo message space)
@@ -180,7 +180,7 @@ impl<'a> Comparator<'a> {
crate::core_crypto::algorithms::lwe_ciphertext_sub_assign(&mut lhs.ct, &rhs.ct);
self.server_key
.key
.keyswitch_programmable_bootstrap_assign(lhs, &self.sign_accumulator);
.apply_lookup_table_assign(lhs, &self.sign_accumulator);
// Here Lhs can have the following values: (-1) % (message modulus * carry modulus), 0, 1
// So the output values after the addition will be: 0, 1, 2
@@ -200,7 +200,7 @@ impl<'a> Comparator<'a> {
&self,
lhs: &RadixCiphertext,
rhs: &RadixCiphertext,
) -> crate::shortint::Ciphertext {
) -> crate::shortint::CiphertextBig {
assert_eq!(lhs.blocks.len(), rhs.blocks.len());
let num_block = lhs.blocks.len();
@@ -248,10 +248,9 @@ impl<'a> Comparator<'a> {
.key
.unchecked_add_assign(&mut selection, comparison);
self.server_key.key.keyswitch_programmable_bootstrap_assign(
&mut selection,
&self.selection_accumulator,
);
self.server_key
.key
.apply_lookup_table_assign(&mut selection, &self.selection_accumulator);
}
selection
@@ -264,7 +263,7 @@ impl<'a> Comparator<'a> {
&self,
lhs: &RadixCiphertext,
rhs: &RadixCiphertext,
) -> crate::shortint::Ciphertext {
) -> crate::shortint::CiphertextBig {
assert_eq!(lhs.blocks.len(), rhs.blocks.len());
let num_block = lhs.blocks.len();
@@ -322,10 +321,9 @@ impl<'a> Comparator<'a> {
.unchecked_scalar_mul_assign(&mut high, 4);
self.server_key.key.unchecked_add_assign(&mut high, low);
self.server_key.key.keyswitch_programmable_bootstrap_assign(
&mut high,
&self.selection_accumulator,
);
self.server_key
.key
.apply_lookup_table_assign(&mut high, &self.selection_accumulator);
high
})
.collect_into_vec(&mut comparisons_2);
@@ -345,7 +343,7 @@ impl<'a> Comparator<'a> {
&self,
lhs: &mut RadixCiphertext,
rhs: &mut RadixCiphertext,
) -> crate::shortint::Ciphertext {
) -> crate::shortint::CiphertextBig {
if has_non_zero_carries(lhs) {
self.server_key.full_propagate(lhs);
}
@@ -359,7 +357,7 @@ impl<'a> Comparator<'a> {
&self,
lhs: &mut RadixCiphertext,
rhs: &mut RadixCiphertext,
) -> crate::shortint::Ciphertext {
) -> crate::shortint::CiphertextBig {
rayon::join(
|| {
if has_non_zero_carries(lhs) {
@@ -391,7 +389,7 @@ impl<'a> Comparator<'a> {
let mut mask = self.unchecked_compare(lhs, rhs);
self.server_key
.key
.keyswitch_programmable_bootstrap_assign(&mut mask, &self.mask_accumulator);
.apply_lookup_table_assign(&mut mask, &self.mask_accumulator);
let mut result = Vec::with_capacity(num_block);
for i in 0..num_block {
@@ -401,11 +399,11 @@ impl<'a> Comparator<'a> {
let maybe_x = self
.server_key
.key
.keyswitch_programmable_bootstrap(&lhs_masked, x_accumulator);
.apply_lookup_table(&lhs_masked, x_accumulator);
let maybe_y = self
.server_key
.key
.keyswitch_programmable_bootstrap(&rhs_masked, y_accumulator);
.apply_lookup_table(&rhs_masked, y_accumulator);
let r = self.server_key.key.unchecked_add(&maybe_x, &maybe_y);
result.push(r)
@@ -429,7 +427,7 @@ impl<'a> Comparator<'a> {
let mut mask = self.unchecked_compare_parallelized(lhs, rhs);
self.server_key
.key
.keyswitch_programmable_bootstrap_assign(&mut mask, &self.mask_accumulator);
.apply_lookup_table_assign(&mut mask, &self.mask_accumulator);
let blocks = lhs
.blocks
@@ -439,18 +437,16 @@ impl<'a> Comparator<'a> {
let (maybe_x, maybe_y) = rayon::join(
|| {
let mut lhs_masked = self.server_key.key.unchecked_add(lhs_block, &mask);
self.server_key.key.keyswitch_programmable_bootstrap_assign(
&mut lhs_masked,
x_accumulator,
);
self.server_key
.key
.apply_lookup_table_assign(&mut lhs_masked, x_accumulator);
lhs_masked
},
|| {
let mut rhs_masked = self.server_key.key.unchecked_add(rhs_block, &mask);
self.server_key.key.keyswitch_programmable_bootstrap_assign(
&mut rhs_masked,
y_accumulator,
);
self.server_key
.key
.apply_lookup_table_assign(&mut rhs_masked, y_accumulator);
rhs_masked
},
);
@@ -500,7 +496,7 @@ impl<'a> Comparator<'a> {
fn map_comparison_result<F>(
&self,
comparison: crate::shortint::Ciphertext,
comparison: crate::shortint::CiphertextBig,
sign_result_handler_fn: F,
num_blocks: usize,
) -> RadixCiphertext
@@ -511,10 +507,7 @@ impl<'a> Comparator<'a> {
.server_key
.key
.generate_accumulator(sign_result_handler_fn);
let result_block = self
.server_key
.key
.keyswitch_programmable_bootstrap(&comparison, &acc);
let result_block = self.server_key.key.apply_lookup_table(&comparison, &acc);
let mut blocks = Vec::with_capacity(num_blocks);
blocks.push(result_block);
@@ -534,7 +527,7 @@ impl<'a> Comparator<'a> {
rhs: &RadixCiphertext,
) -> RadixCiphertext
where
CmpFn: Fn(&Self, &RadixCiphertext, &RadixCiphertext) -> crate::shortint::Ciphertext,
CmpFn: Fn(&Self, &RadixCiphertext, &RadixCiphertext) -> crate::shortint::CiphertextBig,
F: Fn(u64) -> u64,
{
let comparison = comparison_fn(self, lhs, rhs);
@@ -550,7 +543,8 @@ impl<'a> Comparator<'a> {
rhs: &mut RadixCiphertext,
) -> RadixCiphertext
where
CmpFn: Fn(&Self, &mut RadixCiphertext, &mut RadixCiphertext) -> crate::shortint::Ciphertext,
CmpFn:
Fn(&Self, &mut RadixCiphertext, &mut RadixCiphertext) -> crate::shortint::CiphertextBig,
F: Fn(u64) -> u64,
{
let comparison = smart_comparison_fn(self, lhs, rhs);

View File

@@ -86,8 +86,7 @@ impl ServerKey {
.map(|b| self.key.generate_accumulator(|x| f(x) % b));
for (block, acc) in ct1.blocks.iter_mut().zip(accumulators) {
self.key
.keyswitch_programmable_bootstrap_assign(block, &acc);
self.key.apply_lookup_table_assign(block, &acc);
}
}

View File

@@ -89,7 +89,7 @@ impl ServerKey {
.par_iter_mut()
.zip(&accumulators)
.for_each(|(block, acc)| {
self.key.keyswitch_programmable_bootstrap_assign(block, acc);
self.key.apply_lookup_table_assign(block, acc);
});
}

View File

@@ -37,7 +37,7 @@ impl ServerKey {
pub fn unchecked_block_mul_assign(
&self,
ct_left: &mut RadixCiphertext,
ct_right: &crate::shortint::Ciphertext,
ct_right: &crate::shortint::CiphertextBig,
index: usize,
) {
*ct_left = self.unchecked_block_mul(ct_left, ct_right, index);
@@ -78,7 +78,7 @@ impl ServerKey {
pub fn unchecked_block_mul(
&self,
ct1: &RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) -> RadixCiphertext {
let shifted_ct = self.blockshift(ct1, index);
@@ -132,7 +132,7 @@ impl ServerKey {
pub fn smart_block_mul(
&self,
ct1: &mut RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) -> RadixCiphertext {
//Makes sure we can do the multiplications
@@ -160,7 +160,7 @@ impl ServerKey {
pub fn smart_block_mul_assign(
&self,
ct1: &mut RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) {
*ct1 = self.smart_block_mul(ct1, ct2, index);

View File

@@ -44,7 +44,7 @@ impl ServerKey {
pub fn unchecked_block_mul_assign_parallelized(
&self,
ct_left: &mut RadixCiphertext,
ct_right: &crate::shortint::Ciphertext,
ct_right: &crate::shortint::CiphertextBig,
index: usize,
) {
*ct_left = self.unchecked_block_mul_parallelized(ct_left, ct_right, index);
@@ -89,7 +89,7 @@ impl ServerKey {
pub fn unchecked_block_mul_parallelized(
&self,
ct1: &RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) -> RadixCiphertext {
let shifted_ct = self.blockshift(ct1, index);
@@ -138,7 +138,7 @@ impl ServerKey {
pub fn smart_block_mul_parallelized(
&self,
ct1: &mut RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) -> RadixCiphertext {
//Makes sure we can do the multiplications
@@ -158,7 +158,7 @@ impl ServerKey {
&self,
result_lsb: &mut RadixCiphertext,
result_msb: &mut RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) {
let len = result_msb.blocks.len() - 1;
@@ -183,7 +183,7 @@ impl ServerKey {
pub fn smart_block_mul_assign_parallelized(
&self,
ct1: &mut RadixCiphertext,
ct2: &crate::shortint::Ciphertext,
ct2: &crate::shortint::CiphertextBig,
index: usize,
) {
*ct1 = self.smart_block_mul_parallelized(ct1, ct2, index);

View File

@@ -252,11 +252,12 @@ impl WopbsKey {
let mut ct_vec_out = vec![];
for (block, block_out) in ct_in.blocks().iter().zip(vec_ct_out.into_iter()) {
ct_vec_out.push(crate::shortint::Ciphertext {
ct_vec_out.push(crate::shortint::CiphertextBig {
ct: block_out,
degree: Degree(block.message_modulus.0 - 1),
message_modulus: block.message_modulus,
carry_modulus: block.carry_modulus,
_order_marker: Default::default(),
});
}
T::from_blocks(ct_vec_out)
@@ -334,11 +335,12 @@ impl WopbsKey {
let mut ct_vec_out = vec![];
for (block, block_out) in ct_in.blocks().iter().zip(vec_ct_out.into_iter()) {
ct_vec_out.push(crate::shortint::Ciphertext {
ct_vec_out.push(crate::shortint::CiphertextBig {
ct: block_out,
degree: Degree(block.message_modulus.0 - 1),
message_modulus: block.message_modulus,
carry_modulus: block.carry_modulus,
_order_marker: Default::default(),
});
}
T::from_blocks(ct_vec_out)
@@ -1029,13 +1031,14 @@ impl WopbsKey {
.wopbs_key
.circuit_bootstrapping_vertical_packing(lut, &extracted_bits_blocks);
let mut ct_vec_out: Vec<crate::shortint::Ciphertext> = vec![];
let mut ct_vec_out: Vec<crate::shortint::CiphertextBig> = vec![];
for (block, block_out) in vec_ct_in[0].blocks().iter().zip(vec_ct_out.into_iter()) {
ct_vec_out.push(crate::shortint::Ciphertext {
ct_vec_out.push(crate::shortint::CiphertextBig {
ct: block_out,
degree: Degree(block.message_modulus.0 - 1),
message_modulus: block.message_modulus,
carry_modulus: block.carry_modulus,
_order_marker: Default::default(),
});
}
T::from_blocks(ct_vec_out)

View File

@@ -5,22 +5,44 @@ use super::js_wasm_seeder;
use std::panic::set_hook;
#[wasm_bindgen]
pub struct ShortintCiphertext(pub(crate) crate::shortint::ciphertext::Ciphertext);
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) enum ShortintCiphertextInner {
Big(crate::shortint::ciphertext::CiphertextBig),
Small(crate::shortint::ciphertext::CiphertextSmall),
}
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) enum ShortintCompressedCiphertextInner {
Big(crate::shortint::ciphertext::CompressedCiphertextBig),
Small(crate::shortint::ciphertext::CompressedCiphertextSmall),
}
#[wasm_bindgen]
pub struct ShortintCompressedCiphertext(
pub(crate) crate::shortint::ciphertext::CompressedCiphertext,
);
pub struct ShortintCiphertext(pub(crate) ShortintCiphertextInner);
#[wasm_bindgen]
pub struct ShortintCompressedCiphertext(pub(crate) ShortintCompressedCiphertextInner);
#[wasm_bindgen]
pub struct ShortintClientKey(pub(crate) crate::shortint::ClientKey);
#[wasm_bindgen]
pub struct ShortintPublicKey(pub(crate) crate::shortint::PublicKey);
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) enum ShortintPublicKeyInner {
Big(crate::shortint::PublicKeyBig),
Small(crate::shortint::PublicKeySmall),
}
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) enum ShortintCompressedPublicKeyInner {
Big(crate::shortint::CompressedPublicKeyBig),
Small(crate::shortint::CompressedPublicKeySmall),
}
#[wasm_bindgen]
pub struct ShortintCompressedPublicKey(pub(crate) crate::shortint::CompressedPublicKey);
pub struct ShortintPublicKey(pub(crate) ShortintPublicKeyInner);
#[wasm_bindgen]
pub struct ShortintCompressedPublicKey(pub(crate) ShortintCompressedPublicKeyInner);
#[wasm_bindgen]
pub struct ShortintCompressedServerKey(pub(crate) crate::shortint::CompressedServerKey);
@@ -86,6 +108,27 @@ impl Shortint {
.map(ShortintParameters)
}
#[wasm_bindgen]
pub fn get_parameters_small(
message_bits: usize,
carry_bits: usize,
) -> Result<ShortintParameters, JsError> {
set_hook(Box::new(console_error_panic_hook::hook));
match (message_bits, carry_bits) {
(1, 1) => Ok(crate::shortint::parameters::PARAM_SMALL_MESSAGE_1_CARRY_1),
(2, 2) => Ok(crate::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2),
(3, 3) => Ok(crate::shortint::parameters::PARAM_SMALL_MESSAGE_3_CARRY_3),
(4, 4) => Ok(crate::shortint::parameters::PARAM_SMALL_MESSAGE_4_CARRY_4),
_ => Err(wasm_bindgen::JsError::new(
format!(
"No parameters for {message_bits} bits of message and {carry_bits} bits of carry"
)
.as_str(),
)),
}
.map(ShortintParameters)
}
#[wasm_bindgen]
#[allow(clippy::too_many_arguments)]
pub fn new_parameters(
@@ -165,7 +208,18 @@ impl Shortint {
pub fn new_public_key(client_key: &ShortintClientKey) -> ShortintPublicKey {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintPublicKey(crate::shortint::public_key::PublicKey::new(&client_key.0))
ShortintPublicKey(ShortintPublicKeyInner::Big(
crate::shortint::public_key::PublicKeyBig::new(&client_key.0),
))
}
#[wasm_bindgen]
pub fn new_public_key_small(client_key: &ShortintClientKey) -> ShortintPublicKey {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintPublicKey(ShortintPublicKeyInner::Small(
crate::shortint::public_key::PublicKeySmall::new(&client_key.0),
))
}
#[wasm_bindgen]
@@ -174,8 +228,19 @@ impl Shortint {
) -> ShortintCompressedPublicKey {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCompressedPublicKey(crate::shortint::public_key::CompressedPublicKey::new(
&client_key.0,
ShortintCompressedPublicKey(ShortintCompressedPublicKeyInner::Big(
crate::shortint::public_key::CompressedPublicKeyBig::new(&client_key.0),
))
}
#[wasm_bindgen]
pub fn new_compressed_public_key_small(
client_key: &ShortintClientKey,
) -> ShortintCompressedPublicKey {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCompressedPublicKey(ShortintCompressedPublicKeyInner::Small(
crate::shortint::public_key::CompressedPublicKeySmall::new(&client_key.0),
))
}
@@ -194,7 +259,16 @@ impl Shortint {
pub fn encrypt(client_key: &ShortintClientKey, message: u64) -> ShortintCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCiphertext(client_key.0.encrypt(message))
ShortintCiphertext(ShortintCiphertextInner::Big(client_key.0.encrypt(message)))
}
#[wasm_bindgen]
pub fn encrypt_small(client_key: &ShortintClientKey, message: u64) -> ShortintCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCiphertext(ShortintCiphertextInner::Small(
client_key.0.encrypt_small(message),
))
}
#[wasm_bindgen]
@@ -204,7 +278,21 @@ impl Shortint {
) -> ShortintCompressedCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCompressedCiphertext(client_key.0.encrypt_compressed(message))
ShortintCompressedCiphertext(ShortintCompressedCiphertextInner::Big(
client_key.0.encrypt_compressed(message),
))
}
#[wasm_bindgen]
pub fn encrypt_compressed_small(
client_key: &ShortintClientKey,
message: u64,
) -> ShortintCompressedCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCompressedCiphertext(ShortintCompressedCiphertextInner::Small(
client_key.0.encrypt_compressed_small(message),
))
}
#[wasm_bindgen]
@@ -212,7 +300,14 @@ impl Shortint {
compressed_ciphertext: &ShortintCompressedCiphertext,
) -> ShortintCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCiphertext(compressed_ciphertext.0.clone().into())
match &compressed_ciphertext.0 {
ShortintCompressedCiphertextInner::Big(inner) => {
ShortintCiphertext(ShortintCiphertextInner::Big(inner.clone().into()))
}
ShortintCompressedCiphertextInner::Small(inner) => {
ShortintCiphertext(ShortintCiphertextInner::Small(inner.clone().into()))
}
}
}
#[wasm_bindgen]
@@ -222,7 +317,14 @@ impl Shortint {
) -> ShortintCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCiphertext(public_key.0.encrypt(message))
match &public_key.0 {
ShortintPublicKeyInner::Big(inner) => {
ShortintCiphertext(ShortintCiphertextInner::Big(inner.encrypt(message)))
}
ShortintPublicKeyInner::Small(inner) => {
ShortintCiphertext(ShortintCiphertextInner::Small(inner.encrypt(message)))
}
}
}
#[wasm_bindgen]
@@ -232,13 +334,23 @@ impl Shortint {
) -> ShortintCiphertext {
set_hook(Box::new(console_error_panic_hook::hook));
ShortintCiphertext(public_key.0.encrypt(message))
match &public_key.0 {
ShortintCompressedPublicKeyInner::Big(inner) => {
ShortintCiphertext(ShortintCiphertextInner::Big(inner.encrypt(message)))
}
ShortintCompressedPublicKeyInner::Small(inner) => {
ShortintCiphertext(ShortintCiphertextInner::Small(inner.encrypt(message)))
}
}
}
#[wasm_bindgen]
pub fn decrypt(client_key: &ShortintClientKey, ct: &ShortintCiphertext) -> u64 {
set_hook(Box::new(console_error_panic_hook::hook));
client_key.0.decrypt(&ct.0)
match &ct.0 {
ShortintCiphertextInner::Big(inner) => client_key.0.decrypt(inner),
ShortintCiphertextInner::Small(inner) => client_key.0.decrypt(inner),
}
}
#[wasm_bindgen]

View File

@@ -4,11 +4,55 @@ use crate::shortint::parameters::{CarryModulus, MessageModulus};
use serde::{Deserialize, Serialize};
use std::cmp;
use std::fmt::Debug;
use std::marker::PhantomData;
/// This tracks the number of operations that has been done.
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub struct Degree(pub usize);
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum PBSOrder {
/// Ciphertext is encrypted using the big LWE secret key corresponding to the GLWE secret key.
///
/// A keyswitch is first performed to bring it to the small LWE secret key realm, then the PBS
/// is computed bringing it back to the large LWE secret key.
KeyswitchBootstrap = 0,
/// Ciphertext is encrypted using the small LWE secret key.
///
/// The PBS is computed first and a keyswitch is applied to get back to the small LWE secret
/// key realm.
BootstrapKeyswitch = 1,
}
mod seal {
pub trait Sealed {}
impl Sealed for super::BootstrapKeyswitch {}
impl Sealed for super::KeyswitchBootstrap {}
}
/// Trait to mark Ciphertext with the order for the PBS operations
pub trait PBSOrderMarker: seal::Sealed + Debug + Clone + Copy {
fn pbs_order() -> PBSOrder;
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct KeyswitchBootstrap;
impl PBSOrderMarker for KeyswitchBootstrap {
fn pbs_order() -> PBSOrder {
PBSOrder::KeyswitchBootstrap
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct BootstrapKeyswitch;
impl PBSOrderMarker for BootstrapKeyswitch {
fn pbs_order() -> PBSOrder {
PBSOrder::BootstrapKeyswitch
}
}
impl Degree {
pub(crate) fn after_bitxor(&self, other: Degree) -> Degree {
let max = cmp::max(self.0, other.0);
@@ -74,42 +118,164 @@ impl Degree {
}
}
/// A structure representing a shortint ciphertext.
/// It is used to homomorphically evaluate a shortint circuits.
/// Internally, it uses a LWE ciphertext.
#[derive(Clone, Serialize, Deserialize)]
pub struct Ciphertext {
#[derive(Clone)]
#[must_use]
pub struct CiphertextBase<OpOrder: PBSOrderMarker> {
pub ct: LweCiphertextOwned<u64>,
pub degree: Degree,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub _order_marker: PhantomData<OpOrder>,
}
pub type CiphertextBig = CiphertextBase<KeyswitchBootstrap>;
pub type CiphertextSmall = CiphertextBase<BootstrapKeyswitch>;
#[derive(Serialize, Deserialize)]
struct SerialiazableCiphertextBase {
pub ct: LweCiphertextOwned<u64>,
pub degree: Degree,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub op_order: PBSOrder,
}
// Manual impl to be able to carry the OpOrder information
impl<OpOrder: PBSOrderMarker> Serialize for CiphertextBase<OpOrder> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
SerialiazableCiphertextBase {
ct: self.ct.clone(),
degree: self.degree,
message_modulus: self.message_modulus,
carry_modulus: self.carry_modulus,
op_order: OpOrder::pbs_order(),
}
.serialize(serializer)
}
}
// Manual impl to be able to check the OpOrder information
impl<'de, OpOrder: PBSOrderMarker> Deserialize<'de> for CiphertextBase<OpOrder> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let intermediate = SerialiazableCiphertextBase::deserialize(deserializer)?;
if intermediate.op_order != OpOrder::pbs_order() {
return Err(serde::de::Error::custom(format!(
"Expected PBSOrder: {:?}, got {:?}, \
did you mix CiphertextBig ({:?}) and CiphertextSmall ({:?})?",
OpOrder::pbs_order(),
intermediate.op_order,
PBSOrder::KeyswitchBootstrap,
PBSOrder::BootstrapKeyswitch
)));
}
Ok(CiphertextBase {
ct: intermediate.ct,
degree: intermediate.degree,
message_modulus: intermediate.message_modulus,
carry_modulus: intermediate.carry_modulus,
_order_marker: Default::default(),
})
}
}
/// A structure representing a compressed shortint ciphertext.
/// It is used to homomorphically evaluate a shortint circuits.
/// Internally, it uses a LWE ciphertext.
#[derive(Clone, Serialize, Deserialize)]
pub struct CompressedCiphertext {
#[derive(Clone)]
pub struct CompressedCiphertextBase<OpOrder: PBSOrderMarker> {
pub ct: SeededLweCiphertext<u64>,
pub degree: Degree,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub _order_marker: PhantomData<OpOrder>,
}
impl From<CompressedCiphertext> for Ciphertext {
fn from(value: CompressedCiphertext) -> Self {
let CompressedCiphertext {
pub type CompressedCiphertextBig = CompressedCiphertextBase<KeyswitchBootstrap>;
pub type CompressedCiphertextSmall = CompressedCiphertextBase<BootstrapKeyswitch>;
#[derive(Serialize, Deserialize)]
struct SerialiazableCompressedCiphertextBase {
pub ct: SeededLweCiphertext<u64>,
pub degree: Degree,
pub message_modulus: MessageModulus,
pub carry_modulus: CarryModulus,
pub op_order: PBSOrder,
}
// Manual impl to be able to carry the OpOrder information
impl<OpOrder: PBSOrderMarker> Serialize for CompressedCiphertextBase<OpOrder> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
SerialiazableCompressedCiphertextBase {
ct: self.ct.clone(),
degree: self.degree,
message_modulus: self.message_modulus,
carry_modulus: self.carry_modulus,
op_order: OpOrder::pbs_order(),
}
.serialize(serializer)
}
}
// Manual impl to be able to check the OpOrder information
impl<'de, OpOrder: PBSOrderMarker> Deserialize<'de> for CompressedCiphertextBase<OpOrder> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let intermediate = SerialiazableCompressedCiphertextBase::deserialize(deserializer)?;
if intermediate.op_order != OpOrder::pbs_order() {
return Err(serde::de::Error::custom(format!(
"Expected PBSOrder: {:?}, got {:?}, \
did you mix CompressedCiphertextBig ({:?}) and CompressedCiphertextSmall ({:?})?",
OpOrder::pbs_order(),
intermediate.op_order,
PBSOrder::KeyswitchBootstrap,
PBSOrder::BootstrapKeyswitch
)));
}
Ok(CompressedCiphertextBase {
ct: intermediate.ct,
degree: intermediate.degree,
message_modulus: intermediate.message_modulus,
carry_modulus: intermediate.carry_modulus,
_order_marker: Default::default(),
})
}
}
impl<OpOrder: PBSOrderMarker> CompressedCiphertextBase<OpOrder> {
pub fn decompress(self) -> CiphertextBase<OpOrder> {
let CompressedCiphertextBase {
ct,
degree,
message_modulus,
carry_modulus,
} = value;
_order_marker,
} = self;
Self {
CiphertextBase {
ct: ct.decompress_into_lwe_ciphertext(),
degree,
message_modulus,
carry_modulus,
_order_marker,
}
}
}
impl<OpOrder: PBSOrderMarker> From<CompressedCiphertextBase<OpOrder>> for CiphertextBase<OpOrder> {
fn from(value: CompressedCiphertextBase<OpOrder>) -> Self {
value.decompress()
}
}

View File

@@ -1,7 +1,10 @@
//! Module with the definition of the ClientKey.
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::{Ciphertext, CompressedCiphertext};
use crate::shortint::ciphertext::{
CiphertextBase, CiphertextBig, CiphertextSmall, CompressedCiphertextBig,
CompressedCiphertextSmall, PBSOrderMarker,
};
use crate::shortint::engine::ShortintEngine;
use crate::shortint::parameters::{MessageModulus, Parameters};
use serde::{Deserialize, Serialize};
@@ -17,11 +20,11 @@ use std::fmt::Debug;
/// * `parameters` - the cryptographic parameter set.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ClientKey {
/// The actual encryption / decryption key
pub(crate) lwe_secret_key: LweSecretKeyOwned<u64>,
/// The LWE secret key equivalent to the GLWE secret key
pub(crate) large_lwe_secret_key: LweSecretKeyOwned<u64>,
pub(crate) glwe_secret_key: GlweSecretKeyOwned<u64>,
/// Key used as the output of the keyswitch operation
pub(crate) lwe_secret_key_after_ks: LweSecretKeyOwned<u64>,
pub(crate) small_lwe_secret_key: LweSecretKeyOwned<u64>,
pub parameters: Parameters,
}
@@ -68,7 +71,38 @@ impl ClientKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn encrypt(&self, message: u64) -> Ciphertext {
pub fn encrypt(&self, message: u64) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| engine.encrypt(self, message).unwrap())
}
/// Encrypt a small integer message using the client key.
///
/// The input message is reduced to the encrypted message space modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 3;
/// let ct = cks.encrypt_small(msg);
///
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// // Encryption of one message that is outside the encrypted message modulus:
/// let msg = 5;
/// let ct = cks.encrypt_small(msg);
///
/// let dec = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn encrypt_small(&self, message: u64) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| engine.encrypt(self, message).unwrap())
}
@@ -80,7 +114,7 @@ impl ClientKey {
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{Ciphertext, ClientKey};
/// use tfhe::shortint::ClientKey;
///
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
@@ -88,7 +122,7 @@ impl ClientKey {
/// let msg = 3;
/// let ct = cks.encrypt_compressed(msg);
///
/// let ct: Ciphertext = ct.into();
/// let ct = ct.decompress();
///
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
@@ -97,13 +131,50 @@ impl ClientKey {
/// let msg = 5;
/// let ct = cks.encrypt_compressed(msg);
///
/// let ct: Ciphertext = ct.into();
/// let ct = ct.decompress();
///
/// let dec = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn encrypt_compressed(&self, message: u64) -> CompressedCiphertext {
pub fn encrypt_compressed(&self, message: u64) -> CompressedCiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine.encrypt_compressed(self, message).unwrap()
})
}
/// Encrypt a small integer message using the client key returning a compressed ciphertext.
///
/// The input message is reduced to the encrypted message space modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 3;
/// let ct = cks.encrypt_compressed_small(msg);
///
/// let ct = ct.decompress();
///
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// // Encryption of one message that is outside the encrypted message modulus:
/// let msg = 5;
/// let ct = cks.encrypt_compressed_small(msg);
///
/// let ct = ct.decompress();
///
/// let dec = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn encrypt_compressed_small(&self, message: u64) -> CompressedCiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine.encrypt_compressed(self, message).unwrap()
})
@@ -133,7 +204,39 @@ impl ClientKey {
&self,
message: u64,
message_modulus: MessageModulus,
) -> Ciphertext {
) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_message_modulus(self, message, message_modulus)
.unwrap()
})
}
/// Encrypt a small integer message using the client key with a specific message modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::{MessageModulus, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 3;
///
/// // Encryption of one message:
/// let ct = cks.encrypt_with_message_modulus_small(msg, MessageModulus(6));
///
/// // Decryption:
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_with_message_modulus_small(
&self,
message: u64,
message_modulus: MessageModulus,
) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_message_modulus(self, message, message_modulus)
@@ -148,7 +251,7 @@ impl ClientKey {
///
/// ```rust
/// use tfhe::shortint::parameters::MessageModulus;
/// use tfhe::shortint::{Ciphertext, ClientKey, Parameters};
/// use tfhe::shortint::{ClientKey, Parameters};
///
/// // Generate the client key
/// let cks = ClientKey::new(Parameters::default());
@@ -156,9 +259,9 @@ impl ClientKey {
/// let msg = 3;
///
/// // Encryption of one message:
/// let ct = cks.encrypt_with_message_modulus(msg, MessageModulus(6));
/// let ct = cks.encrypt_with_message_modulus_compressed(msg, MessageModulus(6));
///
/// let ct: Ciphertext = ct.into();
/// let ct = ct.decompress();
///
/// // Decryption:
/// let dec = cks.decrypt(&ct);
@@ -168,7 +271,42 @@ impl ClientKey {
&self,
message: u64,
message_modulus: MessageModulus,
) -> CompressedCiphertext {
) -> CompressedCiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_message_modulus_compressed(self, message, message_modulus)
.unwrap()
})
}
/// Encrypt a small integer message using the client key with a specific message modulus
/// returning a compressed ciphertext
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::{MessageModulus, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 3;
///
/// // Encryption of one message:
/// let ct = cks.encrypt_with_message_modulus_compressed_small(msg, MessageModulus(6));
///
/// let ct = ct.decompress();
///
/// // Decryption:
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_with_message_modulus_compressed_small(
&self,
message: u64,
message_modulus: MessageModulus,
) -> CompressedCiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_message_modulus_compressed(self, message, message_modulus)
@@ -196,7 +334,34 @@ impl ClientKey {
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn unchecked_encrypt(&self, message: u64) -> Ciphertext {
pub fn unchecked_encrypt(&self, message: u64) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_encrypt(self, message).unwrap()
})
}
/// Encrypt an integer without reducing the input message modulus the message space
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 7;
/// let ct = cks.unchecked_encrypt_small(msg);
/// // | ct |
/// // | carry | message |
/// // |-------|---------|
/// // | 0 1 | 1 1 |
///
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn unchecked_encrypt_small(&self, message: u64) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_encrypt(self, message).unwrap()
})
@@ -207,10 +372,11 @@ impl ClientKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, Parameters};
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(Parameters::default());
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 3;
///
@@ -220,8 +386,20 @@ impl ClientKey {
/// // Decryption:
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message:
/// let ct = cks.encrypt_small(msg);
///
/// // Decryption:
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn decrypt_message_and_carry(&self, ct: &Ciphertext) -> u64 {
pub fn decrypt_message_and_carry<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| {
engine.decrypt_message_and_carry(self, ct).unwrap()
})
@@ -232,10 +410,11 @@ impl ClientKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// use tfhe::shortint::{ClientKey, Parameters};
///
/// // Generate the client key
/// let cks = ClientKey::new(Parameters::default());
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 3;
///
@@ -245,8 +424,17 @@ impl ClientKey {
/// // Decryption:
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message:
/// let ct = cks.encrypt_small(msg);
///
/// // Decryption:
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn decrypt(&self, ct: &Ciphertext) -> u64 {
pub fn decrypt<OpOrder: PBSOrderMarker>(&self, ct: &CiphertextBase<OpOrder>) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| engine.decrypt(self, ct).unwrap())
}
@@ -269,7 +457,32 @@ impl ClientKey {
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_without_padding(&self, message: u64) -> Ciphertext {
pub fn encrypt_without_padding(&self, message: u64) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine.encrypt_without_padding(self, message).unwrap()
})
}
/// Encrypt a small integer message using the client key without padding bit.
///
/// The input message is reduced to the encrypted message space modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
/// let ct = cks.encrypt_without_padding_small(msg);
///
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_without_padding_small(&self, message: u64) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine.encrypt_without_padding(self, message).unwrap()
})
@@ -284,20 +497,53 @@ impl ClientKey {
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{Ciphertext, ClientKey};
/// use tfhe::shortint::ClientKey;
///
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
/// let ct = cks.encrypt_without_padding(msg);
/// let ct = cks.encrypt_without_padding_compressed(msg);
///
/// let ct: Ciphertext = ct.into();
/// let ct = ct.decompress();
///
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_without_padding_compressed(&self, message: u64) -> CompressedCiphertext {
pub fn encrypt_without_padding_compressed(&self, message: u64) -> CompressedCiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_without_padding_compressed(self, message)
.unwrap()
})
}
/// Encrypt a small integer message using the client key without padding bit returning a
/// compressed message.
///
/// The input message is reduced to the encrypted message space modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
/// let ct = cks.encrypt_without_padding_compressed_small(msg);
///
/// let ct = ct.decompress();
///
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_without_padding_compressed_small(
&self,
message: u64,
) -> CompressedCiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_without_padding_compressed(self, message)
@@ -311,7 +557,7 @@ impl ClientKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_1_CARRY_1;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_1_CARRY_1, PARAM_SMALL_MESSAGE_1_CARRY_1};
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
@@ -325,8 +571,20 @@ impl ClientKey {
/// // Decryption:
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_1_CARRY_1);
///
/// // Encryption of one message:
/// let ct = cks.encrypt_without_padding_small(msg);
///
/// // Decryption:
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn decrypt_message_and_carry_without_padding(&self, ct: &Ciphertext) -> u64 {
pub fn decrypt_message_and_carry_without_padding<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.decrypt_message_and_carry_without_padding(self, ct)
@@ -340,10 +598,11 @@ impl ClientKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, Parameters};
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(Parameters::default());
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 7;
/// let modulus = 4;
@@ -354,8 +613,20 @@ impl ClientKey {
/// // Decryption:
/// let dec = cks.decrypt_without_padding(&ct);
/// assert_eq!(msg % modulus, dec);
///
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encryption of one message:
/// let ct = cks.encrypt_without_padding_small(msg);
///
/// // Decryption:
/// let dec = cks.decrypt_without_padding(&ct);
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn decrypt_without_padding(&self, ct: &Ciphertext) -> u64 {
pub fn decrypt_without_padding<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| {
engine.decrypt_without_padding(self, ct).unwrap()
})
@@ -383,7 +654,38 @@ impl ClientKey {
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
/// ```
pub fn encrypt_native_crt(&self, message: u64, message_modulus: u8) -> Ciphertext {
pub fn encrypt_native_crt(&self, message: u64, message_modulus: u8) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_native_crt(self, message, message_modulus)
.unwrap()
})
}
/// Encrypt a small integer message using the client key without padding bit with some modulus.
///
/// The input message is reduced to the encrypted message space modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
/// let modulus = 3;
///
/// // Encryption of one message:
/// let ct = cks.encrypt_native_crt_small(msg, modulus);
///
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
/// ```
pub fn encrypt_native_crt_small(&self, message: u64, message_modulus: u8) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_native_crt(self, message, message_modulus)
@@ -399,7 +701,7 @@ impl ClientKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{Ciphertext, ClientKey, Parameters};
/// use tfhe::shortint::{ClientKey, Parameters};
///
/// // Generate the client key
/// let cks = ClientKey::new(Parameters::default());
@@ -408,9 +710,9 @@ impl ClientKey {
/// let modulus = 3;
///
/// // Encryption of one message:
/// let ct = cks.encrypt_native_crt(msg, modulus);
/// let ct = cks.encrypt_native_crt_compressed(msg, modulus);
///
/// let ct: Ciphertext = ct.into();
/// let ct = ct.decompress();
///
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
@@ -420,7 +722,45 @@ impl ClientKey {
&self,
message: u64,
message_modulus: u8,
) -> CompressedCiphertext {
) -> CompressedCiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_native_crt_compressed(self, message, message_modulus)
.unwrap()
})
}
/// Encrypt a small integer message using the client key without padding bit with some modulus
/// returning a compressed ciphertext.
///
/// The input message is reduced to the encrypted message space modulus
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
/// let modulus = 3;
///
/// // Encryption of one message:
/// let ct = cks.encrypt_native_crt_compressed_small(msg, modulus);
///
/// let ct = ct.decompress();
///
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
/// ```
pub fn encrypt_native_crt_compressed_small(
&self,
message: u64,
message_modulus: u8,
) -> CompressedCiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_native_crt_compressed(self, message, message_modulus)
@@ -434,10 +774,11 @@ impl ClientKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, Parameters};
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::ClientKey;
///
/// // Generate the client key
/// let cks = ClientKey::new(Parameters::default());
/// let cks = ClientKey::new(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 1;
/// let modulus = 3;
@@ -448,8 +789,19 @@ impl ClientKey {
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
///
/// // Encryption of one message:
/// let ct = cks.encrypt_native_crt_small(msg, modulus);
///
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
/// ```
pub fn decrypt_message_native_crt(&self, ct: &Ciphertext, message_modulus: u8) -> u64 {
pub fn decrypt_message_native_crt<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
message_modulus: u8,
) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.decrypt_message_native_crt(self, ct, message_modulus as u64)

View File

@@ -1,10 +1,13 @@
//! All the `ShortintEngine` method related to client side (encrypt / decrypt)
use super::{EngineResult, ShortintEngine};
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::dispersion::DispersionParameter;
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::{Ciphertext, ClientKey, CompressedCiphertext, Parameters};
use crate::shortint::{
CiphertextBase, ClientKey, CompressedCiphertextBase, PBSOrder, PBSOrderMarker, Parameters,
};
impl ShortintEngine {
pub fn new_client_key(&mut self, parameters: Parameters) -> EngineResult<ClientKey> {
@@ -25,14 +28,18 @@ impl ShortintEngine {
// pack the keys in the client key set
Ok(ClientKey {
lwe_secret_key: large_lwe_secret_key,
large_lwe_secret_key,
glwe_secret_key,
lwe_secret_key_after_ks: small_lwe_secret_key,
small_lwe_secret_key,
parameters,
})
}
pub fn encrypt(&mut self, client_key: &ClientKey, message: u64) -> EngineResult<Ciphertext> {
pub fn encrypt<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
) -> EngineResult<CiphertextBase<OpOrder>> {
self.encrypt_with_message_modulus(
client_key,
message,
@@ -40,11 +47,11 @@ impl ShortintEngine {
)
}
pub fn encrypt_compressed(
pub fn encrypt_compressed<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
) -> EngineResult<CompressedCiphertext> {
) -> EngineResult<CompressedCiphertextBase<OpOrder>> {
self.encrypt_with_message_modulus_compressed(
client_key,
message,
@@ -52,21 +59,17 @@ impl ShortintEngine {
)
}
pub(crate) fn encrypt_with_message_modulus(
fn encrypt_inner_ct(
&mut self,
client_key: &ClientKey,
client_key_parameters: &Parameters,
client_lwe_sk: &LweSecretKeyOwned<u64>,
noise_parameter: impl DispersionParameter,
message: u64,
message_modulus: MessageModulus,
) -> EngineResult<Ciphertext> {
//This ensures that the space message_modulus*carry_modulus < param.message_modulus *
// param.carry_modulus
let carry_modulus = (client_key.parameters.message_modulus.0
* client_key.parameters.carry_modulus.0)
/ message_modulus.0;
) -> LweCiphertextOwned<u64> {
//The delta is the one defined by the parameters
let delta = (1_u64 << 63)
/ (client_key.parameters.message_modulus.0 * client_key.parameters.carry_modulus.0)
/ (client_key_parameters.message_modulus.0 * client_key_parameters.carry_modulus.0)
as u64;
//The input is reduced modulus the message_modulus
@@ -76,27 +79,60 @@ impl ShortintEngine {
let encoded = Plaintext(shifted_message);
let ct = allocate_and_encrypt_new_lwe_ciphertext(
&client_key.lwe_secret_key,
allocate_and_encrypt_new_lwe_ciphertext(
client_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
noise_parameter,
&mut self.encryption_generator,
)
}
pub(crate) fn encrypt_with_message_modulus<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
message_modulus: MessageModulus,
) -> EngineResult<CiphertextBase<OpOrder>> {
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let ct = self.encrypt_inner_ct(
&client_key.parameters,
encryption_lwe_sk,
encryption_noise,
message,
message_modulus,
);
Ok(Ciphertext {
//This ensures that the space message_modulus*carry_modulus < param.message_modulus *
// param.carry_modulus
let carry_modulus = (client_key.parameters.message_modulus.0
* client_key.parameters.carry_modulus.0)
/ message_modulus.0;
Ok(CiphertextBase {
ct,
degree: Degree(message_modulus.0 - 1),
message_modulus,
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_with_message_modulus_compressed(
pub(crate) fn encrypt_with_message_modulus_compressed<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
message_modulus: MessageModulus,
) -> EngineResult<CompressedCiphertext> {
) -> EngineResult<CompressedCiphertextBase<OpOrder>> {
//This ensures that the space message_modulus*carry_modulus < param.message_modulus *
// param.carry_modulus
let carry_modulus = (client_key.parameters.message_modulus.0
@@ -115,26 +151,49 @@ impl ShortintEngine {
let encoded = Plaintext(shifted_message);
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
&client_key.lwe_secret_key,
encryption_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
encryption_noise,
&mut self.seeder,
);
Ok(CompressedCiphertext {
Ok(CompressedCiphertextBase {
ct,
degree: Degree(message_modulus.0 - 1),
message_modulus,
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn unchecked_encrypt(
pub(crate) fn unchecked_encrypt<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let delta = (1_u64 << 63)
/ (client_key.parameters.message_modulus.0 * client_key.parameters.carry_modulus.0)
as u64;
@@ -143,29 +202,35 @@ impl ShortintEngine {
let encoded = Plaintext(shifted_message);
let ct = allocate_and_encrypt_new_lwe_ciphertext(
&client_key.lwe_secret_key,
encryption_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
encryption_noise,
&mut self.encryption_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct,
degree: Degree(
client_key.parameters.message_modulus.0 * client_key.parameters.carry_modulus.0 - 1,
),
message_modulus: client_key.parameters.message_modulus,
carry_modulus: client_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn decrypt_message_and_carry(
pub(crate) fn decrypt_message_and_carry<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<u64> {
let lwe_decryption_key = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => &client_key.large_lwe_secret_key,
PBSOrder::BootstrapKeyswitch => &client_key.small_lwe_secret_key,
};
// decryption
let decrypted_encoded = decrypt_lwe_ciphertext(&client_key.lwe_secret_key, &ct.ct);
let decrypted_encoded = decrypt_lwe_ciphertext(lwe_decryption_key, &ct.ct);
let decrypted_u64: u64 = decrypted_encoded.0;
@@ -182,16 +247,20 @@ impl ShortintEngine {
Ok((decrypted_u64.wrapping_add(rounding)) / delta)
}
pub fn decrypt(&mut self, client_key: &ClientKey, ct: &Ciphertext) -> EngineResult<u64> {
pub fn decrypt<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<u64> {
self.decrypt_message_and_carry(client_key, ct)
.map(|message_and_carry| message_and_carry % ct.message_modulus.0 as u64)
}
pub(crate) fn encrypt_without_padding(
pub(crate) fn encrypt_without_padding<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
//Multiply by 2 to reshift and exclude the padding bit
let delta = ((1_u64 << 63)
/ (client_key.parameters.message_modulus.0 * client_key.parameters.carry_modulus.0)
@@ -202,26 +271,38 @@ impl ShortintEngine {
let encoded = Plaintext(shifted_message);
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let ct = allocate_and_encrypt_new_lwe_ciphertext(
&client_key.lwe_secret_key,
encryption_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
encryption_noise,
&mut self.encryption_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct,
degree: Degree(client_key.parameters.message_modulus.0 - 1),
message_modulus: client_key.parameters.message_modulus,
carry_modulus: client_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_without_padding_compressed(
pub(crate) fn encrypt_without_padding_compressed<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
) -> EngineResult<CompressedCiphertext> {
) -> EngineResult<CompressedCiphertextBase<OpOrder>> {
//Multiply by 2 to reshift and exclude the padding bit
let delta = ((1_u64 << 63)
/ (client_key.parameters.message_modulus.0 * client_key.parameters.carry_modulus.0)
@@ -232,28 +313,45 @@ impl ShortintEngine {
let encoded = Plaintext(shifted_message);
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
&client_key.lwe_secret_key,
encryption_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
encryption_noise,
&mut self.seeder,
);
Ok(CompressedCiphertext {
Ok(CompressedCiphertextBase {
ct,
degree: Degree(client_key.parameters.message_modulus.0 - 1),
message_modulus: client_key.parameters.message_modulus,
carry_modulus: client_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn decrypt_message_and_carry_without_padding(
pub(crate) fn decrypt_message_and_carry_without_padding<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<u64> {
let lwe_decryption_key = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => &client_key.large_lwe_secret_key,
PBSOrder::BootstrapKeyswitch => &client_key.small_lwe_secret_key,
};
// decryption
let decrypted_encoded = decrypt_lwe_ciphertext(&client_key.lwe_secret_key, &ct.ct);
let decrypted_encoded = decrypt_lwe_ciphertext(lwe_decryption_key, &ct.ct);
let decrypted_u64: u64 = decrypted_encoded.0;
@@ -271,77 +369,106 @@ impl ShortintEngine {
Ok((decrypted_u64.wrapping_add(rounding)) / delta)
}
pub(crate) fn decrypt_without_padding(
pub(crate) fn decrypt_without_padding<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<u64> {
self.decrypt_message_and_carry_without_padding(client_key, ct)
.map(|message_and_carry| message_and_carry % ct.message_modulus.0 as u64)
}
pub(crate) fn encrypt_native_crt(
pub(crate) fn encrypt_native_crt<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
message_modulus: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let carry_modulus = 1;
let m = (message % message_modulus as u64) as u128;
let shifted_message = (m * (1 << 64) / message_modulus as u128) as u64;
let encoded = Plaintext(shifted_message);
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let ct = allocate_and_encrypt_new_lwe_ciphertext(
&client_key.lwe_secret_key,
encryption_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
encryption_noise,
&mut self.encryption_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct,
degree: Degree(message_modulus as usize - 1),
message_modulus: MessageModulus(message_modulus as usize),
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_native_crt_compressed(
pub(crate) fn encrypt_native_crt_compressed<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
message: u64,
message_modulus: u8,
) -> EngineResult<CompressedCiphertext> {
) -> EngineResult<CompressedCiphertextBase<OpOrder>> {
let carry_modulus = 1;
let m = (message % message_modulus as u64) as u128;
let shifted_message = (m * (1 << 64) / message_modulus as u128) as u64;
let encoded = Plaintext(shifted_message);
let (encryption_lwe_sk, encryption_noise) = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_key.parameters.glwe_modular_std_dev,
),
PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_key.parameters.lwe_modular_std_dev,
),
};
let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
&client_key.lwe_secret_key,
encryption_lwe_sk,
encoded,
client_key.parameters.lwe_modular_std_dev,
encryption_noise,
&mut self.seeder,
);
Ok(CompressedCiphertext {
Ok(CompressedCiphertextBase {
ct,
degree: Degree(message_modulus as usize - 1),
message_modulus: MessageModulus(message_modulus as usize),
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn decrypt_message_native_crt(
pub(crate) fn decrypt_message_native_crt<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
basis: u64,
) -> EngineResult<u64> {
let lwe_decryption_key = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => &client_key.large_lwe_secret_key,
PBSOrder::BootstrapKeyswitch => &client_key.small_lwe_secret_key,
};
// decryption
let decrypted_encoded = decrypt_lwe_ciphertext(&client_key.lwe_secret_key, &ct.ct);
let decrypted_encoded = decrypt_lwe_ciphertext(lwe_decryption_key, &ct.ct);
let decrypted_u64: u64 = decrypted_encoded.0;

View File

@@ -12,13 +12,15 @@ use crate::core_crypto::entities::*;
use crate::core_crypto::prelude::ContainerMut;
use crate::core_crypto::seeders::new_seeder;
use crate::shortint::ciphertext::Degree;
use crate::shortint::server_key::Accumulator;
use crate::shortint::server_key::{
BivariateLookupTableOwned, LookupTableMutView, LookupTableOwned,
};
use crate::shortint::ServerKey;
use std::cell::RefCell;
use std::fmt::Debug;
use super::parameters::MessageModulus;
use super::server_key::BivariateAccumulator;
use super::server_key::BivariateLookupTable;
mod client_side;
mod public_side;
@@ -31,8 +33,11 @@ thread_local! {
}
pub struct BuffersRef<'a> {
pub(crate) accumulator: GlweCiphertextMutView<'a, u64>,
pub(crate) accumulator: LookupTableMutView<'a>,
// For the intermediate keyswitch result in the case of a big ciphertext
pub(crate) buffer_lwe_after_ks: LweCiphertextMutView<'a, u64>,
// For the intermediate PBS result in the case of a smallciphertext
pub(crate) buffer_lwe_after_pbs: LweCiphertextMutView<'a, u64>,
}
#[derive(Default)]
@@ -44,9 +49,15 @@ impl Memory {
fn as_buffers(&mut self, server_key: &ServerKey) -> BuffersRef<'_> {
let num_elem_in_accumulator = server_key.bootstrapping_key.glwe_size().0
* server_key.bootstrapping_key.polynomial_size().0;
let num_elem_in_lwe = server_key.key_switching_key.output_lwe_size().0;
let num_elem_in_lwe_after_ks = server_key.key_switching_key.output_lwe_size().0;
let num_elem_in_lwe_after_pbs = server_key
.bootstrapping_key
.output_lwe_dimension()
.to_lwe_size()
.0;
let total_elem_needed = num_elem_in_accumulator + num_elem_in_lwe;
let total_elem_needed =
num_elem_in_accumulator + num_elem_in_lwe_after_ks + num_elem_in_lwe_after_pbs;
let all_elements = if self.buffer.len() < total_elem_needed {
self.buffer.resize(total_elem_needed, 0u64);
@@ -55,19 +66,30 @@ impl Memory {
&mut self.buffer[..total_elem_needed]
};
let (accumulator_elements, lwe_elements) =
let (accumulator_elements, other_elements) =
all_elements.split_at_mut(num_elem_in_accumulator);
let accumulator = GlweCiphertextMutView::from_container(
let acc = GlweCiphertext::from_container(
accumulator_elements,
server_key.bootstrapping_key.polynomial_size(),
);
let buffer_lwe_after_ks = LweCiphertextMutView::from_container(lwe_elements);
let accumulator = LookupTableMutView {
acc,
// As a safety, the degree should be updated once the accumulator is actually filled
degree: Degree(server_key.max_degree.0),
};
let (after_ks_elements, after_pbs_elements) =
other_elements.split_at_mut(num_elem_in_lwe_after_ks);
let buffer_lwe_after_ks = LweCiphertextMutView::from_container(after_ks_elements);
let buffer_lwe_after_pbs = LweCiphertextMutView::from_container(after_pbs_elements);
BuffersRef {
accumulator,
buffer_lwe_after_ks,
buffer_lwe_after_pbs,
}
}
}
@@ -222,7 +244,7 @@ impl ShortintEngine {
fn generate_accumulator_with_engine<F>(
server_key: &ServerKey,
f: F,
) -> EngineResult<Accumulator>
) -> EngineResult<LookupTableOwned>
where
F: Fn(u64) -> u64,
{
@@ -233,7 +255,7 @@ impl ShortintEngine {
);
let max_value = fill_accumulator(&mut acc, server_key, f);
Ok(Accumulator {
Ok(LookupTableOwned {
acc,
degree: Degree(max_value as usize),
})
@@ -244,7 +266,7 @@ impl ShortintEngine {
server_key: &ServerKey,
f: F,
left_message_scaling: MessageModulus,
) -> EngineResult<BivariateAccumulator>
) -> EngineResult<BivariateLookupTableOwned>
where
F: Fn(u64, u64) -> u64,
{
@@ -261,21 +283,22 @@ impl ShortintEngine {
};
let accumulator = ShortintEngine::generate_accumulator_with_engine(server_key, wrapped_f)?;
Ok(BivariateAccumulator {
Ok(BivariateLookupTable {
acc: accumulator,
ct_right_modulus: left_message_scaling,
})
}
/// Return the [`BuffersRef`] and [`ComputationBuffers`] for the given `ServerKey`
pub fn buffers_for_key(
pub fn get_carry_clearing_accumulator_and_buffers(
&mut self,
server_key: &ServerKey,
) -> (BuffersRef<'_>, &mut ComputationBuffers) {
let mut buffers = self.ciphertext_buffers.as_buffers(server_key);
fill_accumulator(&mut buffers.accumulator, server_key, |n| {
let max_degree = fill_accumulator(&mut buffers.accumulator.acc, server_key, |n| {
n % server_key.message_modulus.0 as u64
});
buffers.accumulator.degree = Degree(max_degree as usize);
(buffers, &mut self.computation_buffers)
}

View File

@@ -5,83 +5,116 @@ use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::{Ciphertext, ClientKey, CompressedPublicKey, Parameters, PublicKey};
use crate::shortint::{
CiphertextBase, ClientKey, CompressedPublicKeyBase, PBSOrderMarker, PublicKeyBase,
};
// We have q = 2^64 so log2q = 64
const LOG2_Q_64: usize = 64;
pub fn shortint_public_key_zero_encryption_count(
params: &Parameters,
pk_lwe_size: LweSize,
) -> LwePublicKeyZeroEncryptionCount {
// Formula is (k*N + 1) * log2(q) + 128
LwePublicKeyZeroEncryptionCount(
(params.polynomial_size.0 * params.glwe_dimension.0 + 1) * LOG2_Q_64 + 128,
)
// Formula is (n + 1) * log2(q) + 128
// or in the case of a GLWE secret key reinterpreted as an LWE secret key
// (k*N + 1) * log2(q) + 128
LwePublicKeyZeroEncryptionCount(pk_lwe_size.0 * LOG2_Q_64 + 128)
}
impl ShortintEngine {
pub(crate) fn new_public_key(&mut self, client_key: &ClientKey) -> EngineResult<PublicKey> {
pub(crate) fn new_public_key<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
) -> EngineResult<PublicKeyBase<OpOrder>> {
let client_parameters = client_key.parameters;
let zero_encryption_count = shortint_public_key_zero_encryption_count(&client_parameters);
let (secret_encryption_key, encryption_noise) = match OpOrder::pbs_order() {
crate::shortint::PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_parameters.glwe_modular_std_dev,
),
crate::shortint::PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_parameters.lwe_modular_std_dev,
),
};
let zero_encryption_count = shortint_public_key_zero_encryption_count(
secret_encryption_key.lwe_dimension().to_lwe_size(),
);
#[cfg(not(feature = "__wasm_api"))]
let lwe_public_key = par_allocate_and_generate_new_lwe_public_key(
&client_key.lwe_secret_key,
secret_encryption_key,
zero_encryption_count,
client_key.parameters.glwe_modular_std_dev,
encryption_noise,
&mut self.encryption_generator,
);
#[cfg(feature = "__wasm_api")]
let lwe_public_key = allocate_and_generate_new_lwe_public_key(
&client_key.lwe_secret_key,
secret_encryption_key,
zero_encryption_count,
client_key.parameters.glwe_modular_std_dev,
encryption_noise,
&mut self.encryption_generator,
);
Ok(PublicKey {
Ok(PublicKeyBase {
lwe_public_key,
parameters: client_key.parameters.to_owned(),
_order_marker: Default::default(),
})
}
pub(crate) fn new_compressed_public_key(
pub(crate) fn new_compressed_public_key<OpOrder: PBSOrderMarker>(
&mut self,
client_key: &ClientKey,
) -> EngineResult<CompressedPublicKey> {
) -> EngineResult<CompressedPublicKeyBase<OpOrder>> {
let client_parameters = client_key.parameters;
let zero_encryption_count = shortint_public_key_zero_encryption_count(&client_parameters);
let (secret_encryption_key, encryption_noise) = match OpOrder::pbs_order() {
crate::shortint::PBSOrder::KeyswitchBootstrap => (
&client_key.large_lwe_secret_key,
client_parameters.glwe_modular_std_dev,
),
crate::shortint::PBSOrder::BootstrapKeyswitch => (
&client_key.small_lwe_secret_key,
client_parameters.lwe_modular_std_dev,
),
};
let zero_encryption_count = shortint_public_key_zero_encryption_count(
secret_encryption_key.lwe_dimension().to_lwe_size(),
);
#[cfg(not(feature = "__wasm_api"))]
let compressed_public_key = par_allocate_and_generate_new_seeded_lwe_public_key(
&client_key.lwe_secret_key,
secret_encryption_key,
zero_encryption_count,
client_parameters.glwe_modular_std_dev,
encryption_noise,
&mut self.seeder,
);
#[cfg(feature = "__wasm_api")]
let compressed_public_key = allocate_and_generate_new_seeded_lwe_public_key(
&client_key.lwe_secret_key,
secret_encryption_key,
zero_encryption_count,
client_parameters.glwe_modular_std_dev,
encryption_noise,
&mut self.seeder,
);
Ok(CompressedPublicKey {
Ok(CompressedPublicKeyBase {
lwe_public_key: compressed_public_key,
parameters: client_key.parameters.to_owned(),
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_with_public_key(
pub(crate) fn encrypt_with_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &PublicKey,
public_key: &PublicKeyBase<OpOrder>,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let ciphertext = self.encrypt_with_message_modulus_and_public_key(
public_key,
message,
@@ -91,11 +124,11 @@ impl ShortintEngine {
Ok(ciphertext)
}
pub(crate) fn encrypt_with_compressed_public_key(
pub(crate) fn encrypt_with_compressed_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &CompressedPublicKey,
public_key: &CompressedPublicKeyBase<OpOrder>,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let ciphertext = self.encrypt_with_message_modulus_and_compressed_public_key(
public_key,
message,
@@ -105,12 +138,12 @@ impl ShortintEngine {
Ok(ciphertext)
}
pub(crate) fn encrypt_with_message_modulus_and_public_key(
pub(crate) fn encrypt_with_message_modulus_and_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &PublicKey,
public_key: &PublicKeyBase<OpOrder>,
message: u64,
message_modulus: MessageModulus,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
//This ensures that the space message_modulus*carry_modulus < param.message_modulus *
// param.carry_modulus
let carry_modulus = (public_key.parameters.message_modulus.0
@@ -139,20 +172,23 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(message_modulus.0 - 1),
message_modulus,
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_with_message_modulus_and_compressed_public_key(
pub(crate) fn encrypt_with_message_modulus_and_compressed_public_key<
OpOrder: PBSOrderMarker,
>(
&mut self,
public_key: &CompressedPublicKey,
public_key: &CompressedPublicKeyBase<OpOrder>,
message: u64,
message_modulus: MessageModulus,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
//This ensures that the space message_modulus*carry_modulus < param.message_modulus *
// param.carry_modulus
let carry_modulus = (public_key.parameters.message_modulus.0
@@ -182,19 +218,20 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(message_modulus.0 - 1),
message_modulus,
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_without_padding_with_public_key(
pub(crate) fn encrypt_without_padding_with_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &PublicKey,
public_key: &PublicKeyBase<OpOrder>,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
//Multiply by 2 to reshift and exclude the padding bit
let delta = ((1_u64 << 63)
/ (public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0)
@@ -216,19 +253,20 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(public_key.parameters.message_modulus.0 - 1),
message_modulus: public_key.parameters.message_modulus,
carry_modulus: public_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_without_padding_with_compressed_public_key(
pub(crate) fn encrypt_without_padding_with_compressed_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &CompressedPublicKey,
public_key: &CompressedPublicKeyBase<OpOrder>,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
//Multiply by 2 to reshift and exclude the padding bit
let delta = ((1_u64 << 63)
/ (public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0)
@@ -250,20 +288,21 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(public_key.parameters.message_modulus.0 - 1),
message_modulus: public_key.parameters.message_modulus,
carry_modulus: public_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_native_crt_with_public_key(
pub(crate) fn encrypt_native_crt_with_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &PublicKey,
public_key: &PublicKeyBase<OpOrder>,
message: u64,
message_modulus: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let carry_modulus = 1;
let m = (message % message_modulus as u64) as u128;
let shifted_message = m * (1 << 64) / message_modulus as u128;
@@ -281,20 +320,21 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(message_modulus as usize - 1),
message_modulus: MessageModulus(message_modulus as usize),
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn encrypt_native_crt_with_compressed_public_key(
pub(crate) fn encrypt_native_crt_with_compressed_public_key<OpOder: PBSOrderMarker>(
&mut self,
public_key: &CompressedPublicKey,
public_key: &CompressedPublicKeyBase<OpOder>,
message: u64,
message_modulus: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOder>> {
let carry_modulus = 1;
let m = (message % message_modulus as u64) as u128;
let shifted_message = m * (1 << 64) / message_modulus as u128;
@@ -312,19 +352,20 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(message_modulus as usize - 1),
message_modulus: MessageModulus(message_modulus as usize),
carry_modulus: CarryModulus(carry_modulus),
_order_marker: Default::default(),
})
}
pub(crate) fn unchecked_encrypt_with_public_key(
pub(crate) fn unchecked_encrypt_with_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &PublicKey,
public_key: &PublicKeyBase<OpOrder>,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let delta = (1_u64 << 63)
/ (public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0)
as u64;
@@ -342,21 +383,22 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(
public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0 - 1,
),
message_modulus: public_key.parameters.message_modulus,
carry_modulus: public_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn unchecked_encrypt_with_compressed_public_key(
pub(crate) fn unchecked_encrypt_with_compressed_public_key<OpOrder: PBSOrderMarker>(
&mut self,
public_key: &CompressedPublicKey,
public_key: &CompressedPublicKeyBase<OpOrder>,
message: u64,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let delta = (1_u64 << 63)
/ (public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0)
as u64;
@@ -374,13 +416,14 @@ impl ShortintEngine {
&mut self.secret_generator,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: encrypted_ct,
degree: Degree(
public_key.parameters.message_modulus.0 * public_key.parameters.carry_modulus.0 - 1,
),
message_modulus: public_key.parameters.message_modulus,
carry_modulus: public_key.parameters.carry_modulus,
_order_marker: Default::default(),
})
}
}

View File

@@ -1,45 +1,45 @@
use crate::core_crypto::algorithms::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_add(
pub(crate) fn unchecked_add<OpOrder: PBSOrderMarker>(
&mut self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_add_assign(&mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_add_assign(
pub(crate) fn unchecked_add_assign<OpOrder: PBSOrderMarker>(
&mut self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
lwe_ciphertext_add_assign(&mut ct_left.ct, &ct_right.ct);
ct_left.degree = Degree(ct_left.degree.0 + ct_right.degree.0);
Ok(())
}
pub(crate) fn smart_add(
pub(crate) fn smart_add<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_add_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_add_assign(
pub(crate) fn smart_add_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
//If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
if !server_key.is_add_possible(ct_left, ct_right) {

View File

@@ -1,25 +1,25 @@
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_bitand(
pub(crate) fn unchecked_bitand<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_bitand_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_bitand_assign(
pub(crate) fn unchecked_bitand_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -29,22 +29,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_bitand(
pub(crate) fn smart_bitand<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_bitand_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_bitand_assign(
pub(crate) fn smart_bitand_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -54,24 +54,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_bitxor(
pub(crate) fn unchecked_bitxor<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_bitxor_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_bitxor_assign(
pub(crate) fn unchecked_bitxor_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -81,22 +81,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_bitxor(
pub(crate) fn smart_bitxor<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_bitxor_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_bitxor_assign(
pub(crate) fn smart_bitxor_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -106,24 +106,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_bitor(
pub(crate) fn unchecked_bitor<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_bitor_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_bitor_assign(
pub(crate) fn unchecked_bitor_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -133,22 +133,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_bitor(
pub(crate) fn smart_bitor<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_bitor_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_bitor_assign(
pub(crate) fn smart_bitor_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;

View File

@@ -1,25 +1,25 @@
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_greater(
pub(crate) fn unchecked_greater<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_greater_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
fn unchecked_greater_assign(
fn unchecked_greater_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -28,22 +28,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_greater(
pub(crate) fn smart_greater<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_greater_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_greater_assign(
pub(crate) fn smart_greater_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -54,24 +54,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_greater_or_equal(
pub(crate) fn unchecked_greater_or_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_greater_or_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
fn unchecked_greater_or_equal_assign(
fn unchecked_greater_or_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -80,22 +80,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_greater_or_equal(
pub(crate) fn smart_greater_or_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_greater_or_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_greater_or_equal_assign(
pub(crate) fn smart_greater_or_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -105,24 +105,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_less(
pub(crate) fn unchecked_less<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_less_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
fn unchecked_less_assign(
fn unchecked_less_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -131,22 +131,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_less(
pub(crate) fn smart_less<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_less_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_less_assign(
pub(crate) fn smart_less_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -156,24 +156,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_less_or_equal(
pub(crate) fn unchecked_less_or_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_less_or_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
fn unchecked_less_or_equal_assign(
fn unchecked_less_or_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -182,22 +182,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_less_or_equal(
pub(crate) fn smart_less_or_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_less_or_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_less_or_equal_assign(
pub(crate) fn smart_less_or_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -207,24 +207,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_equal(
pub(crate) fn unchecked_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
fn unchecked_equal_assign(
fn unchecked_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -233,22 +233,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_equal(
pub(crate) fn smart_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_equal_assign(
pub(crate) fn smart_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -258,49 +258,49 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_scalar_equal(
pub(crate) fn smart_scalar_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_scalar_equal_assign(server_key, &mut result, scalar)?;
Ok(result)
}
fn smart_scalar_equal_assign(
fn smart_scalar_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let modulus = ct_left.message_modulus.0 as u64;
let acc =
self.generate_accumulator(server_key, |x| (x % modulus == scalar as u64) as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree.0 = 1;
Ok(())
}
pub(crate) fn unchecked_not_equal(
pub(crate) fn unchecked_not_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_not_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
fn unchecked_not_equal_assign(
fn unchecked_not_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -309,22 +309,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_not_equal(
pub(crate) fn smart_not_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_not_equal_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_not_equal_assign(
pub(crate) fn smart_not_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -334,119 +334,119 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_scalar_not_equal(
pub(crate) fn smart_scalar_not_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_scalar_not_equal_assign(server_key, &mut result, scalar)?;
Ok(result)
}
fn smart_scalar_not_equal_assign(
fn smart_scalar_not_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let modulus = ct_left.message_modulus.0 as u64;
let acc =
self.generate_accumulator(server_key, |x| (x % modulus != scalar as u64) as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree.0 = 1;
Ok(())
}
pub(crate) fn smart_scalar_greater_or_equal(
pub(crate) fn smart_scalar_greater_or_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_scalar_greater_or_equal_assign(server_key, &mut result, scalar)?;
Ok(result)
}
fn smart_scalar_greater_or_equal_assign(
fn smart_scalar_greater_or_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let acc = self.generate_accumulator(server_key, |x| (x >= scalar as u64) as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree.0 = 1;
Ok(())
}
pub(crate) fn smart_scalar_less_or_equal(
pub(crate) fn smart_scalar_less_or_equal<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_scalar_less_or_equal_assign(server_key, &mut result, scalar)?;
Ok(result)
}
fn smart_scalar_less_or_equal_assign(
fn smart_scalar_less_or_equal_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let acc = self.generate_accumulator(server_key, |x| (x <= scalar as u64) as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree.0 = 1;
Ok(())
}
pub(crate) fn smart_scalar_greater(
pub(crate) fn smart_scalar_greater<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_scalar_greater_assign(server_key, &mut result, scalar)?;
Ok(result)
}
fn smart_scalar_greater_assign(
fn smart_scalar_greater_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let acc = self.generate_accumulator(server_key, |x| (x > scalar as u64) as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree.0 = 1;
Ok(())
}
pub(crate) fn smart_scalar_less(
pub(crate) fn smart_scalar_less<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_scalar_less_assign(server_key, &mut result, scalar)?;
Ok(result)
}
fn smart_scalar_less_assign(
fn smart_scalar_less_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let acc = self.generate_accumulator(server_key, |x| (x < scalar as u64) as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree.0 = 1;
Ok(())
}

View File

@@ -1,6 +1,6 @@
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
// Specific division function returning 0 in case of a division by 0
pub(crate) fn safe_division(x: u64, y: u64) -> u64 {
@@ -12,24 +12,24 @@ pub(crate) fn safe_division(x: u64, y: u64) -> u64 {
}
impl ShortintEngine {
pub(crate) fn unchecked_div(
pub(crate) fn unchecked_div<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_div_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_div_assign(
pub(crate) fn unchecked_div_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_functional_bivariate_pbs_assign(
self.unchecked_evaluate_bivariate_function_assign(
server_key,
ct_left,
ct_right,
@@ -38,22 +38,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_div(
pub(crate) fn smart_div<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_div_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_div_assign(
pub(crate) fn smart_div_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
if ct_left.message_modulus.0 + ct_right.degree.0 <= server_key.max_degree.0 {
@@ -73,12 +73,12 @@ impl ShortintEngine {
/// # Panics
///
/// This function will panic if `scalar == 0`
pub(crate) fn unchecked_scalar_div(
pub(crate) fn unchecked_scalar_div<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.unchecked_scalar_div_assign(server_key, &mut result, scalar)?;
Ok(result)
@@ -87,26 +87,26 @@ impl ShortintEngine {
/// # Panics
///
/// This function will panic if `scalar == 0`
pub(crate) fn unchecked_scalar_div_assign(
pub(crate) fn unchecked_scalar_div_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
assert_ne!(scalar, 0);
//generate the accumulator for the multiplication
let acc = self.generate_accumulator(server_key, |x| x / (scalar as u64))?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = Degree(ct.degree.0 / scalar as usize);
Ok(())
}
pub(crate) fn unchecked_scalar_mod(
pub(crate) fn unchecked_scalar_mod<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
modulus: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.unchecked_scalar_mod_assign(server_key, &mut result, modulus)?;
Ok(result)
@@ -115,15 +115,15 @@ impl ShortintEngine {
/// # Panics
///
/// This function will panic if `modulus == 0`
pub(crate) fn unchecked_scalar_mod_assign(
pub(crate) fn unchecked_scalar_mod_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
modulus: u8,
) -> EngineResult<()> {
assert_ne!(modulus, 0);
let acc = self.generate_accumulator(server_key, |x| x % modulus as u64)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = Degree(modulus as usize - 1);
Ok(())
}

View File

@@ -6,9 +6,11 @@ use crate::core_crypto::fft_impl::math::fft::Fft;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::EngineResult;
use crate::shortint::parameters::MessageModulus;
use crate::shortint::server_key::{Accumulator, BivariateAccumulator, MaxDegree};
use crate::shortint::{Ciphertext, ClientKey, CompressedServerKey, ServerKey};
use std::cmp::min;
use crate::shortint::server_key::{BivariateLookupTableOwned, LookupTableOwned, MaxDegree};
use crate::shortint::{
CiphertextBase, CiphertextBig, CiphertextSmall, ClientKey, CompressedServerKey, PBSOrder,
PBSOrderMarker, ServerKey,
};
mod add;
mod bitwise_op;
@@ -39,7 +41,7 @@ impl ShortintEngine {
) -> EngineResult<ServerKey> {
let bootstrap_key: LweBootstrapKeyOwned<u64> =
par_allocate_and_generate_new_lwe_bootstrap_key(
&cks.lwe_secret_key_after_ks,
&cks.small_lwe_secret_key,
&cks.glwe_secret_key,
cks.parameters.pbs_base_log,
cks.parameters.pbs_level,
@@ -75,8 +77,8 @@ impl ShortintEngine {
// Creation of the key switching key
let key_switching_key = allocate_and_generate_new_lwe_keyswitch_key(
&cks.lwe_secret_key,
&cks.lwe_secret_key_after_ks,
&cks.large_lwe_secret_key,
&cks.small_lwe_secret_key,
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
@@ -112,7 +114,7 @@ impl ShortintEngine {
) -> EngineResult<CompressedServerKey> {
#[cfg(not(feature = "__wasm_api"))]
let bootstrapping_key = par_allocate_and_generate_new_seeded_lwe_bootstrap_key(
&cks.lwe_secret_key_after_ks,
&cks.small_lwe_secret_key,
&cks.glwe_secret_key,
cks.parameters.pbs_base_log,
cks.parameters.pbs_level,
@@ -122,7 +124,7 @@ impl ShortintEngine {
#[cfg(feature = "__wasm_api")]
let bootstrapping_key = allocate_and_generate_new_seeded_lwe_bootstrap_key(
&cks.lwe_secret_key_after_ks,
&cks.small_lwe_secret_key,
&cks.glwe_secret_key,
cks.parameters.pbs_base_log,
cks.parameters.pbs_level,
@@ -132,8 +134,8 @@ impl ShortintEngine {
// Creation of the key switching key
let key_switching_key = allocate_and_generate_new_seeded_lwe_keyswitch_key(
&cks.lwe_secret_key,
&cks.lwe_secret_key_after_ks,
&cks.large_lwe_secret_key,
&cks.small_lwe_secret_key,
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
@@ -154,30 +156,21 @@ impl ShortintEngine {
&mut self,
server_key: &ServerKey,
f: F,
) -> EngineResult<Accumulator>
) -> EngineResult<LookupTableOwned>
where
F: Fn(u64) -> u64,
{
Self::generate_accumulator_with_engine(server_key, f)
}
pub(crate) fn keyswitch_bootstrap(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
) -> EngineResult<Ciphertext> {
let mut ct_in = ct.clone();
self.keyswitch_bootstrap_assign(server_key, &mut ct_in)?;
Ok(ct_in)
}
pub(crate) fn keyswitch_bootstrap_assign(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBig,
) -> EngineResult<()> {
// Compute the programmable bootstrapping with fixed test polynomial
let (mut ciphertext_buffers, buffers) = self.buffers_for_key(server_key);
let (mut ciphertext_buffers, buffers) =
self.get_carry_clearing_accumulator_and_buffers(server_key);
// Compute a keyswitch
keyswitch_lwe_ciphertext(
@@ -205,34 +198,54 @@ impl ShortintEngine {
programmable_bootstrap_lwe_ciphertext_mem_optimized(
&ciphertext_buffers.buffer_lwe_after_ks,
&mut ct.ct,
&ciphertext_buffers.accumulator,
&ciphertext_buffers.accumulator.acc,
fourier_bsk,
fft,
stack,
);
ct.degree = ciphertext_buffers.accumulator.degree;
Ok(())
}
pub(crate) fn keyswitch_programmable_bootstrap(
pub(crate) fn clear_carry<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
acc: &Accumulator,
) -> EngineResult<Ciphertext> {
let mut ct_res = ct.clone();
self.keyswitch_programmable_bootstrap_assign(server_key, &mut ct_res, acc)?;
Ok(ct_res)
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_in = ct.clone();
self.clear_carry_assign(server_key, &mut ct_in)?;
Ok(ct_in)
}
pub(crate) fn clear_carry_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => {
let ct = unsafe { std::mem::transmute(ct) };
self.keyswitch_bootstrap_assign(server_key, ct)?;
}
PBSOrder::BootstrapKeyswitch => {
let ct = unsafe { std::mem::transmute(ct) };
self.bootstrap_keyswitch_assign(server_key, ct)?;
}
}
Ok(())
}
pub(crate) fn keyswitch_programmable_bootstrap_assign(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
acc: &Accumulator,
ct: &mut CiphertextBig,
acc: &LookupTableOwned,
) -> EngineResult<()> {
// Compute the programmable bootstrapping with fixed test polynomial
let (mut ciphertext_buffers, buffers) = self.buffers_for_key(server_key);
let (mut ciphertext_buffers, buffers) =
self.get_carry_clearing_accumulator_and_buffers(server_key);
// Compute a key switch
keyswitch_lwe_ciphertext(
@@ -271,29 +284,24 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn keyswitch_programmable_bootstrap_bivariate(
pub(crate) fn unchecked_apply_lookup_table_bivariate<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
acc: &BivariateAccumulator,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_res = ct_left.clone();
self.keyswitch_programmable_bootstrap_bivariate_assign(
server_key,
&mut ct_res,
ct_right,
acc,
)?;
self.unchecked_apply_lookup_table_bivariate_assign(server_key, &mut ct_res, ct_right, acc)?;
Ok(ct_res)
}
pub(crate) fn keyswitch_programmable_bootstrap_bivariate_assign(
pub(crate) fn unchecked_apply_lookup_table_bivariate_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
acc: &BivariateAccumulator,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) -> EngineResult<()> {
let modulus = (ct_right.degree.0 + 1) as u64;
assert!(modulus <= acc.ct_right_modulus.0 as u64);
@@ -304,7 +312,7 @@ impl ShortintEngine {
self.unchecked_add_assign(ct_left, ct_right)?;
// Compute the PBS
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc.acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc.acc)?;
Ok(())
}
@@ -314,7 +322,7 @@ impl ShortintEngine {
server_key: &ServerKey,
f: F,
left_message_scaling: MessageModulus,
) -> EngineResult<BivariateAccumulator>
) -> EngineResult<BivariateLookupTableOwned>
where
F: Fn(u64, u64) -> u64,
{
@@ -325,7 +333,7 @@ impl ShortintEngine {
&mut self,
server_key: &ServerKey,
f: F,
) -> EngineResult<BivariateAccumulator>
) -> EngineResult<BivariateLookupTableOwned>
where
F: Fn(u64, u64) -> u64,
{
@@ -335,26 +343,26 @@ impl ShortintEngine {
self.generate_accumulator_bivariate_with_factor(server_key, f, server_key.message_modulus)
}
pub(crate) fn unchecked_functional_bivariate_pbs<F>(
pub(crate) fn unchecked_evaluate_bivariate_function<F, OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
f: F,
) -> EngineResult<Ciphertext>
) -> EngineResult<CiphertextBase<OpOrder>>
where
F: Fn(u64, u64) -> u64,
{
let mut ct_res = ct_left.clone();
self.unchecked_functional_bivariate_pbs_assign(server_key, &mut ct_res, ct_right, f)?;
self.unchecked_evaluate_bivariate_function_assign(server_key, &mut ct_res, ct_right, f)?;
Ok(ct_res)
}
pub(crate) fn unchecked_functional_bivariate_pbs_assign<F>(
pub(crate) fn unchecked_evaluate_bivariate_function_assign<OpOrder: PBSOrderMarker, F>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
f: F,
) -> EngineResult<()>
where
@@ -364,81 +372,62 @@ impl ShortintEngine {
let factor = MessageModulus(ct_right.degree.0 + 1);
let acc = self.generate_accumulator_bivariate_with_factor(server_key, f, factor)?;
// Compute the PBS
self.keyswitch_programmable_bootstrap_bivariate_assign(
server_key, ct_left, ct_right, &acc,
)?;
self.unchecked_apply_lookup_table_bivariate_assign(server_key, ct_left, ct_right, &acc)?;
Ok(())
}
pub(crate) fn smart_functional_bivariate_pbs_assign<F>(
pub(crate) fn smart_evaluate_bivariate_function<OpOrder: PBSOrderMarker, F>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
f: F,
) -> EngineResult<CiphertextBase<OpOrder>>
where
F: Fn(u64, u64) -> u64,
{
let mut ct_res = ct_left.clone();
self.smart_evaluate_bivariate_function_assign(server_key, &mut ct_res, ct_right, f)?;
Ok(ct_res)
}
pub(crate) fn smart_evaluate_bivariate_function_assign<OpOrder: PBSOrderMarker, F>(
&mut self,
server_key: &ServerKey,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
f: F,
) -> EngineResult<()>
where
F: Fn(u64, u64) -> u64,
{
// First try to clear carries of ct_right
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_right)?;
}
// Generate the accumulator for the function
let factor = MessageModulus(ct_right.degree.0 + 1);
let acc = self.generate_accumulator_bivariate_with_factor(server_key, f, factor)?;
// It was not enough, clean the ct_left carries also
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
}
self.unchecked_functional_bivariate_pbs_assign(server_key, ct_left, ct_right, f)
self.smart_apply_lookup_table_bivariate_assign(server_key, ct_left, ct_right, &acc)?;
Ok(())
}
pub(crate) fn smart_functional_bivariate_pbs<F>(
pub(crate) fn smart_apply_lookup_table_bivariate<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
f: F,
) -> EngineResult<Ciphertext>
where
F: Fn(u64, u64) -> u64,
{
// First try to clear carries of ct_right
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_right)?;
}
// It was not enough, clean the ct_left carries also
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
}
self.unchecked_functional_bivariate_pbs(server_key, ct_left, ct_right, f)
}
// Those are currently not used in shortint, we therefore disable the warning when not compiling
// the C API
#[cfg_attr(not(feature = "__c_api"), allow(dead_code))]
pub(crate) fn smart_bivariate_pbs(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &mut Ciphertext,
acc: &BivariateAccumulator,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_res = ct_left.clone();
self.smart_bivariate_pbs_assign(server_key, &mut ct_res, ct_right, acc)?;
self.smart_apply_lookup_table_bivariate_assign(server_key, &mut ct_res, ct_right, acc)?;
Ok(ct_res)
}
#[cfg_attr(not(feature = "__c_api"), allow(dead_code))]
pub(crate) fn smart_bivariate_pbs_assign(
pub(crate) fn smart_apply_lookup_table_bivariate_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
acc: &BivariateAccumulator,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) -> EngineResult<()> {
if !server_key.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
// After the message_extract, we'll have ct_left, ct_right in [0, message_modulus[
@@ -448,70 +437,225 @@ impl ShortintEngine {
self.message_extract_assign(server_key, ct_right)?;
}
self.keyswitch_programmable_bootstrap_bivariate_assign(server_key, ct_left, ct_right, acc)
self.unchecked_apply_lookup_table_bivariate_assign(server_key, ct_left, ct_right, acc)
}
pub(crate) fn carry_extract_assign(
pub(crate) fn programmable_bootstrap_keyswitch_assign(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextSmall,
acc: &LookupTableOwned,
) -> EngineResult<()> {
let (mut ciphertext_buffers, buffers) =
self.get_carry_clearing_accumulator_and_buffers(server_key);
let fourier_bsk = &server_key.bootstrapping_key;
let fft = Fft::new(fourier_bsk.polynomial_size());
let fft = fft.as_view();
buffers.resize(
programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::<u64>(
fourier_bsk.glwe_size(),
fourier_bsk.polynomial_size(),
fft,
)
.unwrap()
.unaligned_bytes_required(),
);
let stack = buffers.stack();
// Compute a bootstrap
programmable_bootstrap_lwe_ciphertext_mem_optimized(
&ct.ct,
&mut ciphertext_buffers.buffer_lwe_after_pbs,
&acc.acc,
fourier_bsk,
fft,
stack,
);
// Compute a key switch
keyswitch_lwe_ciphertext(
&server_key.key_switching_key,
&ciphertext_buffers.buffer_lwe_after_pbs,
&mut ct.ct,
);
ct.degree = acc.degree;
Ok(())
}
pub(crate) fn bootstrap_keyswitch_assign(
&mut self,
server_key: &ServerKey,
ct: &mut CiphertextSmall,
) -> EngineResult<()> {
// Compute the programmable bootstrapping with fixed test polynomial
let (mut ciphertext_buffers, buffers) =
self.get_carry_clearing_accumulator_and_buffers(server_key);
let fourier_bsk = &server_key.bootstrapping_key;
let fft = Fft::new(fourier_bsk.polynomial_size());
let fft = fft.as_view();
buffers.resize(
programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement::<u64>(
fourier_bsk.glwe_size(),
fourier_bsk.polynomial_size(),
fft,
)
.unwrap()
.unaligned_bytes_required(),
);
let stack = buffers.stack();
// Compute a bootstrap
programmable_bootstrap_lwe_ciphertext_mem_optimized(
&ct.ct,
&mut ciphertext_buffers.buffer_lwe_after_pbs,
&ciphertext_buffers.accumulator.acc,
fourier_bsk,
fft,
stack,
);
// Compute a keyswitch
keyswitch_lwe_ciphertext(
&server_key.key_switching_key,
&ciphertext_buffers.buffer_lwe_after_pbs,
&mut ct.ct,
);
ct.degree = ciphertext_buffers.accumulator.degree;
Ok(())
}
pub(crate) fn apply_lookup_table_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut CiphertextBase<OpOrder>,
acc: &LookupTableOwned,
) -> EngineResult<()> {
// We know the OpOrder corresponds to the CiphertextBig or CiphertextSmall and the memory
// layout is the same as the type information is just encoded in a phantom data marker
match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => {
let ct = unsafe { std::mem::transmute(ct) };
// This updates the ciphertext degree
self.keyswitch_programmable_bootstrap_assign(server_key, ct, acc)?;
}
PBSOrder::BootstrapKeyswitch => {
let ct = unsafe { std::mem::transmute(ct) };
// This updates the ciphertext degree
self.programmable_bootstrap_keyswitch_assign(server_key, ct, acc)?;
}
};
Ok(())
}
pub(crate) fn apply_lookup_table<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &CiphertextBase<OpOrder>,
acc: &LookupTableOwned,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_res = ct.clone();
self.apply_lookup_table_assign(server_key, &mut ct_res, acc)?;
Ok(ct_res)
}
pub(crate) fn apply_msg_identity_lut_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
// We know the OpOrder corresponds to the CiphertextBig or CiphertextSmall and the memory
// layout is the same as the type information is just encoded in a phantom data marker
match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => {
let ct = unsafe { std::mem::transmute(ct) };
// This updates the ciphertext degree
self.keyswitch_bootstrap_assign(server_key, ct)?;
}
PBSOrder::BootstrapKeyswitch => {
let ct = unsafe { std::mem::transmute(ct) };
// This updates the ciphertext degree
self.bootstrap_keyswitch_assign(server_key, ct)?;
}
};
Ok(())
}
pub(crate) fn carry_extract_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
let modulus = ct.message_modulus.0 as u64;
let accumulator = self.generate_accumulator(server_key, |x| x / modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &accumulator)?;
self.apply_lookup_table_assign(server_key, ct, &accumulator)?;
// The degree of the carry
ct.degree = Degree(min(modulus - 1, ct.degree.0 as u64 / modulus) as usize);
Ok(())
}
pub(crate) fn carry_extract(
pub(crate) fn carry_extract<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.carry_extract_assign(server_key, &mut result)?;
Ok(result)
}
pub(crate) fn message_extract_assign(
pub(crate) fn message_extract_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
let modulus = ct.message_modulus.0 as u64;
let acc = self.generate_accumulator(server_key, |x| x % modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = Degree(ct.message_modulus.0 - 1);
Ok(())
}
pub(crate) fn message_extract(
pub(crate) fn message_extract<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.message_extract_assign(server_key, &mut result)?;
Ok(result)
}
// Impossible to call the assign function in this case
pub(crate) fn create_trivial(
pub(crate) fn create_trivial<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
value: u64,
) -> EngineResult<Ciphertext> {
let lwe_size = server_key
.bootstrapping_key
.output_lwe_dimension()
.to_lwe_size();
) -> EngineResult<CiphertextBase<OpOrder>> {
let lwe_size = match OpOrder::pbs_order() {
PBSOrder::KeyswitchBootstrap => server_key
.bootstrapping_key
.output_lwe_dimension()
.to_lwe_size(),
PBSOrder::BootstrapKeyswitch => server_key
.bootstrapping_key
.input_lwe_dimension()
.to_lwe_size(),
};
let modular_value = value as usize % server_key.message_modulus.0;
@@ -526,18 +670,19 @@ impl ShortintEngine {
let degree = Degree(modular_value);
Ok(Ciphertext {
Ok(CiphertextBase {
ct,
degree,
message_modulus: server_key.message_modulus,
carry_modulus: server_key.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn create_trivial_assign(
pub(crate) fn create_trivial_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
value: u64,
) -> EngineResult<()> {
let modular_value = value as usize % server_key.message_modulus.0;

View File

@@ -1,24 +1,24 @@
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_mul_lsb(
pub(crate) fn unchecked_mul_lsb<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_mul_lsb_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_mul_lsb_assign(
pub(crate) fn unchecked_mul_lsb_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
let modulus = (ct_right.degree.0 + 1) as u64;
@@ -36,28 +36,28 @@ impl ShortintEngine {
((x / modulus) * (x % modulus)) % res_modulus
})?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree = Degree(ct_left.message_modulus.0 - 1);
Ok(())
}
pub(crate) fn unchecked_mul_msb(
pub(crate) fn unchecked_mul_msb<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_mul_msb_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_mul_msb_assign(
pub(crate) fn unchecked_mul_msb_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
let modulus = (ct_right.degree.0 + 1) as u64;
let deg = (ct_left.degree.0 * ct_right.degree.0) / ct_right.message_modulus.0;
@@ -76,18 +76,18 @@ impl ShortintEngine {
((x / modulus) * (x % modulus)) / res_modulus
})?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct_left, &acc)?;
self.apply_lookup_table_assign(server_key, ct_left, &acc)?;
ct_left.degree = Degree(deg);
Ok(())
}
pub(crate) fn unchecked_mul_lsb_small_carry_modulus(
pub(crate) fn unchecked_mul_lsb_small_carry_modulus<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct1: &mut Ciphertext,
ct2: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct1: &mut CiphertextBase<OpOrder>,
ct2: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
//ct1 + ct2
let mut ct_tmp_left = self.unchecked_add(ct1, ct2)?;
@@ -102,28 +102,28 @@ impl ShortintEngine {
let acc_sub =
self.generate_accumulator(server_key, |x| (((x - z) * (x - z)) / 4) % modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, &mut ct_tmp_left, &acc_add)?;
self.keyswitch_programmable_bootstrap_assign(server_key, &mut ct_tmp_right, &acc_sub)?;
self.apply_lookup_table_assign(server_key, &mut ct_tmp_left, &acc_add)?;
self.apply_lookup_table_assign(server_key, &mut ct_tmp_right, &acc_sub)?;
//Last subtraction might fill one bit of carry
self.unchecked_sub(server_key, &ct_tmp_left, &ct_tmp_right)
}
pub(crate) fn unchecked_mul_lsb_small_carry_modulus_assign(
pub(crate) fn unchecked_mul_lsb_small_carry_modulus_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct1: &mut Ciphertext,
ct2: &mut Ciphertext,
ct1: &mut CiphertextBase<OpOrder>,
ct2: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
*ct1 = self.unchecked_mul_lsb_small_carry_modulus(server_key, ct1, ct2)?;
Ok(())
}
pub(crate) fn smart_mul_lsb_assign(
pub(crate) fn smart_mul_lsb_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
//Choice of the multiplication algorithm depending on the parameters
if ct_left.message_modulus.0 > ct_left.carry_modulus.0 {
@@ -156,22 +156,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_mul_lsb(
pub(crate) fn smart_mul_lsb<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_mul_lsb_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn smart_mul_msb_assign(
pub(crate) fn smart_mul_msb_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
if !server_key.is_mul_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;
@@ -181,12 +181,12 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_mul_msb(
pub(crate) fn smart_mul_msb<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.smart_mul_msb_assign(server_key, &mut result, ct_right)?;
Ok(result)

View File

@@ -2,42 +2,42 @@ use crate::core_crypto::algorithms::*;
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_neg(
pub(crate) fn unchecked_neg<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.unchecked_neg_assign(server_key, &mut result)?;
Ok(result)
}
pub(crate) fn unchecked_neg_with_correcting_term(
pub(crate) fn unchecked_neg_with_correcting_term<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
) -> EngineResult<(Ciphertext, u64)> {
ct: &CiphertextBase<OpOrder>,
) -> EngineResult<(CiphertextBase<OpOrder>, u64)> {
let mut result = ct.clone();
let z = self.unchecked_neg_assign_with_correcting_term(server_key, &mut result)?;
Ok((result, z))
}
pub(crate) fn unchecked_neg_assign(
pub(crate) fn unchecked_neg_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
let _z = self.unchecked_neg_assign_with_correcting_term(server_key, ct)?;
Ok(())
}
pub(crate) fn unchecked_neg_assign_with_correcting_term(
pub(crate) fn unchecked_neg_assign_with_correcting_term<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<u64> {
// z = ceil( degree / 2^p ) * 2^p
let msg_mod = ct.message_modulus.0;
@@ -62,26 +62,26 @@ impl ShortintEngine {
Ok(z)
}
pub(crate) fn smart_neg(
pub(crate) fn smart_neg<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
// If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
if !server_key.is_neg_possible(ct) {
self.keyswitch_bootstrap_assign(server_key, ct)?;
self.apply_msg_identity_lut_assign(server_key, ct)?;
}
self.unchecked_neg(server_key, ct)
}
pub(crate) fn smart_neg_assign(
pub(crate) fn smart_neg_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
// If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
if !server_key.is_neg_possible(ct) {
self.keyswitch_bootstrap_assign(server_key, ct)?;
self.apply_msg_identity_lut_assign(server_key, ct)?;
}
self.unchecked_neg_assign(server_key, ct)
}

View File

@@ -2,22 +2,22 @@ use crate::core_crypto::algorithms::*;
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_scalar_add(
pub(crate) fn unchecked_scalar_add<OpOrder: PBSOrderMarker>(
&mut self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_result = ct.clone();
self.unchecked_scalar_add_assign(&mut ct_result, scalar)?;
Ok(ct_result)
}
pub(crate) fn unchecked_scalar_add_assign(
pub(crate) fn unchecked_scalar_add_assign<OpOrder: PBSOrderMarker>(
&mut self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let delta = (1_u64 << 63) / (ct.message_modulus.0 * ct.carry_modulus.0) as u64;
@@ -29,10 +29,10 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn unchecked_scalar_add_assign_crt(
pub(crate) fn unchecked_scalar_add_assign_crt<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let delta =
@@ -45,22 +45,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_scalar_add(
pub(crate) fn smart_scalar_add<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_result = ct.clone();
self.smart_scalar_add_assign(server_key, &mut ct_result, scalar)?;
Ok(ct_result)
}
pub(crate) fn smart_scalar_add_assign(
pub(crate) fn smart_scalar_add_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let modulus = server_key.message_modulus.0 as u64;
@@ -70,7 +70,7 @@ impl ShortintEngine {
} else {
// If the scalar is too large, PBS is used to compute the scalar mul
let acc = self.generate_accumulator(server_key, |x| (scalar as u64 + x) % modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = Degree(server_key.message_modulus.0 - 1);
}
Ok(())

View File

@@ -2,23 +2,23 @@ use crate::core_crypto::algorithms::*;
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_scalar_mul(
pub(crate) fn unchecked_scalar_mul<OpOrder: PBSOrderMarker>(
&mut self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_result = ct.clone();
self.unchecked_scalar_mul_assign(&mut ct_result, scalar)?;
Ok(ct_result)
}
pub(crate) fn unchecked_scalar_mul_assign(
pub(crate) fn unchecked_scalar_mul_assign<OpOrder: PBSOrderMarker>(
&mut self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let scalar = u64::from(scalar);
@@ -29,22 +29,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_scalar_mul(
pub(crate) fn smart_scalar_mul<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ctxt: &mut Ciphertext,
ctxt: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_result = ctxt.clone();
self.smart_scalar_mul_assign(server_key, &mut ct_result, scalar)?;
Ok(ct_result)
}
pub(crate) fn smart_scalar_mul_assign(
pub(crate) fn smart_scalar_mul_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ctxt: &mut Ciphertext,
ctxt: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let modulus = server_key.message_modulus.0 as u64;
@@ -56,7 +56,7 @@ impl ShortintEngine {
// If the ciphertext cannot be multiplied without exceeding the degree max
else {
let acc = self.generate_accumulator(server_key, |x| (scalar as u64 * x) % modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ctxt, &acc)?;
self.apply_lookup_table_assign(server_key, ctxt, &acc)?;
ctxt.degree = Degree(server_key.message_modulus.0 - 1);
}
Ok(())

View File

@@ -2,22 +2,22 @@ use crate::core_crypto::algorithms::*;
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_scalar_sub(
pub(crate) fn unchecked_scalar_sub<OpOrder: PBSOrderMarker>(
&mut self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_result = ct.clone();
self.unchecked_scalar_sub_assign(&mut ct_result, scalar)?;
Ok(ct_result)
}
pub(crate) fn unchecked_scalar_sub_assign(
pub(crate) fn unchecked_scalar_sub_assign<OpOrder: PBSOrderMarker>(
&mut self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let neg_scalar = u64::from(scalar.wrapping_neg()) % ct.message_modulus.0 as u64;
@@ -31,22 +31,22 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_scalar_sub(
pub(crate) fn smart_scalar_sub<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut ct_result = ct.clone();
self.smart_scalar_sub_assign(server_key, &mut ct_result, scalar)?;
Ok(ct_result)
}
pub(crate) fn smart_scalar_sub_assign(
pub(crate) fn smart_scalar_sub_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> EngineResult<()> {
let modulus = server_key.message_modulus.0 as u64;
@@ -57,7 +57,7 @@ impl ShortintEngine {
let scalar = u64::from(scalar);
// If the scalar is too large, PBS is used to compute the scalar mul
let acc = self.generate_accumulator(server_key, |x| (x - scalar) % modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = Degree(server_key.message_modulus.0 - 1);
}
Ok(())

View File

@@ -1,45 +1,45 @@
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_scalar_right_shift(
pub(crate) fn unchecked_scalar_right_shift<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
shift: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.unchecked_scalar_right_shift_assign(server_key, &mut result, shift)?;
Ok(result)
}
pub(crate) fn unchecked_scalar_right_shift_assign(
pub(crate) fn unchecked_scalar_right_shift_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) -> EngineResult<()> {
let acc = self.generate_accumulator(server_key, |x| x >> shift)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = Degree(ct.degree.0 >> shift);
Ok(())
}
pub(crate) fn unchecked_scalar_left_shift(
pub(crate) fn unchecked_scalar_left_shift<OpOrder: PBSOrderMarker>(
&mut self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
shift: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.unchecked_scalar_left_shift_assign(&mut result, shift)?;
Ok(result)
}
pub(crate) fn unchecked_scalar_left_shift_assign(
pub(crate) fn unchecked_scalar_left_shift_assign<OpOrder: PBSOrderMarker>(
&mut self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) -> EngineResult<()> {
let scalar = 1_u8 << shift;
@@ -47,21 +47,21 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_scalar_left_shift(
pub(crate) fn smart_scalar_left_shift<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct.clone();
self.smart_scalar_left_shift_assign(server_key, &mut result, shift)?;
Ok(result)
}
pub(crate) fn smart_scalar_left_shift_assign(
pub(crate) fn smart_scalar_left_shift_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) -> EngineResult<()> {
if server_key.is_scalar_left_shift_possible(ct, shift) {
@@ -69,7 +69,7 @@ impl ShortintEngine {
} else {
let modulus = server_key.message_modulus.0 as u64;
let acc = self.generate_accumulator(server_key, |x| (x << shift) % modulus)?;
self.keyswitch_programmable_bootstrap_assign(server_key, ct, &acc)?;
self.apply_lookup_table_assign(server_key, ct, &acc)?;
ct.degree = ct.degree.after_left_shift(shift, modulus as usize);
}
Ok(())

View File

@@ -1,37 +1,37 @@
use crate::core_crypto::algorithms::*;
use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::{Ciphertext, ServerKey};
use crate::shortint::{CiphertextBase, PBSOrderMarker, ServerKey};
impl ShortintEngine {
pub(crate) fn unchecked_sub(
pub(crate) fn unchecked_sub<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
let mut result = ct_left.clone();
self.unchecked_sub_assign(server_key, &mut result, ct_right)?;
Ok(result)
}
pub(crate) fn unchecked_sub_assign(
pub(crate) fn unchecked_sub_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<()> {
self.unchecked_sub_assign_with_correcting_term(server_key, ct_left, ct_right)?;
Ok(())
}
pub(crate) fn unchecked_sub_with_correcting_term(
pub(crate) fn unchecked_sub_with_correcting_term<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> EngineResult<(Ciphertext, u64)> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<(CiphertextBase<OpOrder>, u64)> {
let mut result = ct_left.clone();
let z =
self.unchecked_sub_assign_with_correcting_term(server_key, &mut result, ct_right)?;
@@ -39,11 +39,11 @@ impl ShortintEngine {
Ok((result, z))
}
pub(crate) fn unchecked_sub_assign_with_correcting_term(
pub(crate) fn unchecked_sub_assign_with_correcting_term<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> EngineResult<u64> {
let (neg_right, z) = self.unchecked_neg_with_correcting_term(server_key, ct_right)?;
@@ -54,12 +54,12 @@ impl ShortintEngine {
Ok(z)
}
pub(crate) fn smart_sub(
pub(crate) fn smart_sub<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<Ciphertext> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
// If the ciphertext cannot be subtracted together without exceeding the degree max
if !server_key.is_sub_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_right)?;
@@ -68,11 +68,11 @@ impl ShortintEngine {
self.unchecked_sub(server_key, ct_left, ct_right)
}
pub(crate) fn smart_sub_assign(
pub(crate) fn smart_sub_assign<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<()> {
// If the ciphertext cannot be subtracted together without exceeding the degree max
if !server_key.is_sub_possible(ct_left, ct_right) {
@@ -84,12 +84,12 @@ impl ShortintEngine {
Ok(())
}
pub(crate) fn smart_sub_with_correcting_term(
pub(crate) fn smart_sub_with_correcting_term<OpOrder: PBSOrderMarker>(
&mut self,
server_key: &ServerKey,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> EngineResult<(Ciphertext, u64)> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> EngineResult<(CiphertextBase<OpOrder>, u64)> {
//If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
if !server_key.is_sub_possible(ct_left, ct_right) {
self.message_extract_assign(server_key, ct_left)?;

View File

@@ -9,7 +9,7 @@ use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::{EngineResult, ShortintEngine};
use crate::shortint::server_key::MaxDegree;
use crate::shortint::wopbs::WopbsKey;
use crate::shortint::{Ciphertext, ClientKey, Parameters, ServerKey};
use crate::shortint::{CiphertextBase, ClientKey, PBSOrderMarker, Parameters, ServerKey};
impl ShortintEngine {
// Creates a key when ONLY a wopbs is used.
@@ -19,7 +19,7 @@ impl ShortintEngine {
sks: &ServerKey,
) -> EngineResult<WopbsKey> {
let cbs_pfpksk = par_allocate_and_generate_new_circuit_bootstrap_lwe_pfpksk_list(
&cks.lwe_secret_key,
&cks.large_lwe_secret_key,
&cks.glwe_secret_key,
cks.parameters.pfks_base_log,
cks.parameters.pfks_level,
@@ -109,7 +109,7 @@ impl ShortintEngine {
// KSK to convert from input ciphertext key to the wopbs input one
let ksk_pbs_large_to_wopbs_large = allocate_and_generate_new_lwe_keyswitch_key(
&cks.lwe_secret_key,
&cks.large_lwe_secret_key,
&large_lwe_secret_key,
cks.parameters.ks_base_log,
cks.parameters.ks_level,
@@ -121,7 +121,7 @@ impl ShortintEngine {
// classical PBS. This allows compatibility between PBS and WoPBS
let ksk_wopbs_large_to_pbs_small = allocate_and_generate_new_lwe_keyswitch_key(
&large_lwe_secret_key,
&cks.lwe_secret_key_after_ks,
&cks.small_lwe_secret_key,
cks.parameters.ks_base_log,
cks.parameters.ks_level,
cks.parameters.lwe_modular_std_dev,
@@ -290,14 +290,14 @@ impl ShortintEngine {
Ok(output_cbs_vp_ct)
}
pub(crate) fn extract_bits_circuit_bootstrapping(
pub(crate) fn extract_bits_circuit_bootstrapping<OpOrder: PBSOrderMarker>(
&mut self,
wopbs_key: &WopbsKey,
ct_in: &Ciphertext,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
delta_log: DeltaLog,
nb_bit_to_extract: ExtractedBitsCount,
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let extracted_bits =
self.extract_bits(delta_log, &ct_in.ct, wopbs_key, nb_bit_to_extract)?;
@@ -315,22 +315,23 @@ impl ShortintEngine {
let ciphertext = LweCiphertextOwned::from_container(ciphertext_list.into_container());
let sks = &wopbs_key.wopbs_server_key;
let ct_out = Ciphertext {
let ct_out = CiphertextBase {
ct: ciphertext,
degree: Degree(sks.message_modulus.0 - 1),
message_modulus: sks.message_modulus,
carry_modulus: sks.carry_modulus,
_order_marker: Default::default(),
};
Ok(ct_out)
}
pub(crate) fn programmable_bootstrapping_without_padding(
pub(crate) fn programmable_bootstrapping_without_padding<OpOrder: PBSOrderMarker>(
&mut self,
wopbs_key: &WopbsKey,
ct_in: &Ciphertext,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let sks = &wopbs_key.wopbs_server_key;
let delta = (1_usize << 63) / (sks.message_modulus.0 * sks.carry_modulus.0) * 2;
let delta_log = DeltaLog(f64::log2(delta as f64) as usize);
@@ -349,15 +350,15 @@ impl ShortintEngine {
Ok(ciphertext)
}
pub(crate) fn keyswitch_to_wopbs_params(
pub(crate) fn keyswitch_to_wopbs_params<OpOrder: PBSOrderMarker>(
&mut self,
sks: &ServerKey,
wopbs_key: &WopbsKey,
ct_in: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_in: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
// First PBS to remove the noise
let acc = self.generate_accumulator(sks, |x| x)?;
let ct_clean = self.keyswitch_programmable_bootstrap(sks, ct_in, &acc)?;
let ct_clean = self.apply_lookup_table(sks, ct_in, &acc)?;
let mut buffer_lwe_after_ks = LweCiphertextOwned::new(
0,
@@ -374,26 +375,28 @@ impl ShortintEngine {
&mut buffer_lwe_after_ks,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: buffer_lwe_after_ks,
degree: ct_clean.degree,
message_modulus: ct_clean.message_modulus,
carry_modulus: ct_clean.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn keyswitch_to_pbs_params(
pub(crate) fn keyswitch_to_pbs_params<OpOrder: PBSOrderMarker>(
&mut self,
wopbs_key: &WopbsKey,
ct_in: &Ciphertext,
) -> EngineResult<Ciphertext> {
ct_in: &CiphertextBase<OpOrder>,
) -> EngineResult<CiphertextBase<OpOrder>> {
// move to wopbs parameters to pbs parameters
//Keyswitch-PBS:
// 1. KS to go back to the original encryption key
// 2. PBS to remove the noise added by the previous KS
//
let acc = self.generate_accumulator(&wopbs_key.pbs_server_key, |x| x)?;
let (mut ciphertext_buffers, buffers) = self.buffers_for_key(&wopbs_key.pbs_server_key);
let (mut ciphertext_buffers, buffers) =
self.get_carry_clearing_accumulator_and_buffers(&wopbs_key.pbs_server_key);
// Compute a key switch
keyswitch_lwe_ciphertext(
&wopbs_key.pbs_server_key.key_switching_key,
@@ -429,20 +432,21 @@ impl ShortintEngine {
stack,
);
Ok(Ciphertext {
Ok(CiphertextBase {
ct: ct_out,
degree: ct_in.degree,
message_modulus: ct_in.message_modulus,
carry_modulus: ct_in.carry_modulus,
_order_marker: Default::default(),
})
}
pub(crate) fn wopbs(
pub(crate) fn wopbs<OpOrder: PBSOrderMarker>(
&mut self,
wopbs_key: &WopbsKey,
ct_in: &Ciphertext,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let tmp_sks = &wopbs_key.wopbs_server_key;
let delta = (1_usize << 63) / (tmp_sks.message_modulus.0 * tmp_sks.carry_modulus.0);
let delta_log = DeltaLog(f64::log2(delta as f64) as usize);
@@ -460,13 +464,13 @@ impl ShortintEngine {
Ok(ct_out)
}
pub(crate) fn programmable_bootstrapping(
pub(crate) fn programmable_bootstrapping<OpOrder: PBSOrderMarker>(
&mut self,
wopbs_key: &WopbsKey,
sks: &ServerKey,
ct_in: &Ciphertext,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let ct_wopbs = self.keyswitch_to_wopbs_params(sks, wopbs_key, ct_in)?;
let result_ct = self.wopbs(wopbs_key, &ct_wopbs, lut)?;
let ct_out = self.keyswitch_to_pbs_params(wopbs_key, &result_ct)?;
@@ -474,12 +478,12 @@ impl ShortintEngine {
Ok(ct_out)
}
pub(crate) fn programmable_bootstrapping_native_crt(
pub(crate) fn programmable_bootstrapping_native_crt<OpOrder: PBSOrderMarker>(
&mut self,
wopbs_key: &WopbsKey,
ct_in: &mut Ciphertext,
ct_in: &mut CiphertextBase<OpOrder>,
lut: &[u64],
) -> EngineResult<Ciphertext> {
) -> EngineResult<CiphertextBase<OpOrder>> {
let nb_bit_to_extract =
f64::log2((ct_in.message_modulus.0 * ct_in.carry_modulus.0) as f64).ceil() as usize;
let delta_log = DeltaLog(64 - nb_bit_to_extract);

View File

@@ -58,10 +58,16 @@ pub mod server_key;
#[cfg(not(feature = "__wasm_api"))]
pub mod wopbs;
pub use ciphertext::{Ciphertext, CompressedCiphertext};
pub use ciphertext::{
CiphertextBase, CiphertextBig, CiphertextSmall, CompressedCiphertextBase,
CompressedCiphertextBig, CompressedCiphertextSmall, PBSOrder, PBSOrderMarker,
};
pub use client_key::ClientKey;
pub use parameters::Parameters;
pub use public_key::{CompressedPublicKey, PublicKey};
pub use public_key::{
CompressedPublicKeyBase, CompressedPublicKeyBig, CompressedPublicKeySmall, PublicKeyBase,
PublicKeyBig, PublicKeySmall,
};
pub use server_key::{CheckError, CompressedServerKey, ServerKey};
/// Generate a couple of client and server keys.

View File

@@ -810,6 +810,82 @@ pub const PARAM_MESSAGE_8_CARRY_0: Parameters = Parameters {
carry_modulus: CarryModulus(1),
};
pub const PARAM_SMALL_MESSAGE_1_CARRY_1: Parameters = Parameters {
lwe_dimension: LweDimension(783),
glwe_dimension: GlweDimension(3),
polynomial_size: PolynomialSize(512),
lwe_modular_std_dev: StandardDev(0.0000033382067621812462),
glwe_modular_std_dev: StandardDev(0.0000000000034525330484572114),
pbs_base_log: DecompositionBaseLog(18),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(3),
ks_base_log: DecompositionBaseLog(5),
pfks_level: DecompositionLevelCount(0),
pfks_base_log: DecompositionBaseLog(0),
pfks_modular_std_dev: StandardDev(0.0000000000034525330484572114),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(2),
carry_modulus: CarryModulus(2),
};
pub const PARAM_SMALL_MESSAGE_2_CARRY_2: Parameters = Parameters {
lwe_dimension: LweDimension(870),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(2048),
lwe_modular_std_dev: StandardDev(0.0000006791658447437413),
glwe_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
pbs_base_log: DecompositionBaseLog(23),
pbs_level: DecompositionLevelCount(1),
ks_level: DecompositionLevelCount(4),
ks_base_log: DecompositionBaseLog(4),
pfks_level: DecompositionLevelCount(0),
pfks_base_log: DecompositionBaseLog(0),
pfks_modular_std_dev: StandardDev(0.00000000000000029403601535432533),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(4),
carry_modulus: CarryModulus(4),
};
pub const PARAM_SMALL_MESSAGE_3_CARRY_3: Parameters = Parameters {
lwe_dimension: LweDimension(1025),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(8192),
lwe_modular_std_dev: StandardDev(0.00000003980397588319241),
glwe_modular_std_dev: StandardDev(0.0000000000000000002168404344971009),
pbs_base_log: DecompositionBaseLog(15),
pbs_level: DecompositionLevelCount(2),
ks_level: DecompositionLevelCount(5),
ks_base_log: DecompositionBaseLog(4),
pfks_level: DecompositionLevelCount(0),
pfks_base_log: DecompositionBaseLog(0),
pfks_modular_std_dev: StandardDev(0.0000000000000000002168404344971009),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(8),
carry_modulus: CarryModulus(8),
};
pub const PARAM_SMALL_MESSAGE_4_CARRY_4: Parameters = Parameters {
lwe_dimension: LweDimension(1214),
glwe_dimension: GlweDimension(1),
polynomial_size: PolynomialSize(32768),
lwe_modular_std_dev: StandardDev(0.0000000012520482863081104),
glwe_modular_std_dev: StandardDev(0.0000000000000000002168404344971009),
pbs_base_log: DecompositionBaseLog(15),
pbs_level: DecompositionLevelCount(2),
ks_level: DecompositionLevelCount(6),
ks_base_log: DecompositionBaseLog(4),
pfks_level: DecompositionLevelCount(0),
pfks_base_log: DecompositionBaseLog(0),
pfks_modular_std_dev: StandardDev(0.0000000000000000002168404344971009),
cbs_level: DecompositionLevelCount(0),
cbs_base_log: DecompositionBaseLog(0),
message_modulus: MessageModulus(16),
carry_modulus: CarryModulus(16),
};
/// Return a parameter set from a message and carry moduli.
///
/// # Example

View File

@@ -3,7 +3,10 @@
//! The TFHE-rs preludes include convenient imports.
//! Having `tfhe::shortint::prelude::*;` should be enough to start using the lib.
pub use super::ciphertext::{Ciphertext, CompressedCiphertext};
pub use super::ciphertext::{
CiphertextBase, CiphertextBig, CiphertextSmall, CompressedCiphertextBase,
CompressedCiphertextBig, CompressedCiphertextSmall, PBSOrder, PBSOrderMarker,
};
pub use super::client_key::ClientKey;
pub use super::gen_keys;
pub use super::parameters::{
@@ -16,5 +19,5 @@ pub use super::parameters::{
PARAM_MESSAGE_3_CARRY_3, PARAM_MESSAGE_3_CARRY_4, PARAM_MESSAGE_3_CARRY_5,
PARAM_MESSAGE_4_CARRY_4,
};
pub use super::public_key::PublicKey;
pub use super::public_key::{PublicKeyBase, PublicKeyBig, PublicKeySmall};
pub use super::server_key::ServerKey;

View File

@@ -1,6 +1,8 @@
//! Module with the definition of the compressed PublicKey.
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Ciphertext;
use crate::shortint::ciphertext::{
BootstrapKeyswitch, CiphertextBase, KeyswitchBootstrap, PBSOrderMarker,
};
use crate::shortint::engine::ShortintEngine;
use crate::shortint::parameters::{MessageModulus, Parameters};
use crate::shortint::ClientKey;
@@ -9,32 +11,60 @@ use std::fmt::Debug;
/// A structure containing a public key.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CompressedPublicKey {
pub struct CompressedPublicKeyBase<OpOrder: PBSOrderMarker> {
pub(crate) lwe_public_key: SeededLwePublicKeyOwned<u64>,
pub parameters: Parameters,
pub _order_marker: std::marker::PhantomData<OpOrder>,
}
impl CompressedPublicKey {
/// Generate a compressed public key.
pub type CompressedPublicKeyBig = CompressedPublicKeyBase<KeyswitchBootstrap>;
pub type CompressedPublicKeySmall = CompressedPublicKeyBase<BootstrapKeyswitch>;
impl CompressedPublicKeyBig {
/// Generate a public key.
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::client_key::ClientKey;
/// use tfhe::shortint::parameters::Parameters;
/// use tfhe::shortint::public_key::CompressedPublicKey;
/// use tfhe::shortint::public_key::CompressedPublicKeyBig;
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = CompressedPublicKey::new(&cks);
/// let pk = CompressedPublicKeyBig::new(&cks);
/// ```
pub fn new(client_key: &ClientKey) -> CompressedPublicKey {
pub fn new(client_key: &ClientKey) -> Self {
ShortintEngine::with_thread_local_mut(|engine| {
engine.new_compressed_public_key(client_key).unwrap()
})
}
}
impl CompressedPublicKeySmall {
/// Generate a public key.
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::client_key::ClientKey;
/// use tfhe::shortint::parameters::Parameters;
/// use tfhe::shortint::public_key::CompressedPublicKeySmall;
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = CompressedPublicKeySmall::new(&cks);
/// ```
pub fn new(client_key: &ClientKey) -> Self {
ShortintEngine::with_thread_local_mut(|engine| {
engine.new_compressed_public_key(client_key).unwrap()
})
}
}
impl<OpOrder: PBSOrderMarker> CompressedPublicKeyBase<OpOrder> {
/// Encrypts a small integer message using the client key.
///
/// The input message is reduced to the encrypted message space modulus
@@ -43,12 +73,29 @@ impl CompressedPublicKey {
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{ClientKey, CompressedPublicKey};
/// use tfhe::shortint::{ClientKey, CompressedPublicKeyBig, CompressedPublicKeySmall};
///
/// // Generate the client key:
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
/// let pk = CompressedPublicKey::new(&cks);
/// let pk = CompressedPublicKeyBig::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 3;
/// let ct = pk.encrypt(msg);
///
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// // Encryption of one message that is outside the encrypted message modulus:
/// let msg = 5;
/// let ct = pk.encrypt(msg);
///
/// let dec = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
///
/// let pk = CompressedPublicKeySmall::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 3;
@@ -65,7 +112,7 @@ impl CompressedPublicKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn encrypt(&self, message: u64) -> Ciphertext {
pub fn encrypt(&self, message: u64) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_compressed_public_key(self, message)
@@ -79,12 +126,23 @@ impl CompressedPublicKey {
///
/// ```rust
/// use tfhe::shortint::parameters::MessageModulus;
/// use tfhe::shortint::{ClientKey, CompressedPublicKey, Parameters};
/// use tfhe::shortint::{ClientKey, CompressedPublicKeyBig, CompressedPublicKeySmall, Parameters};
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = CompressedPublicKey::new(&cks);
/// let pk = CompressedPublicKeyBig::new(&cks);
///
/// let msg = 3;
///
/// // Encryption of one message:
/// let ct = pk.encrypt_with_message_modulus(msg, MessageModulus(6));
///
/// // Decryption:
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// let pk = CompressedPublicKeySmall::new(&cks);
///
/// let msg = 3;
///
@@ -99,7 +157,7 @@ impl CompressedPublicKey {
&self,
message: u64,
message_modulus: MessageModulus,
) -> Ciphertext {
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_message_modulus_and_compressed_public_key(
@@ -116,12 +174,24 @@ impl CompressedPublicKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, CompressedPublicKey, Parameters};
/// use tfhe::shortint::{ClientKey, CompressedPublicKeyBig, CompressedPublicKeySmall, Parameters};
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = CompressedPublicKey::new(&cks);
/// let pk = CompressedPublicKeyBig::new(&cks);
///
/// let msg = 7;
/// let ct = pk.unchecked_encrypt(msg);
/// // | ct |
/// // | carry | message |
/// // |-------|---------|
/// // | 0 1 | 1 1 |
///
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
///
/// let pk = CompressedPublicKeySmall::new(&cks);
///
/// let msg = 7;
/// let ct = pk.unchecked_encrypt(msg);
@@ -133,7 +203,7 @@ impl CompressedPublicKey {
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn unchecked_encrypt(&self, message: u64) -> Ciphertext {
pub fn unchecked_encrypt(&self, message: u64) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_encrypt_with_compressed_public_key(self, message)
@@ -149,12 +219,21 @@ impl CompressedPublicKey {
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{ClientKey, CompressedPublicKey};
/// use tfhe::shortint::{ClientKey, CompressedPublicKeyBig, CompressedPublicKeySmall};
///
/// // Generate the client key:
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
/// // DISCLAIMER: Note that this parameter is not guaranteed to be secure
/// let pk = CompressedPublicKey::new(&cks);
/// let pk = CompressedPublicKeyBig::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
/// let ct = pk.encrypt_without_padding(msg);
///
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
///
/// let pk = CompressedPublicKeyBig::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
@@ -163,7 +242,7 @@ impl CompressedPublicKey {
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_without_padding(&self, message: u64) -> Ciphertext {
pub fn encrypt_without_padding(&self, message: u64) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_without_padding_with_compressed_public_key(self, message)
@@ -177,12 +256,24 @@ impl CompressedPublicKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, CompressedPublicKey, Parameters};
/// use tfhe::shortint::{ClientKey, CompressedPublicKeyBig, CompressedPublicKeySmall, Parameters};
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = CompressedPublicKey::new(&cks);
/// let pk = CompressedPublicKeyBig::new(&cks);
///
/// let msg = 2;
/// let modulus = 3;
///
/// // Encryption of one message:
/// let ct = pk.encrypt_native_crt(msg, modulus);
///
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
///
/// let pk = CompressedPublicKeySmall::new(&cks);
///
/// let msg = 2;
/// let modulus = 3;
@@ -194,7 +285,7 @@ impl CompressedPublicKey {
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
/// ```
pub fn encrypt_native_crt(&self, message: u64, message_modulus: u8) -> Ciphertext {
pub fn encrypt_native_crt(&self, message: u64, message_modulus: u8) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_native_crt_with_compressed_public_key(self, message, message_modulus)

View File

@@ -3,5 +3,5 @@
pub mod compressed;
pub mod standard;
pub use compressed::CompressedPublicKey;
pub use standard::PublicKey;
pub use compressed::{CompressedPublicKeyBase, CompressedPublicKeyBig, CompressedPublicKeySmall};
pub use standard::{PublicKeyBase, PublicKeyBig, PublicKeySmall};

View File

@@ -1,20 +1,26 @@
//! Module with the definition of the PublicKey.
use crate::core_crypto::entities::*;
use crate::shortint::ciphertext::Ciphertext;
use crate::shortint::ciphertext::{
BootstrapKeyswitch, CiphertextBase, KeyswitchBootstrap, PBSOrderMarker,
};
use crate::shortint::engine::ShortintEngine;
use crate::shortint::parameters::{MessageModulus, Parameters};
use crate::shortint::{ClientKey, CompressedPublicKey};
use crate::shortint::{ClientKey, CompressedPublicKeyBase};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
/// A structure containing a public key.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PublicKey {
pub struct PublicKeyBase<OpOrder: PBSOrderMarker> {
pub(crate) lwe_public_key: LwePublicKeyOwned<u64>,
pub parameters: Parameters,
pub _order_marker: std::marker::PhantomData<OpOrder>,
}
impl PublicKey {
pub type PublicKeyBig = PublicKeyBase<KeyswitchBootstrap>;
pub type PublicKeySmall = PublicKeyBase<BootstrapKeyswitch>;
impl PublicKeyBig {
/// Generate a public key.
///
/// # Example
@@ -22,17 +28,39 @@ impl PublicKey {
/// ```rust
/// use tfhe::shortint::client_key::ClientKey;
/// use tfhe::shortint::parameters::Parameters;
/// use tfhe::shortint::public_key::PublicKey;
/// use tfhe::shortint::public_key::PublicKeyBig;
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = PublicKey::new(&cks);
/// let pk = PublicKeyBig::new(&cks);
/// ```
pub fn new(client_key: &ClientKey) -> PublicKey {
pub fn new(client_key: &ClientKey) -> PublicKeyBig {
ShortintEngine::with_thread_local_mut(|engine| engine.new_public_key(client_key).unwrap())
}
}
impl PublicKeySmall {
/// Generate a public key.
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::client_key::ClientKey;
/// use tfhe::shortint::parameters::Parameters;
/// use tfhe::shortint::public_key::PublicKeySmall;
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = PublicKeySmall::new(&cks);
/// ```
pub fn new(client_key: &ClientKey) -> PublicKeySmall {
ShortintEngine::with_thread_local_mut(|engine| engine.new_public_key(client_key).unwrap())
}
}
impl<OpOrder: PBSOrderMarker> PublicKeyBase<OpOrder> {
/// Encrypt a small integer message using the client key.
///
/// The input message is reduced to the encrypted message space modulus
@@ -41,12 +69,29 @@ impl PublicKey {
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{ClientKey, PublicKey, ServerKey};
/// use tfhe::shortint::{ClientKey, PublicKeyBig, PublicKeySmall, ServerKey};
///
/// // Generate the client key:
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
///
/// let pk = PublicKey::new(&cks);
/// let pk = PublicKeyBig::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 3;
/// let ct = pk.encrypt(msg);
///
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// // Encryption of one message that is outside the encrypted message modulus:
/// let msg = 5;
/// let ct = pk.encrypt(msg);
///
/// let dec = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
///
/// let pk = PublicKeySmall::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 3;
@@ -63,7 +108,7 @@ impl PublicKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(msg % modulus, dec);
/// ```
pub fn encrypt(&self, message: u64) -> Ciphertext {
pub fn encrypt(&self, message: u64) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.encrypt_with_public_key(self, message).unwrap()
})
@@ -75,12 +120,23 @@ impl PublicKey {
///
/// ```rust
/// use tfhe::shortint::parameters::MessageModulus;
/// use tfhe::shortint::{ClientKey, Parameters, PublicKey};
/// use tfhe::shortint::{ClientKey, Parameters, PublicKeyBig, PublicKeySmall};
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = PublicKey::new(&cks);
/// let pk = PublicKeyBig::new(&cks);
///
/// let msg = 3;
///
/// // Encryption of one message:
/// let ct = pk.encrypt_with_message_modulus(msg, MessageModulus(6));
///
/// // Decryption:
/// let dec = cks.decrypt(&ct);
/// assert_eq!(msg, dec);
///
/// let pk = PublicKeySmall::new(&cks);
///
/// let msg = 3;
///
@@ -95,7 +151,7 @@ impl PublicKey {
&self,
message: u64,
message_modulus: MessageModulus,
) -> Ciphertext {
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_with_message_modulus_and_public_key(self, message, message_modulus)
@@ -108,12 +164,24 @@ impl PublicKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, Parameters, PublicKey};
/// use tfhe::shortint::{ClientKey, Parameters, PublicKeyBig, PublicKeySmall};
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = PublicKey::new(&cks);
/// let pk = PublicKeyBig::new(&cks);
///
/// let msg = 7;
/// let ct = pk.unchecked_encrypt(msg);
/// // | ct |
/// // | carry | message |
/// // |-------|---------|
/// // | 0 1 | 1 1 |
///
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
///
/// let pk = PublicKeySmall::new(&cks);
///
/// let msg = 7;
/// let ct = pk.unchecked_encrypt(msg);
@@ -125,7 +193,7 @@ impl PublicKey {
/// let dec = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn unchecked_encrypt(&self, message: u64) -> Ciphertext {
pub fn unchecked_encrypt(&self, message: u64) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_encrypt_with_public_key(self, message)
@@ -141,12 +209,21 @@ impl PublicKey {
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{ClientKey, PublicKey};
/// use tfhe::shortint::{ClientKey, PublicKeyBig, PublicKeySmall};
///
/// // Generate the client key:
/// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
/// // DISCLAIMER: Note that this parameter is not guaranteed to be secure
/// let pk = PublicKey::new(&cks);
/// let pk = PublicKeyBig::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
/// let ct = pk.encrypt_without_padding(msg);
///
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
///
/// let pk = PublicKeySmall::new(&cks);
///
/// // Encryption of one message that is within the encrypted message modulus:
/// let msg = 6;
@@ -155,7 +232,7 @@ impl PublicKey {
/// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
/// assert_eq!(msg, dec);
/// ```
pub fn encrypt_without_padding(&self, message: u64) -> Ciphertext {
pub fn encrypt_without_padding(&self, message: u64) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_without_padding_with_public_key(self, message)
@@ -170,12 +247,24 @@ impl PublicKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{ClientKey, Parameters, PublicKey};
/// use tfhe::shortint::{ClientKey, Parameters, PublicKeyBig, PublicKeySmall};
///
/// // Generate the client key:
/// let cks = ClientKey::new(Parameters::default());
///
/// let pk = PublicKey::new(&cks);
/// let pk = PublicKeyBig::new(&cks);
///
/// let msg = 2;
/// let modulus = 3;
///
/// // Encryption of one message:
/// let ct = pk.encrypt_native_crt(msg, modulus);
///
/// // Decryption:
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
///
/// let pk = PublicKeySmall::new(&cks);
///
/// let msg = 2;
/// let modulus = 3;
@@ -187,7 +276,7 @@ impl PublicKey {
/// let dec = cks.decrypt_message_native_crt(&ct, modulus);
/// assert_eq!(msg, dec % modulus as u64);
/// ```
pub fn encrypt_native_crt(&self, message: u64, message_modulus: u8) -> Ciphertext {
pub fn encrypt_native_crt(&self, message: u64, message_modulus: u8) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.encrypt_native_crt_with_public_key(self, message, message_modulus)
@@ -196,8 +285,8 @@ impl PublicKey {
}
}
impl From<CompressedPublicKey> for PublicKey {
fn from(compressed_public_key: CompressedPublicKey) -> Self {
impl<OpOder: PBSOrderMarker> From<CompressedPublicKeyBase<OpOder>> for PublicKeyBase<OpOder> {
fn from(compressed_public_key: CompressedPublicKeyBase<OpOder>) -> Self {
let parameters = compressed_public_key.parameters;
let decompressed_public_key = compressed_public_key
@@ -207,6 +296,7 @@ impl From<CompressedPublicKey> for PublicKey {
Self {
lwe_public_key: decompressed_public_key,
parameters,
_order_marker: Default::default(),
}
}
}

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute homomorphically an addition between two ciphertexts encrypting integer values.
@@ -16,7 +16,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -32,8 +32,27 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(msg1 + msg2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Same thing using the small key for encryption
/// let msg1 = 1;
/// let msg2 = 2;
/// let ct1 = cks.encrypt_small(msg1);
/// let ct2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_add(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_add<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_add(ct_left, ct_right).unwrap()
})
@@ -50,7 +69,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -66,8 +85,24 @@ impl ServerKey {
/// // Decrypt:
/// let two = cks.decrypt(&ct_left);
/// assert_eq!(msg + msg, two);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let mut ct_left = cks.encrypt_small(msg);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_add_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_add_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_add_assign(ct_left, ct_right).unwrap()
})
@@ -82,7 +117,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -97,8 +132,23 @@ impl ServerKey {
/// let can_be_added = sks.is_add_possible(&ct_left, &ct_right);
///
/// assert_eq!(can_be_added, true);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg);
/// let ct_right = cks.encrypt_small(msg);
///
/// // Check if we can perform an addition
/// let can_be_added = sks.is_add_possible(&ct_left, &ct_right);
///
/// assert_eq!(can_be_added, true);
/// ```
pub fn is_add_possible(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> bool {
pub fn is_add_possible<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> bool {
let final_operation_count = ct_left.degree.0 + ct_right.degree.0;
final_operation_count <= self.max_degree.0
}
@@ -112,7 +162,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -131,12 +181,27 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg + msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct1 = cks.encrypt_small(msg);
/// let ct2 = cks.encrypt_small(msg);
///
/// // Compute homomorphically an addition:
/// let ct_res = sks.checked_add(&ct1, &ct2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg + msg);
/// ```
pub fn checked_add(
pub fn checked_add<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_add_possible(ct_left, ct_right) {
let ct_result = self.unchecked_add(ct_left, ct_right);
Ok(ct_result)
@@ -154,7 +219,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -172,11 +237,25 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg + msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_left = cks.encrypt_small(msg);
/// let ct_right = cks.encrypt_small(msg);
///
/// // Compute homomorphically an addition:
/// let res = sks.checked_add_assign(&mut ct_left, &ct_right);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg + msg);
/// ```
pub fn checked_add_assign(
pub fn checked_add_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
if self.is_add_possible(ct_left, ct_right) {
self.unchecked_add_assign(ct_left, ct_right);
@@ -194,7 +273,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -211,8 +290,25 @@ impl ServerKey {
/// // Decrypt:
/// let two = cks.decrypt(&ct_res);
/// assert_eq!(msg + msg, two);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_add(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_add<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_add(self, ct_left, ct_right).unwrap()
})
@@ -226,15 +322,15 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let msg1 = 15;
/// let msg2 = 3;
///
/// // Encrypt two messages:
/// let mut ct1 = cks.unchecked_encrypt(msg1);
/// let mut ct2 = cks.encrypt(msg2);
///
@@ -247,8 +343,28 @@ impl ServerKey {
/// // 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_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.unchecked_encrypt_small(msg1);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_add_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_add_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_add_assign(self, ct_left, ct_right).unwrap()
})

View File

@@ -1,7 +1,7 @@
use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::CheckError::CarryFull;
use crate::shortint::{CheckError, Ciphertext};
use crate::shortint::{CheckError, CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute bitwise AND between two ciphertexts without checks.
@@ -12,9 +12,9 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 2;
/// let clear_2 = 1;
@@ -26,8 +26,22 @@ impl ServerKey {
///
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(clear_1 & clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let ct_1 = cks.encrypt_small(clear_1);
/// let ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_bitand(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_bitand<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_bitand(self, ct_left, ct_right).unwrap()
})
@@ -41,9 +55,9 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 1;
/// let clear_2 = 2;
@@ -55,8 +69,22 @@ impl ServerKey {
///
/// let res = cks.decrypt(&ct_left);
/// assert_eq!(clear_1 & clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let mut ct_left = cks.encrypt_small(clear_1);
/// let ct_right = cks.encrypt_small(clear_2);
///
/// sks.unchecked_bitand_assign(&mut ct_left, &ct_right);
///
/// let res = cks.decrypt(&ct_left);
/// assert_eq!(clear_1 & clear_2, res);
/// ```
pub fn unchecked_bitand_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_bitand_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_bitand_assign(self, ct_left, ct_right)
@@ -73,7 +101,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -92,12 +120,27 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg & msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct1 = cks.encrypt_small(msg);
/// let ct2 = cks.encrypt_small(msg);
///
/// // Compute homomorphically an AND:
/// let ct_res = sks.checked_bitand(&ct1, &ct2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg & msg);
/// ```
pub fn checked_bitand(
pub fn checked_bitand<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
let ct_result = self.unchecked_bitand(ct_left, ct_right);
Ok(ct_result)
@@ -115,7 +158,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -133,11 +176,25 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg & msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_left = cks.encrypt_small(msg);
/// let ct_right = cks.encrypt_small(msg);
///
/// // Compute homomorphically an AND:
/// let res = sks.checked_bitand_assign(&mut ct_left, &ct_right);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg & msg);
/// ```
pub fn checked_bitand_assign(
pub fn checked_bitand_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.unchecked_bitand_assign(ct_left, ct_right);
@@ -155,7 +212,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -172,8 +229,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(msg & msg, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_bitand(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_bitand<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_bitand(self, ct_left, ct_right).unwrap()
})
@@ -190,16 +264,17 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let modulus = 4;
/// // Encrypt two messages:
///
/// let msg1 = 15;
/// let msg2 = 3;
///
/// // Encrypt two messages:
/// let mut ct1 = cks.unchecked_encrypt(msg1);
/// let mut ct2 = cks.encrypt(msg2);
///
@@ -210,8 +285,25 @@ impl ServerKey {
/// let res = cks.decrypt(&ct1);
///
/// assert_eq!((msg2 & msg1) % modulus, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let mut ct1 = cks.unchecked_encrypt_small(msg1);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_bitand_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_bitand_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_bitand_assign(self, ct_left, ct_right).unwrap()
})
@@ -225,9 +317,9 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 1;
/// let clear_2 = 2;
@@ -240,8 +332,23 @@ impl ServerKey {
///
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(clear_1 ^ clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(clear_1);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_bitxor(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_bitxor<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_bitxor(self, ct_left, ct_right).unwrap()
})
@@ -255,23 +362,38 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 2;
/// let clear_2 = 0;
///
/// // Encrypt two messages
/// let mut ct_left = cks.encrypt(clear_1);
/// let mut ct_right = cks.encrypt(clear_2);
/// let ct_right = cks.encrypt(clear_2);
///
/// sks.smart_bitxor(&mut ct_left, &mut ct_right);
/// 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_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_left = cks.encrypt_small(clear_1);
/// let ct_right = cks.encrypt_small(clear_2);
///
/// sks.unchecked_bitxor_assign(&mut ct_left, &ct_right);
///
/// let res = cks.decrypt(&ct_left);
/// assert_eq!(clear_1 ^ clear_2, res);
/// ```
pub fn unchecked_bitxor_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_bitxor_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_bitxor_assign(self, ct_left, ct_right)
@@ -288,7 +410,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -307,12 +429,27 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg ^ msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct1 = cks.encrypt_small(msg);
/// let ct2 = cks.encrypt_small(msg);
///
/// // Compute homomorphically a xor:
/// let ct_res = sks.checked_bitxor(&ct1, &ct2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg ^ msg);
/// ```
pub fn checked_bitxor(
pub fn checked_bitxor<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
let ct_result = self.unchecked_bitxor(ct_left, ct_right);
Ok(ct_result)
@@ -330,7 +467,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -348,11 +485,25 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg ^ msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_left = cks.encrypt_small(msg);
/// let ct_right = cks.encrypt_small(msg);
///
/// // Compute homomorphically a xor:
/// let res = sks.checked_bitxor_assign(&mut ct_left, &ct_right);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg ^ msg);
/// ```
pub fn checked_bitxor_assign(
pub fn checked_bitxor_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.unchecked_bitxor_assign(ct_left, ct_right);
@@ -370,7 +521,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -387,8 +538,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(msg ^ msg, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_bitxor(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_bitxor<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_bitxor(self, ct_left, ct_right).unwrap()
})
@@ -405,16 +573,17 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let modulus = 4;
/// // Encrypt two messages:
///
/// let msg1 = 15;
/// let msg2 = 3;
///
/// // Encrypt two messages:
/// let mut ct1 = cks.unchecked_encrypt(msg1);
/// let mut ct2 = cks.encrypt(msg2);
///
@@ -425,8 +594,25 @@ impl ServerKey {
/// let res = cks.decrypt(&ct1);
///
/// assert_eq!((msg2 ^ msg1) % modulus, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let mut ct1 = cks.unchecked_encrypt_small(msg1);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_bitxor_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_bitxor_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_bitxor_assign(self, ct_left, ct_right).unwrap()
})
@@ -440,10 +626,10 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_left = 1;
/// let clear_right = 2;
@@ -456,8 +642,23 @@ impl ServerKey {
///
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(clear_left | clear_right, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(clear_left);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_bitor(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_bitor<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_bitor(self, ct_left, ct_right).unwrap()
})
@@ -471,10 +672,10 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_left = 2;
/// let clear_right = 1;
@@ -487,8 +688,23 @@ impl ServerKey {
///
/// let res = cks.decrypt(&ct_left);
/// assert_eq!(clear_left | clear_right, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_left = cks.encrypt_small(clear_left);
/// let ct_right = cks.encrypt_small(clear_right);
///
/// sks.unchecked_bitor_assign(&mut ct_left, &ct_right);
///
/// let res = cks.decrypt(&ct_left);
/// assert_eq!(clear_left | clear_right, res);
/// ```
pub fn unchecked_bitor_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_bitor_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_bitor_assign(self, ct_left, ct_right)
@@ -505,7 +721,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -524,12 +740,27 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg | msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct1 = cks.encrypt_small(msg);
/// let ct2 = cks.encrypt_small(msg);
///
/// // Compute homomorphically a or:
/// let ct_res = sks.checked_bitor(&ct1, &ct2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, msg | msg);
/// ```
pub fn checked_bitor(
pub fn checked_bitor<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
let ct_result = self.unchecked_bitor(ct_left, ct_right);
Ok(ct_result)
@@ -547,7 +778,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -565,11 +796,25 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg | msg);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_left = cks.encrypt_small(msg);
/// let ct_right = cks.encrypt_small(msg);
///
/// // Compute homomorphically an or:
/// let res = sks.checked_bitor_assign(&mut ct_left, &ct_right);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct_left);
/// assert_eq!(clear_res, msg | msg);
/// ```
pub fn checked_bitor_assign(
pub fn checked_bitor_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
self.unchecked_bitor_assign(ct_left, ct_right);
@@ -587,7 +832,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -604,8 +849,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(msg | msg, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_bitor(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_bitor<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_bitor(self, ct_left, ct_right).unwrap()
})
@@ -622,16 +884,17 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let modulus = 4;
/// // Encrypt two messages:
///
/// let msg1 = 15;
/// let msg2 = 3;
///
/// // Encrypt two messages:
/// let mut ct1 = cks.unchecked_encrypt(msg1);
/// let mut ct2 = cks.encrypt(msg2);
///
@@ -642,8 +905,26 @@ impl ServerKey {
/// let res = cks.decrypt(&ct1);
///
/// assert_eq!((msg2 | msg1) % modulus, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.unchecked_encrypt_small(msg1);
/// let mut ct2 = cks.encrypt_small(msg2);
///
/// // Compute homomorphically an OR:
/// sks.smart_bitor_assign(&mut ct1, &mut ct2);
///
/// // Decrypt:
/// let res = cks.decrypt(&ct1);
///
/// assert_eq!((msg2 | msg1) % modulus, res);
/// ```
pub fn smart_bitor_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_bitor_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_bitor_assign(self, ct_left, ct_right).unwrap()
})

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
// # Note:
// _assign comparison operation are not made public (if they exists) as we don't think there are
@@ -17,7 +17,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -33,8 +33,24 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg_1 > msg_2) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_greater(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_greater<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_greater(self, ct_left, ct_right).unwrap()
})
@@ -49,7 +65,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -67,12 +83,26 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 > msg_2) as u64, clear_res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let res = sks.checked_greater(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 > msg_2) as u64, clear_res);
/// ```
pub fn checked_greater(
pub fn checked_greater<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
Ok(self.unchecked_greater(ct_left, ct_right))
} else {
@@ -88,7 +118,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -105,8 +135,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg > msg) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_greater(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_greater<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_greater(self, ct_left, ct_right).unwrap()
})
@@ -118,7 +165,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -134,12 +181,24 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg_1 >= msg_2) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_greater_or_equal(
pub fn unchecked_greater_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_greater_or_equal(self, ct_left, ct_right)
@@ -155,7 +214,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -172,12 +231,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg >= msg) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_greater_or_equal(
pub fn smart_greater_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_greater_or_equal(self, ct_left, ct_right)
@@ -194,7 +266,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -205,7 +277,21 @@ impl ServerKey {
/// let ct_left = cks.encrypt(msg_1);
/// let ct_right = cks.encrypt(msg_2);
///
/// let res = sks.checked_greater(&ct_left, &ct_right);
/// let res = sks.checked_greater_or_equal(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 >= msg_2) as u64, clear_res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let res = sks.checked_greater_or_equal(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
@@ -213,11 +299,11 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 >= msg_2) as u64, clear_res);
/// ```
pub fn checked_greater_or_equal(
pub fn checked_greater_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
Ok(self.unchecked_greater_or_equal(ct_left, ct_right))
} else {
@@ -231,7 +317,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -248,8 +334,25 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg_1 < msg_2) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_less(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_less<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_less(self, ct_left, ct_right).unwrap()
})
@@ -264,7 +367,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -282,12 +385,26 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 < msg_2) as u64, clear_res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let res = sks.checked_less(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 < msg_2) as u64, clear_res);
/// ```
pub fn checked_less(
pub fn checked_less<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
Ok(self.unchecked_less(ct_left, ct_right))
} else {
@@ -303,7 +420,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -320,8 +437,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg < msg) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_less(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_less<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_less(self, ct_left, ct_right).unwrap()
})
@@ -333,7 +467,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -349,12 +483,24 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg_1 <= msg_2) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(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);
/// ```
pub fn unchecked_less_or_equal(
pub fn unchecked_less_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Ciphertext {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_less_or_equal(self, ct_left, ct_right)
@@ -371,7 +517,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -389,12 +535,26 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 <= msg_2) as u64, clear_res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let res = sks.checked_less_or_equal(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 <= msg_2) as u64, clear_res);
/// ```
pub fn checked_less_or_equal(
pub fn checked_less_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
Ok(self.unchecked_less(ct_left, ct_right))
} else {
@@ -410,7 +570,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -427,12 +587,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg <= msg) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_less_or_equal(
pub fn smart_less_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_less_or_equal(self, ct_left, ct_right).unwrap()
})
@@ -444,7 +617,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -460,8 +633,24 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, 1);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let ct_res = sks.unchecked_equal(&ct_left, &ct_right);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, 1);
/// ```
pub fn unchecked_equal(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_equal(self, ct_left, ct_right).unwrap()
})
@@ -476,7 +665,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -494,12 +683,26 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 == msg_2) as u64, clear_res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let res = sks.checked_equal(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 == msg_2) as u64, clear_res);
/// ```
pub fn checked_equal(
pub fn checked_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
Ok(self.unchecked_equal(ct_left, ct_right))
} else {
@@ -515,7 +718,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -532,8 +735,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg == msg) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_equal(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_equal(self, ct_left, ct_right).unwrap()
})
@@ -545,7 +765,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -561,8 +781,24 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, 1);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let ct_res = sks.unchecked_not_equal(&ct_left, &ct_right);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, 1);
/// ```
pub fn unchecked_not_equal(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_not_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_not_equal(self, ct_left, ct_right).unwrap()
})
@@ -577,7 +813,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
@@ -595,12 +831,26 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 != msg_2) as u64, clear_res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_left = cks.encrypt_small(msg_1);
/// let ct_right = cks.encrypt_small(msg_2);
///
/// let res = sks.checked_not_equal(&ct_left, &ct_right);
///
/// assert!(res.is_ok());
/// let res = res.unwrap();
///
/// let clear_res = cks.decrypt(&res);
/// assert_eq!((msg_1 != msg_2) as u64, clear_res);
/// ```
pub fn checked_not_equal(
pub fn checked_not_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_functional_bivariate_pbs_possible(ct_left, ct_right) {
Ok(self.unchecked_not_equal(ct_left, ct_right))
} else {
@@ -616,7 +866,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -633,12 +883,25 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((msg != msg) as u64, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct1 = cks.encrypt_small(msg);
/// let mut ct2 = cks.encrypt_small(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);
/// ```
pub fn smart_not_equal(
pub fn smart_not_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_not_equal(self, ct_left, ct_right).unwrap()
})
@@ -650,14 +913,14 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg_1 = 2;
/// let scalar = 2;
///
/// // Encrypt two messages
/// // Encrypt our message
/// let ct_left = cks.encrypt(msg_1);
///
/// let ct_res = sks.smart_scalar_equal(&ct_left, scalar);
@@ -665,8 +928,23 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 == scalar as u64) as u64);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt our message
/// let ct_left = cks.encrypt_small(msg_1);
///
/// let ct_res = sks.smart_scalar_equal(&ct_left, scalar);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 == scalar as u64) as u64);
/// ```
pub fn smart_scalar_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_equal(self, ct_left, scalar).unwrap()
})
@@ -678,14 +956,14 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg_1 = 2;
/// let scalar = 2;
///
/// // Encrypt two messages
/// // Encrypt our message
/// let ct_left = cks.encrypt(msg_1);
///
/// let ct_res = sks.smart_scalar_not_equal(&ct_left, scalar);
@@ -693,8 +971,23 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 != scalar as u64) as u64);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt our message
/// let ct_left = cks.encrypt_small(msg_1);
///
/// let ct_res = sks.smart_scalar_not_equal(&ct_left, scalar);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 != scalar as u64) as u64);
/// ```
pub fn smart_scalar_not_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_not_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_scalar_not_equal(self, ct_left, scalar)
@@ -709,14 +1002,14 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg_1 = 2;
/// let scalar = 2;
///
/// // Encrypt two messages
/// // Encrypt our message
/// let ct_left = cks.encrypt(msg_1);
///
/// let ct_res = sks.smart_scalar_greater_or_equal(&ct_left, scalar);
@@ -724,8 +1017,23 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 >= scalar as u64) as u64);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt our message
/// let ct_left = cks.encrypt_small(msg_1);
///
/// let ct_res = sks.smart_scalar_greater_or_equal(&ct_left, scalar);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 >= scalar as u64) as u64);
/// ```
pub fn smart_scalar_greater_or_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_greater_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_scalar_greater_or_equal(self, ct_left, scalar)
@@ -740,14 +1048,14 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg_1 = 2;
/// let scalar = 2;
///
/// // Encrypt two messages
/// // Encrypt our message
/// let ct_left = cks.encrypt(msg_1);
///
/// let ct_res = sks.smart_scalar_less_or_equal(&ct_left, scalar);
@@ -755,8 +1063,23 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 <= scalar as u64) as u64);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt our message
/// let ct_left = cks.encrypt_small(msg_1);
///
/// let ct_res = sks.smart_scalar_less_or_equal(&ct_left, scalar);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 <= scalar as u64) as u64);
/// ```
pub fn smart_scalar_less_or_equal(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_less_or_equal<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_scalar_less_or_equal(self, ct_left, scalar)
@@ -770,14 +1093,14 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg_1 = 2;
/// let scalar = 2;
///
/// // Encrypt two messages
/// // Encrypt our message
/// let ct_left = cks.encrypt(msg_1);
///
/// let ct_res = sks.smart_scalar_greater(&ct_left, scalar);
@@ -785,8 +1108,23 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 > scalar as u64) as u64);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt our message
/// let ct_left = cks.encrypt_small(msg_1);
///
/// let ct_res = sks.smart_scalar_greater(&ct_left, scalar);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 > scalar as u64) as u64);
/// ```
pub fn smart_scalar_greater(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_greater<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_greater(self, ct_left, scalar).unwrap()
})
@@ -798,14 +1136,14 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg_1 = 2;
/// let scalar = 2;
///
/// // Encrypt two messages
/// // Encrypt our message
/// let ct_left = cks.encrypt(msg_1);
///
/// let ct_res = sks.smart_scalar_less(&ct_left, scalar);
@@ -813,8 +1151,23 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 < scalar as u64) as u64);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt our message
/// let ct_left = cks.encrypt_small(msg_1);
///
/// let ct_res = sks.smart_scalar_less(&ct_left, scalar);
///
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (msg_1 < scalar as u64) as u64);
/// ```
pub fn smart_scalar_less(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_less<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_less(self, ct_left, scalar).unwrap()
})

View File

@@ -1,6 +1,6 @@
use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute a division between two ciphertexts without checks.
@@ -15,7 +15,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -33,8 +33,25 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(clear_1 / clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_1 = cks.encrypt_small(clear_1);
/// let ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_div(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_div<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_div(self, ct_left, ct_right).unwrap()
})
@@ -52,7 +69,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -70,8 +87,25 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_1);
/// assert_eq!(clear_1 / clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_1 = cks.encrypt_small(clear_1);
/// let ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_div_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_div_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_div_assign(self, ct_left, ct_right)
@@ -91,7 +125,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -109,8 +143,25 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(clear_1 / clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_1 = cks.encrypt_small(clear_1);
/// let mut ct_2 = cks.encrypt_small(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);
/// ```
pub fn smart_div(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_div<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_div(self, ct_left, ct_right).unwrap()
})
@@ -128,7 +179,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -146,8 +197,25 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_1);
/// assert_eq!(clear_1 / clear_2, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_1 = cks.encrypt_small(clear_1);
/// let mut ct_2 = cks.encrypt_small(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);
/// ```
pub fn smart_div_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_div_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_div_assign(self, ct_left, ct_right).unwrap()
})
@@ -163,7 +231,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -180,14 +248,34 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(clear_1 / (clear_2 as u64), res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt one message
/// let mut ct_1 = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_div(&self, ct_left: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn unchecked_scalar_div<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_div(self, ct_left, scalar).unwrap()
})
}
pub fn unchecked_scalar_div_assign(&self, ct_left: &mut Ciphertext, scalar: u8) {
pub fn unchecked_scalar_div_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_scalar_div_assign(self, ct_left, scalar)
@@ -205,7 +293,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -221,14 +309,34 @@ impl ServerKey {
/// // Decrypt:
/// let dec = cks.decrypt(&ct_res);
/// assert_eq!(1, dec);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_mod(&self, ct_left: &Ciphertext, modulus: u8) -> Ciphertext {
pub fn unchecked_scalar_mod<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
modulus: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_mod(self, ct_left, modulus).unwrap()
})
}
pub fn unchecked_scalar_mod_assign(&self, ct_left: &mut Ciphertext, modulus: u8) {
pub fn unchecked_scalar_mod_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
modulus: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_scalar_mod_assign(self, ct_left, modulus)

View File

@@ -21,12 +21,14 @@ pub use compressed::CompressedServerKey;
mod tests;
use crate::core_crypto::algorithms::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::core_crypto::fft_impl::crypto::bootstrap::FourierLweBootstrapKeyOwned;
use crate::shortint::ciphertext::{Ciphertext, Degree};
use crate::shortint::ciphertext::{CiphertextBase, CiphertextBig, CiphertextSmall, Degree};
use crate::shortint::client_key::ClientKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::parameters::{CarryModulus, MessageModulus};
use crate::shortint::PBSOrderMarker;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display, Formatter};
@@ -71,31 +73,46 @@ pub struct ServerKey {
/// Returns whether it is possible to pack lhs and rhs into a unique
/// ciphertext without exceeding the max storable value using the formula:
/// `unique_ciphertext = (lhs * factor) + rhs`
fn ciphertexts_can_be_packed_without_exceeding_space(
lhs: &Ciphertext,
rhs: &Ciphertext,
fn ciphertexts_can_be_packed_without_exceeding_space<OpOrder: PBSOrderMarker>(
lhs: &CiphertextBase<OpOrder>,
rhs: &CiphertextBase<OpOrder>,
factor: usize,
) -> bool {
let final_degree = (lhs.degree.0 * factor) + rhs.degree.0;
final_degree < lhs.carry_modulus.0 * lhs.message_modulus.0
}
pub struct Accumulator {
pub acc: GlweCiphertextOwned<u64>,
#[derive(Clone, Debug, PartialEq)]
#[must_use]
pub struct LookupTable<C: Container<Element = u64>> {
pub acc: GlweCiphertext<C>,
pub degree: Degree,
}
pub struct BivariateAccumulator {
pub type LookupTableOwned = LookupTable<Vec<u64>>;
pub type LookupTableMutView<'a> = LookupTable<&'a mut [u64]>;
pub type LookupTableView<'a> = LookupTable<&'a [u64]>;
#[must_use]
pub struct BivariateLookupTable<C: Container<Element = u64>> {
// A bivariate accumulator is an univariate accumulator
// where the message space is shared to encode
// 2 values
pub acc: Accumulator,
pub acc: LookupTable<C>,
// By how much we shift the lhs in the LUT
pub ct_right_modulus: MessageModulus,
}
impl BivariateAccumulator {
pub fn is_bivariate_pbs_possible(&self, lhs: &Ciphertext, rhs: &Ciphertext) -> bool {
pub type BivariateLookupTableOwned = BivariateLookupTable<Vec<u64>>;
pub type BivariateLookupTableMutView<'a> = BivariateLookupTable<&'a mut [u64]>;
pub type BivariateLookupTableView<'a> = BivariateLookupTable<&'a [u64]>;
impl<C: Container<Element = u64>> BivariateLookupTable<C> {
pub fn is_bivariate_pbs_possible<OpOrder: PBSOrderMarker>(
&self,
lhs: &CiphertextBase<OpOrder>,
rhs: &CiphertextBase<OpOrder>,
) -> bool {
ciphertexts_can_be_packed_without_exceeding_space(lhs, rhs, self.ct_right_modulus.0)
}
}
@@ -106,7 +123,7 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// use tfhe::shortint::{gen_keys, ServerKey};
///
/// // Generate the client key and the server key:
@@ -134,7 +151,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -147,13 +164,13 @@ impl ServerKey {
/// let f = |x| x ^ 2 % 4;
///
/// let acc = sks.generate_accumulator(f);
/// let ct_res = sks.keyswitch_programmable_bootstrap(&ct, &acc);
/// let ct_res = sks.apply_lookup_table(&ct, &acc);
///
/// let dec = cks.decrypt(&ct_res);
/// // 3^2 mod 4 = 1
/// assert_eq!(dec, f(msg));
/// ```
pub fn generate_accumulator<F>(&self, f: F) -> Accumulator
pub fn generate_accumulator<F>(&self, f: F) -> LookupTableOwned
where
F: Fn(u64) -> u64,
{
@@ -166,7 +183,7 @@ impl ServerKey {
&self,
f: F,
left_message_scaling: MessageModulus,
) -> BivariateAccumulator
) -> BivariateLookupTableOwned
where
F: Fn(u64, u64) -> u64,
{
@@ -183,7 +200,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -192,18 +209,18 @@ impl ServerKey {
/// let msg_2 = 2;
///
/// let ct1 = cks.encrypt(msg_1);
/// let ct2 = cks.encrypt(msg_2);
/// let mut ct2 = cks.encrypt(msg_2);
///
/// let f = |x, y| (x + y) % 4;
///
/// let acc = sks.generate_accumulator_bivariate(f);
/// assert!(acc.is_bivariate_pbs_possible(&ct1, &ct2));
/// let ct_res = sks.keyswitch_programmable_bootstrap_bivariate(&ct1, &ct2, &acc);
/// let ct_res = sks.smart_apply_lookup_table_bivariate(&ct1, &mut ct2, &acc);
///
/// let dec = cks.decrypt(&ct_res);
/// assert_eq!(dec, f(msg_1, msg_2));
/// ```
pub fn generate_accumulator_bivariate<F>(&self, f: F) -> BivariateAccumulator
pub fn generate_accumulator_bivariate<F>(&self, f: F) -> BivariateLookupTableOwned
where
F: Fn(u64, u64) -> u64,
{
@@ -219,7 +236,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -246,7 +263,41 @@ impl ServerKey {
/// let carry = cks.decrypt(&ct_carry);
/// assert_eq!(carry, 1);
///
/// let ct_res = sks.keyswitch_bootstrap(&ct_res);
/// let ct_res = sks.clear_carry(&ct_res);
///
/// let ct_carry = sks.carry_extract(&ct_res);
/// let carry = cks.decrypt(&ct_carry);
/// assert_eq!(carry, 0);
///
/// let clear = cks.decrypt(&ct_res);
///
/// assert_eq!(clear, (3 + 2) % 4);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let mut ct1 = cks.encrypt_small(3);
/// // | ct1 |
/// // | carry | message |
/// // |-------|---------|
/// // | 0 0 | 1 1 |
/// let mut ct2 = cks.encrypt_small(2);
/// // | ct2 |
/// // | carry | message |
/// // |-------|---------|
/// // | 0 0 | 1 0 |
///
/// let ct_res = sks.smart_add(&mut ct1, &mut ct2);
/// // | ct_res |
/// // | carry | message |
/// // |-------|---------|
/// // | 0 1 | 0 1 |
///
/// // Get the carry
/// let ct_carry = sks.carry_extract(&ct_res);
/// let carry = cks.decrypt(&ct_carry);
/// assert_eq!(carry, 1);
///
/// let ct_res = sks.clear_carry(&ct_res);
///
/// let ct_carry = sks.carry_extract(&ct_res);
/// let carry = cks.decrypt(&ct_carry);
@@ -256,15 +307,16 @@ impl ServerKey {
///
/// assert_eq!(clear, (3 + 2) % 4);
/// ```
pub fn keyswitch_bootstrap(&self, ct_in: &Ciphertext) -> Ciphertext {
ShortintEngine::with_thread_local_mut(|engine| {
engine.keyswitch_bootstrap(self, ct_in).unwrap()
})
pub fn clear_carry<OpOrder: PBSOrderMarker>(
&self,
ct_in: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.clear_carry(self, ct_in).unwrap())
}
pub fn keyswitch_bootstrap_assign(&self, ct_in: &mut Ciphertext) {
pub fn clear_carry_assign<OpOrder: PBSOrderMarker>(&self, ct_in: &mut CiphertextBase<OpOrder>) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.keyswitch_bootstrap_assign(self, ct_in).unwrap()
engine.clear_carry_assign(self, ct_in).unwrap()
})
}
@@ -274,7 +326,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -286,34 +338,34 @@ impl ServerKey {
///
/// // Generate the accumulator for the function f: x -> x^3 mod 2^2
/// let acc = sks.generate_accumulator_bivariate(|x, y| x * y * x % modulus);
/// let ct_res = sks.keyswitch_programmable_bootstrap_bivariate(&ct1, &ct2, &acc);
/// let ct_res = sks.unchecked_apply_lookup_table_bivariate(&ct1, &ct2, &acc);
///
/// let dec = cks.decrypt(&ct_res);
/// // 3^3 mod 4 = 3
/// assert_eq!(dec, (msg * msg * msg) % modulus);
/// ```
pub fn keyswitch_programmable_bootstrap_bivariate(
pub fn unchecked_apply_lookup_table_bivariate<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
acc: &BivariateAccumulator,
) -> Ciphertext {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.keyswitch_programmable_bootstrap_bivariate(self, ct_left, ct_right, acc)
.unchecked_apply_lookup_table_bivariate(self, ct_left, ct_right, acc)
.unwrap()
})
}
pub fn keyswitch_programmable_bootstrap_bivariate_assign(
pub fn unchecked_apply_lookup_table_bivariate_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
acc: &BivariateAccumulator,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.keyswitch_programmable_bootstrap_bivariate_assign(self, ct_left, ct_right, acc)
.unchecked_apply_lookup_table_bivariate_assign(self, ct_left, ct_right, acc)
.unwrap()
})
}
@@ -324,7 +376,57 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg: u64 = 3;
/// let ct1 = cks.encrypt(msg);
/// let mut ct2 = cks.encrypt(msg);
/// let modulus = cks.parameters.message_modulus.0 as u64;
///
/// // Generate the accumulator for the function f: x -> x^3 mod 2^2
/// let acc = sks.generate_accumulator_bivariate(|x, y| x * y * x % modulus);
/// let ct_res = sks.smart_apply_lookup_table_bivariate(&ct1, &mut ct2, &acc);
///
/// let dec = cks.decrypt(&ct_res);
/// // 3^3 mod 4 = 3
/// assert_eq!(dec, (msg * msg * msg) % modulus);
/// ```
pub fn smart_apply_lookup_table_bivariate<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_apply_lookup_table_bivariate(self, ct_left, ct_right, acc)
.unwrap()
})
}
pub fn smart_apply_lookup_table_bivariate_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
acc: &BivariateLookupTableOwned,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_apply_lookup_table_bivariate_assign(self, ct_left, ct_right, acc)
.unwrap()
})
}
/// Compute a keyswitch and programmable bootstrap.
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -335,102 +437,102 @@ impl ServerKey {
///
/// // Generate the accumulator for the function f: x -> x^3 mod 2^2
/// let acc = sks.generate_accumulator(|x| x * x * x % modulus);
/// let ct_res = sks.keyswitch_programmable_bootstrap(&ct, &acc);
/// let ct_res = sks.apply_lookup_table(&ct, &acc);
///
/// let dec = cks.decrypt(&ct_res);
/// // 3^3 mod 4 = 3
/// assert_eq!(dec, (msg * msg * msg) % modulus);
/// ```
pub fn keyswitch_programmable_bootstrap(
pub fn apply_lookup_table<OpOrder: PBSOrderMarker>(
&self,
ct_in: &Ciphertext,
acc: &Accumulator,
) -> Ciphertext {
ct_in: &CiphertextBase<OpOrder>,
acc: &LookupTableOwned,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.keyswitch_programmable_bootstrap(self, ct_in, acc)
.unwrap()
engine.apply_lookup_table(self, ct_in, acc).unwrap()
})
}
pub fn keyswitch_programmable_bootstrap_assign(
pub fn apply_lookup_table_assign<OpOrder: PBSOrderMarker>(
&self,
ct_in: &mut Ciphertext,
acc: &Accumulator,
ct_in: &mut CiphertextBase<OpOrder>,
acc: &LookupTableOwned,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.keyswitch_programmable_bootstrap_assign(self, ct_in, acc)
.unwrap()
engine.apply_lookup_table_assign(self, ct_in, acc).unwrap()
})
}
/// Generic programmable bootstrap where messages are concatenated
/// into one ciphertext to compute bivariate functions.
/// This is used to apply many binary operations (comparisons, multiplications, division).
pub fn unchecked_functional_bivariate_pbs<F>(
/// Generic programmable bootstrap where messages are concatenated into one ciphertext to
/// evaluate a bivariate function. This is used to apply many binary operations (comparisons,
/// multiplications, division).
pub fn unchecked_evaluate_bivariate_function<F, OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
f: F,
) -> Ciphertext
) -> CiphertextBase<OpOrder>
where
F: Fn(u64, u64) -> u64,
{
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_functional_bivariate_pbs(self, ct_left, ct_right, f)
.unchecked_evaluate_bivariate_function(self, ct_left, ct_right, f)
.unwrap()
})
}
pub fn unchecked_functional_bivariate_pbs_assign<F>(
pub fn unchecked_evaluate_bivariate_function_assign<F, OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
f: F,
) where
F: Fn(u64, u64) -> u64,
{
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_functional_bivariate_pbs_assign(self, ct_left, ct_right, f)
.unchecked_evaluate_bivariate_function_assign(self, ct_left, ct_right, f)
.unwrap()
})
}
/// Verify if a functional bivariate pbs can be applied on ct_left and ct_right.
pub fn is_functional_bivariate_pbs_possible(&self, ct1: &Ciphertext, ct2: &Ciphertext) -> bool {
pub fn is_functional_bivariate_pbs_possible<OpOrder: PBSOrderMarker>(
&self,
ct1: &CiphertextBase<OpOrder>,
ct2: &CiphertextBase<OpOrder>,
) -> bool {
ciphertexts_can_be_packed_without_exceeding_space(ct1, ct2, ct2.degree.0 + 1)
}
pub fn smart_functional_bivariate_pbs_assign<F>(
pub fn smart_evaluate_bivariate_function_assign<F, OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
f: F,
) where
F: Fn(u64, u64) -> u64,
{
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_functional_bivariate_pbs_assign(self, ct_left, ct_right, f)
.smart_evaluate_bivariate_function_assign(self, ct_left, ct_right, f)
.unwrap()
})
}
pub fn smart_functional_bivariate_pbs<F>(
pub fn smart_evaluate_bivariate_function<F, OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
f: F,
) -> Ciphertext
) -> CiphertextBase<OpOrder>
where
F: Fn(u64, u64) -> u64,
{
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_functional_bivariate_pbs(self, ct_left, ct_right, f)
.smart_evaluate_bivariate_function(self, ct_left, ct_right, f)
.unwrap()
})
}
@@ -440,7 +542,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -467,7 +569,7 @@ impl ServerKey {
/// let res = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(2, res);
/// ```
pub fn carry_extract_assign(&self, ct: &mut Ciphertext) {
pub fn carry_extract_assign<OpOrder: PBSOrderMarker>(&self, ct: &mut CiphertextBase<OpOrder>) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.carry_extract_assign(self, ct).unwrap()
})
@@ -479,7 +581,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -506,7 +608,10 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(2, res);
/// ```
pub fn carry_extract(&self, ct: &Ciphertext) -> Ciphertext {
pub fn carry_extract<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.carry_extract(self, ct).unwrap())
}
@@ -516,7 +621,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -542,8 +647,33 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct);
/// assert_eq!(1, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.unchecked_encrypt_small(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);
/// ```
pub fn message_extract_assign(&self, ct: &mut Ciphertext) {
pub fn message_extract_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.message_extract_assign(self, ct).unwrap()
})
@@ -555,7 +685,7 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -581,18 +711,42 @@ impl ServerKey {
/// // Decrypt:
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(1, res);
///
/// // Encrypt a message
/// let ct = cks.unchecked_encrypt_small(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);
/// ```
pub fn message_extract(&self, ct: &Ciphertext) -> Ciphertext {
pub fn message_extract<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.message_extract(self, ct).unwrap())
}
/// Compute a trivial shortint from a given value.
/// Compute a trivial shortint ciphertext with the dimension of the big LWE secret key from a
/// given value.
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -605,11 +759,39 @@ impl ServerKey {
/// let ct_res = cks.decrypt(&ct1);
/// assert_eq!(1, ct_res);
/// ```
pub fn create_trivial(&self, value: u64) -> Ciphertext {
pub fn create_trivial(&self, value: u64) -> CiphertextBig {
ShortintEngine::with_thread_local_mut(|engine| engine.create_trivial(self, value).unwrap())
}
pub fn create_trivial_assign(&self, ct: &mut Ciphertext, value: u64) {
/// Compute a trivial shortint ciphertext with the dimension of the small LWE secret key from a
/// given value.
///
/// # Example
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// let msg = 1;
///
/// // Trivial encryption
/// let ct1 = sks.create_trivial_small(msg);
///
/// let ct_res = cks.decrypt(&ct1);
/// assert_eq!(1, ct_res);
/// ```
pub fn create_trivial_small(&self, value: u64) -> CiphertextSmall {
ShortintEngine::with_thread_local_mut(|engine| engine.create_trivial(self, value).unwrap())
}
pub fn create_trivial_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
value: u64,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.create_trivial_assign(self, ct, value).unwrap()
})

View File

@@ -3,7 +3,7 @@ use crate::shortint::ciphertext::Degree;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Multiply two ciphertexts together without checks.
@@ -17,10 +17,10 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_1_CARRY_1;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 1;
/// let clear_2 = 1;
@@ -42,8 +42,32 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_res);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!((clear_1 * clear_2) % modulus, res);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let ct_1 = cks.encrypt_small(clear_1);
/// let ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_mul_lsb(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_mul_lsb<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_mul_lsb(self, ct_left, ct_right).unwrap()
})
@@ -60,10 +84,10 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (mut cks, mut sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 3;
/// let clear_2 = 2;
@@ -79,8 +103,26 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_1);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!((clear_1 * clear_2) % modulus, res);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_1 = cks.encrypt_small(clear_1);
/// let ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_mul_lsb_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_mul_lsb_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_mul_lsb_assign(self, ct_left, ct_right)
@@ -99,10 +141,10 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::DEFAULT_PARAMETERS;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key
/// let (mut cks, mut sks) = gen_keys(DEFAULT_PARAMETERS);
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 3;
/// let clear_2 = 2;
@@ -125,14 +167,43 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_res);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!((clear_1 * clear_2) / modulus, res);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_1 = cks.encrypt_small(clear_1);
/// let mut ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_mul_msb(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_mul_msb<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_mul_msb(self, ct_left, ct_right).unwrap()
})
}
pub fn unchecked_mul_msb_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_mul_msb_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_mul_msb_assign(self, ct_left, ct_right)
@@ -145,10 +216,11 @@ impl ServerKey {
/// # Example
///
///```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(Parameters::default());
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
@@ -160,8 +232,23 @@ impl ServerKey {
/// let res = sks.is_mul_possible(&ct_1, &ct_2);
///
/// assert_eq!(true, res);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_1 = cks.encrypt_small(msg);
/// let ct_2 = cks.encrypt_small(msg);
///
/// // Check if we can perform a multiplication
/// let res = sks.is_mul_possible(&ct_1, &ct_2);
///
/// assert_eq!(true, res);
/// ```
pub fn is_mul_possible(&self, ct1: &Ciphertext, ct2: &Ciphertext) -> bool {
pub fn is_mul_possible<OpOrder: PBSOrderMarker>(
&self,
ct1: &CiphertextBase<OpOrder>,
ct2: &CiphertextBase<OpOrder>,
) -> bool {
self.is_functional_bivariate_pbs_possible(ct1, ct2)
}
@@ -176,10 +263,11 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(Parameters::default());
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_1 = cks.encrypt(2);
@@ -194,12 +282,28 @@ impl ServerKey {
/// 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 (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_1 = cks.encrypt_small(2);
/// let ct_2 = cks.encrypt_small(1);
///
/// // Compute homomorphically a multiplication:
/// let ct_res = sks.checked_mul_lsb(&ct_1, &ct_2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.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);
/// ```
pub fn checked_mul_lsb(
pub fn checked_mul_lsb<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_mul_possible(ct_left, ct_right) {
let ct_result = self.unchecked_mul_lsb(ct_left, ct_right);
Ok(ct_result)
@@ -220,10 +324,11 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(Parameters::default());
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_1 = cks.encrypt(2);
@@ -237,11 +342,26 @@ impl ServerKey {
/// 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 (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_1 = cks.encrypt_small(2);
/// let ct_2 = cks.encrypt_small(1);
///
/// // Compute homomorphically a multiplication:
/// let ct_res = sks.checked_mul_lsb_assign(&mut ct_1, &ct_2);
///
/// assert!(ct_res.is_ok());
///
/// 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);
/// ```
pub fn checked_mul_lsb_assign(
pub fn checked_mul_lsb_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
if self.is_mul_possible(ct_left, ct_right) {
self.unchecked_mul_lsb_assign(ct_left, ct_right);
@@ -263,7 +383,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -293,12 +413,37 @@ impl ServerKey {
/// clear_res,
/// (msg_1 * msg_2) / cks.parameters.message_modulus.0 as u64
/// );
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let ct_1 = cks.encrypt_small(msg_1);
/// let ct_2 = cks.encrypt_small(msg_2);
///
/// // Compute homomorphically a multiplication:
/// let ct_res = sks.checked_mul_msb(&ct_1, &ct_2);
/// assert!(ct_res.is_ok());
///
/// // 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 ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(
/// clear_res,
/// (msg_1 * msg_2) / cks.parameters.message_modulus.0 as u64
/// );
/// ```
pub fn checked_mul_msb(
pub fn checked_mul_msb<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_mul_possible(ct_left, ct_right) {
let ct_result = self.unchecked_mul_msb(ct_left, ct_right);
Ok(ct_result)
@@ -319,11 +464,11 @@ impl ServerKey {
/// # Example
///
///```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_1_CARRY_1;
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let clear_1 = 1;
/// let clear_2 = 1;
@@ -338,12 +483,25 @@ impl ServerKey {
/// // Decrypt
/// let res = cks.decrypt(&ct_res);
/// assert_eq!((clear_2 * clear_1), res);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages
/// let mut ct_1 = cks.encrypt_small(clear_1);
/// let mut ct_2 = cks.encrypt_small(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);
/// ```
pub fn unchecked_mul_lsb_small_carry(
pub fn unchecked_mul_lsb_small_carry<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Ciphertext {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_mul_lsb_small_carry_modulus(self, ct_left, ct_right)
@@ -351,10 +509,10 @@ impl ServerKey {
})
}
pub fn unchecked_mul_lsb_small_carry_assign(
pub fn unchecked_mul_lsb_small_carry_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
@@ -394,8 +552,30 @@ impl ServerKey {
/// res = sks.is_mul_small_carry_possible(&ct_1, &ct_3);
///
/// assert_eq!(false, res);
///
/// // Encrypt two messages:
/// let ct_1 = cks.encrypt(msg);
/// let ct_2 = cks.encrypt(msg);
///
/// // Check if we can perform a multiplication
/// let mut res = sks.is_mul_small_carry_possible(&ct_1, &ct_2);
///
/// assert_eq!(true, res);
///
/// //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
/// res = sks.is_mul_small_carry_possible(&ct_1, &ct_3);
///
/// assert_eq!(false, res);
/// ```
pub fn is_mul_small_carry_possible(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> bool {
pub fn is_mul_small_carry_possible<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> bool {
// Check if an addition is possible
let b1 = self.is_add_possible(ct_left, ct_right);
let b2 = self.is_sub_possible(ct_left, ct_right);
@@ -412,8 +592,8 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -434,12 +614,28 @@ impl ServerKey {
/// 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 (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_1 = cks.encrypt_small(msg_1);
/// let mut ct_2 = cks.encrypt_small(msg_2);
///
/// // Compute homomorphically a multiplication
/// let ct_res = sks.checked_mul_lsb_with_small_carry(&mut ct_1, &mut ct_2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.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);
/// ```
pub fn checked_mul_lsb_with_small_carry(
pub fn checked_mul_lsb_with_small_carry<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_mul_small_carry_possible(ct_left, ct_right) {
let mut ct_result = self.unchecked_mul_lsb_small_carry(ct_left, ct_right);
ct_result.degree = Degree(ct_left.degree.0 * 2);
@@ -465,10 +661,10 @@ impl ServerKey {
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_1);
///
/// // Encrypt two messages:
/// 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);
///
@@ -478,8 +674,23 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_1);
/// let modulus = sks.message_modulus.0 as u64;
/// assert_eq!(res % modulus, (msg1 * msg2) % modulus);
///
/// // Encrypt two messages:
/// let mut ct_1 = cks.unchecked_encrypt_small(msg1);
/// let mut ct_2 = cks.unchecked_encrypt_small(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);
/// ```
pub fn smart_mul_lsb_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_mul_lsb_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_mul_lsb_assign(self, ct_left, ct_right)
@@ -487,7 +698,11 @@ impl ServerKey {
})
}
pub fn smart_mul_msb_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_mul_msb_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_mul_msb_assign(self, ct_left, ct_right)
@@ -503,15 +718,16 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let msg1 = 12;
/// let msg2 = 13;
///
/// // Encrypt two messages:
/// let mut ct_left = cks.unchecked_encrypt(msg1);
/// // | ct_left |
/// // | carry | message |
@@ -533,8 +749,37 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_res);
/// let modulus = sks.message_modulus.0;
/// assert_eq!(res, (msg1 * msg2) % modulus as u64);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_left = cks.unchecked_encrypt_small(msg1);
/// // | ct_left |
/// // | carry | message |
/// // |-------|---------|
/// // | 1 1 | 0 0 |
/// let mut ct_right = cks.unchecked_encrypt_small(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);
/// ```
pub fn smart_mul_lsb(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_mul_lsb<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_mul_lsb(self, ct_left, ct_right).unwrap()
})
@@ -548,15 +793,16 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// 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);
///
@@ -566,8 +812,25 @@ impl ServerKey {
/// let res = cks.decrypt(&ct_res);
/// let modulus = sks.carry_modulus.0;
/// assert_eq!(res, (msg1 * msg2) % modulus as u64);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let mut ct_1 = cks.unchecked_encrypt_small(msg1);
/// let mut ct_2 = cks.unchecked_encrypt_small(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.carry_modulus.0;
/// assert_eq!(res, (msg1 * msg2) % modulus as u64);
/// ```
pub fn smart_mul_msb(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_mul_msb<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_mul_msb(self, ct_left, ct_right).unwrap()
})

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Homomorphically negates a message without checks.
@@ -15,10 +15,11 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (mut cks, mut sks) = gen_keys(Parameters::default());
/// let (mut cks, mut sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 1;
///
@@ -32,12 +33,31 @@ impl ServerKey {
/// let three = cks.decrypt(&ct_res);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(modulus - msg, three);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_neg(&self, ct: &Ciphertext) -> Ciphertext {
pub fn unchecked_neg<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.unchecked_neg(self, ct).unwrap())
}
pub fn unchecked_neg_with_correcting_term(&self, ct: &Ciphertext) -> (Ciphertext, u64) {
pub fn unchecked_neg_with_correcting_term<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> (CiphertextBase<OpOrder>, u64) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_neg_with_correcting_term(self, ct).unwrap()
})
@@ -50,13 +70,15 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 3;
///
/// // Encrypt a message
/// let msg = 3;
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a negation
@@ -65,14 +87,29 @@ impl ServerKey {
/// // Decrypt
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(modulus - msg, cks.decrypt(&ct));
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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));
/// ```
pub fn unchecked_neg_assign(&self, ct: &mut Ciphertext) {
pub fn unchecked_neg_assign<OpOrder: PBSOrderMarker>(&self, ct: &mut CiphertextBase<OpOrder>) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_neg_assign(self, ct).unwrap()
})
}
pub fn unchecked_neg_assign_with_correcting_term(&self, ct: &mut Ciphertext) -> u64 {
pub fn unchecked_neg_assign_with_correcting_term<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_neg_assign_with_correcting_term(self, ct)
@@ -85,21 +122,33 @@ impl ServerKey {
/// # Example
///
///```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let msg = 2;
/// let ct = cks.encrypt(msg);
///
/// // Check if we can perform a negation
/// let can_be_negated = sks.is_neg_possible(&ct);
///
/// assert_eq!(can_be_negated, true);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(msg);
///
/// // Check if we can perform a negation
/// let can_be_negated = sks.is_neg_possible(&ct);
///
/// assert_eq!(can_be_negated, true);
/// ```
pub fn is_neg_possible(&self, ct: &Ciphertext) -> bool {
pub fn is_neg_possible<OpOrder: PBSOrderMarker>(&self, ct: &CiphertextBase<OpOrder>) -> bool {
// z = ceil( degree / 2^p ) x 2^p
let msg_mod = self.message_modulus.0;
let mut z = (ct.degree.0 + msg_mod - 1) / msg_mod;
@@ -119,13 +168,15 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 1;
///
/// // Encrypt a message
/// let msg = 1;
/// let ct = cks.encrypt(msg);
///
/// // Compute homomorphically a negation:
@@ -136,8 +187,25 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&ct_res.unwrap());
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res, modulus - msg);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(msg);
///
/// // Compute homomorphically a negation:
/// let ct_res = sks.checked_neg(&ct);
///
/// assert!(ct_res.is_ok());
///
/// let clear_res = cks.decrypt(&ct_res.unwrap());
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res, modulus - msg);
/// ```
pub fn checked_neg(&self, ct: &Ciphertext) -> Result<Ciphertext, CheckError> {
pub fn checked_neg<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
// If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
if self.is_neg_possible(ct) {
let ct_result = self.unchecked_neg(ct);
@@ -157,13 +225,15 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// let msg = 1;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically the negation:
@@ -174,8 +244,25 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res, modulus - msg);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(msg);
///
/// // Compute homomorphically the negation:
/// let res = sks.checked_neg_assign(&mut ct);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res, modulus - msg);
/// ```
pub fn checked_neg_assign(&self, ct: &mut Ciphertext) -> Result<(), CheckError> {
pub fn checked_neg_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
if self.is_neg_possible(ct) {
self.unchecked_neg_assign(ct);
Ok(())
@@ -192,13 +279,15 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let msg = 3;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a negation
@@ -208,8 +297,24 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&ct_res);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res, modulus - msg);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_neg(&self, ct: &mut Ciphertext) -> Ciphertext {
pub fn smart_neg<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.smart_neg(self, ct).unwrap())
}
@@ -220,13 +325,15 @@ impl ServerKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt two messages:
/// let msg = 3;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a negation
@@ -236,8 +343,21 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&ct);
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res, modulus - msg);
///
/// let (mut cks, mut sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_neg_assign(&self, ct: &mut Ciphertext) {
pub fn smart_neg_assign<OpOrder: PBSOrderMarker>(&self, ct: &mut CiphertextBase<OpOrder>) {
ShortintEngine::with_thread_local_mut(|engine| engine.smart_neg_assign(self, ct).unwrap())
}
}

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute homomorphically an addition between a ciphertext and a scalar.
@@ -15,11 +15,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar addition:
@@ -27,8 +28,23 @@ impl ServerKey {
///
/// let clear = cks.decrypt(&ct_res);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_add(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn unchecked_scalar_add<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_add(ct, scalar).unwrap()
})
@@ -44,11 +60,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar addition:
@@ -56,14 +73,33 @@ impl ServerKey {
///
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(1);
///
/// // Compute homomorphically a scalar addition:
/// sks.unchecked_scalar_add_assign(&mut ct, 2);
///
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
/// ```
pub fn unchecked_scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn unchecked_scalar_add_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_add_assign(ct, scalar).unwrap()
})
}
pub fn unchecked_scalar_add_assign_crt(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn unchecked_scalar_add_assign_crt<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_scalar_add_assign_crt(self, ct, scalar)
@@ -77,19 +113,34 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt(2);
///
/// // Verification if the scalar addition can be computed:
/// let can_be_computed = sks.is_scalar_add_possible(&ct, 3);
///
/// assert_eq!(can_be_computed, true);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(2);
///
/// // Verification if the scalar addition can be computed:
/// let can_be_computed = sks.is_scalar_add_possible(&ct, 3);
///
/// assert_eq!(can_be_computed, true);
/// ```
pub fn is_scalar_add_possible(&self, ct: &Ciphertext, scalar: u8) -> bool {
pub fn is_scalar_add_possible<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> bool {
let final_degree = scalar as usize + ct.degree.0;
final_degree <= self.max_degree.0
@@ -104,12 +155,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// // Encrypt a message
/// let ct = cks.encrypt(1);
///
/// // Compute homomorphically a addition multiplication:
@@ -120,12 +171,26 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, 3);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(1);
///
/// // Compute homomorphically a addition multiplication:
/// let ct_res = sks.checked_scalar_add(&ct, 2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, 3);
/// ```
pub fn checked_scalar_add(
pub fn checked_scalar_add<OpOrder: PBSOrderMarker>(
&self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> Result<Ciphertext, CheckError> {
) -> Result<CiphertextBase<OpOrder>, CheckError> {
//If the ciphertext cannot be multiplied without exceeding the max degree
if self.is_scalar_add_possible(ct, scalar) {
let ct_result = self.unchecked_scalar_add(ct, scalar);
@@ -144,12 +209,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// // Encrypt a message
/// let mut ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar addition:
@@ -159,10 +224,23 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct);
/// assert_eq!(clear_res, 3);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(1);
///
/// // Compute homomorphically a scalar addition:
/// let res = sks.checked_scalar_add_assign(&mut ct, 2);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct);
/// assert_eq!(clear_res, 3);
/// ```
pub fn checked_scalar_add_assign(
pub fn checked_scalar_add_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> Result<(), CheckError> {
if self.is_scalar_add_possible(ct, scalar) {
@@ -184,7 +262,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -192,6 +270,7 @@ impl ServerKey {
/// let msg = 1_u64;
/// let scalar = 9_u8;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a scalar multiplication:
@@ -204,8 +283,28 @@ impl ServerKey {
/// 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_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_add(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_add<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_add(self, ct, scalar).unwrap()
})
@@ -222,7 +321,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -230,6 +329,7 @@ impl ServerKey {
/// let msg = 1_u64;
/// let scalar = 5_u8;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a scalar multiplication:
@@ -238,8 +338,24 @@ impl ServerKey {
/// // Our result is what we expect
/// let clear = cks.decrypt_message_and_carry(&ct);
/// assert_eq!(6, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_add_assign(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn smart_scalar_add_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_add_assign(self, ct, scalar).unwrap()
})

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute homomorphically a multiplication of a ciphertext by a scalar.
@@ -17,11 +17,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar multiplication:
@@ -29,8 +30,23 @@ impl ServerKey {
///
/// let clear = cks.decrypt(&ct_res);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_mul(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn unchecked_scalar_mul<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_mul(ct, scalar).unwrap()
})
@@ -48,11 +64,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar multiplication:
@@ -60,8 +77,23 @@ impl ServerKey {
///
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(1);
///
/// // Compute homomorphically a scalar multiplication:
/// sks.unchecked_scalar_mul_assign(&mut ct, 3);
///
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
/// ```
pub fn unchecked_scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn unchecked_scalar_mul_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_mul_assign(ct, scalar).unwrap()
})
@@ -73,19 +105,34 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt(2);
///
/// // Verification if the scalar multiplication can be computed:
/// let can_be_computed = sks.is_scalar_mul_possible(&ct, 3);
///
/// assert_eq!(can_be_computed, true);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(2);
///
/// // Verification if the scalar multiplication can be computed:
/// let can_be_computed = sks.is_scalar_mul_possible(&ct, 3);
///
/// assert_eq!(can_be_computed, true);
/// ```
pub fn is_scalar_mul_possible(&self, ct: &Ciphertext, scalar: u8) -> bool {
pub fn is_scalar_mul_possible<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> bool {
//scalar * ct.counter
let final_degree = scalar as usize * ct.degree.0;
@@ -104,12 +151,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// // Encrypt a message
/// let ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar multiplication:
@@ -120,12 +167,26 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, 3);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(1);
///
/// // Compute homomorphically a scalar multiplication:
/// let ct_res = sks.checked_scalar_mul(&ct, 3);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, 3);
/// ```
pub fn checked_scalar_mul(
pub fn checked_scalar_mul<OpOrder: PBSOrderMarker>(
&self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> Result<Ciphertext, CheckError> {
) -> Result<CiphertextBase<OpOrder>, CheckError> {
//If the ciphertext cannot be multiplied without exceeding the degree max
if self.is_scalar_mul_possible(ct, scalar) {
let ct_result = self.unchecked_scalar_mul(ct, scalar);
@@ -146,12 +207,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// // Encrypt a message
/// let mut ct = cks.encrypt(1);
///
/// // Compute homomorphically a scalar multiplication:
@@ -161,10 +222,23 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct);
/// assert_eq!(clear_res, 3);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(1);
///
/// // Compute homomorphically a scalar multiplication:
/// let res = sks.checked_scalar_mul_assign(&mut ct, 3);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct);
/// assert_eq!(clear_res, 3);
/// ```
pub fn checked_scalar_mul_assign(
pub fn checked_scalar_mul_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> Result<(), CheckError> {
if self.is_scalar_mul_possible(ct, scalar) {
@@ -184,7 +258,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -192,6 +266,7 @@ impl ServerKey {
/// let msg = 1_u64;
/// let scalar = 3_u8;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a scalar multiplication:
@@ -204,8 +279,28 @@ impl ServerKey {
/// 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_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_mul(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_mul<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_mul(self, ct, scalar).unwrap()
})
@@ -220,7 +315,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -228,6 +323,7 @@ impl ServerKey {
/// let msg = 1_u64;
/// let scalar = 3_u8;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a scalar multiplication:
@@ -236,8 +332,24 @@ impl ServerKey {
/// // Our result is what we expect
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_mul_assign(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn smart_scalar_mul_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_mul_assign(self, ct, scalar).unwrap()
})

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute homomorphically a subtraction of a ciphertext by a scalar.
@@ -15,11 +15,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt(5);
///
/// // Compute homomorphically a scalar subtraction:
@@ -28,8 +29,24 @@ impl ServerKey {
/// // 5 - 6 mod 4 = 3 mod 4
/// let clear = cks.decrypt(&ct_res);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_sub(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext {
pub fn unchecked_scalar_sub<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_sub(ct, scalar).unwrap()
})
@@ -45,11 +62,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(5);
///
/// // Compute homomorphically a scalar subtraction:
@@ -57,8 +75,23 @@ impl ServerKey {
///
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(5);
///
/// // Compute homomorphically a scalar subtraction:
/// sks.unchecked_scalar_sub_assign(&mut ct, 2);
///
/// let clear = cks.decrypt(&ct);
/// assert_eq!(3, clear);
/// ```
pub fn unchecked_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn unchecked_scalar_sub_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_sub_assign(ct, scalar).unwrap()
})
@@ -70,19 +103,34 @@ impl ServerKey {
///
///```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt(5);
///
/// // Verification if the scalar subtraction can be computed:
/// let can_be_computed = sks.is_scalar_sub_possible(&ct, 3);
///
/// assert_eq!(can_be_computed, true);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(5);
///
/// // Verification if the scalar subtraction can be computed:
/// let can_be_computed = sks.is_scalar_sub_possible(&ct, 3);
///
/// assert_eq!(can_be_computed, true);
/// ```
pub fn is_scalar_sub_possible(&self, ct: &Ciphertext, scalar: u8) -> bool {
pub fn is_scalar_sub_possible<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> bool {
let neg_scalar = u64::from(scalar.wrapping_neg()) % self.message_modulus.0 as u64;
let final_degree = neg_scalar as usize + ct.degree.0;
final_degree <= self.max_degree.0
@@ -97,12 +145,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// // Encrypt a message
/// let ct = cks.encrypt(5);
///
/// // Compute homomorphically a subtraction multiplication:
@@ -113,12 +161,26 @@ impl ServerKey {
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, 3);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(5);
///
/// // Compute homomorphically a subtraction multiplication:
/// let ct_res = sks.checked_scalar_sub(&ct, 2);
///
/// assert!(ct_res.is_ok());
///
/// let ct_res = ct_res.unwrap();
/// let clear_res = cks.decrypt(&ct_res);
/// assert_eq!(clear_res, 3);
/// ```
pub fn checked_scalar_sub(
pub fn checked_scalar_sub<OpOrder: PBSOrderMarker>(
&self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
scalar: u8,
) -> Result<Ciphertext, CheckError> {
) -> Result<CiphertextBase<OpOrder>, CheckError> {
//If the scalar subtraction cannot be done without exceeding the max degree
if self.is_scalar_sub_possible(ct, scalar) {
let ct_result = self.unchecked_scalar_sub(ct, scalar);
@@ -137,12 +199,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message:
/// // Encrypt a message
/// let mut ct = cks.encrypt(5);
///
/// // Compute homomorphically a scalar subtraction:
@@ -152,10 +214,23 @@ impl ServerKey {
///
/// let clear_res = cks.decrypt(&ct);
/// assert_eq!(clear_res, 3);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(5);
///
/// // Compute homomorphically a scalar subtraction:
/// let res = sks.checked_scalar_sub_assign(&mut ct, 2);
///
/// assert!(res.is_ok());
///
/// let clear_res = cks.decrypt(&ct);
/// assert_eq!(clear_res, 3);
/// ```
pub fn checked_scalar_sub_assign(
pub fn checked_scalar_sub_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> Result<(), CheckError> {
if self.is_scalar_sub_possible(ct, scalar) {
@@ -176,7 +251,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -184,6 +259,7 @@ impl ServerKey {
/// let msg = 3;
/// let scalar = 3;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a scalar multiplication:
@@ -196,8 +272,28 @@ impl ServerKey {
/// let clear = cks.decrypt(&ct_res);
///
/// assert_eq!(msg - scalar as u64, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_sub(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext {
pub fn smart_scalar_sub<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_sub(self, ct, scalar).unwrap()
})
@@ -214,7 +310,7 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
@@ -222,6 +318,7 @@ impl ServerKey {
/// let msg = 5;
/// let scalar = 3;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
///
/// // Compute homomorphically a scalar multiplication:
@@ -230,8 +327,24 @@ impl ServerKey {
/// // Our result is what we expect
/// let clear = cks.decrypt(&ct);
/// assert_eq!(msg - scalar as u64, clear);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8) {
pub fn smart_scalar_sub_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
scalar: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_sub_assign(self, ct, scalar).unwrap()
})

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Compute homomorphically a right shift of the bits without checks.
@@ -11,12 +11,14 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let ct = cks.encrypt(msg);
/// // | ct |
/// // | carry | message |
@@ -35,8 +37,34 @@ impl ServerKey {
/// 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_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_right_shift(&self, ct: &Ciphertext, shift: u8) -> Ciphertext {
pub fn unchecked_scalar_right_shift<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
shift: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_scalar_right_shift(self, ct, shift)
@@ -50,10 +78,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
/// // | ct |
/// // | carry | message |
@@ -72,8 +102,34 @@ impl ServerKey {
/// 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_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_right_shift_assign(&self, ct: &mut Ciphertext, shift: u8) {
pub fn unchecked_scalar_right_shift_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_scalar_right_shift_assign(self, ct, shift)
@@ -87,13 +143,14 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let ct = cks.encrypt(msg);
/// // | ct |
/// // | carry | message |
@@ -115,8 +172,37 @@ impl ServerKey {
///
/// assert_eq!(msg << shift, msg_and_carry);
/// assert_eq!((msg << shift) % modulus, msg_only);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_left_shift(&self, ct: &Ciphertext, shift: u8) -> Ciphertext {
pub fn unchecked_scalar_left_shift<OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
shift: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_scalar_left_shift(ct, shift).unwrap()
})
@@ -128,10 +214,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
/// // | ct |
/// // | carry | message |
@@ -153,8 +241,37 @@ impl ServerKey {
///
/// assert_eq!(msg << shift, msg_and_carry);
/// assert_eq!((msg << shift) % modulus, msg_only);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn unchecked_scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8) {
pub fn unchecked_scalar_left_shift_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_scalar_left_shift_assign(ct, shift)
@@ -167,21 +284,38 @@ impl ServerKey {
/// # Example
///
///```rust
/// use tfhe::shortint::{gen_keys, Parameters};
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_SMALL_MESSAGE_2_CARRY_2;
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(Parameters::default());
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// 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, shift);
///
/// assert_eq!(false, res);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct1 = cks.encrypt_small(msg);
///
/// // Check if we can perform an addition
/// let res = sks.is_scalar_left_shift_possible(&ct1, shift);
///
/// assert_eq!(false, res);
/// ```
pub fn is_scalar_left_shift_possible(&self, ct1: &Ciphertext, shift: u8) -> bool {
pub fn is_scalar_left_shift_possible<OpOrder: PBSOrderMarker>(
&self,
ct1: &CiphertextBase<OpOrder>,
shift: u8,
) -> bool {
let final_operation_count = ct1.degree.0 << shift as usize;
final_operation_count <= self.max_degree.0
}
@@ -195,13 +329,14 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
///
/// // Generate the client key and the server key:
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let ct1 = cks.encrypt(msg);
/// // | ct |
/// // | carry | message |
@@ -229,12 +364,43 @@ impl ServerKey {
///
/// assert_eq!(msg << shift, msg_and_carry);
/// assert_eq!((msg << shift) % modulus, msg_only);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let ct1 = cks.encrypt_small(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);
/// assert!(ct_res.is_ok());
/// let ct_res = ct_res.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);
/// ```
pub fn checked_scalar_left_shift(
pub fn checked_scalar_left_shift<OpOrder: PBSOrderMarker>(
&self,
ct: &Ciphertext,
ct: &CiphertextBase<OpOrder>,
shift: u8,
) -> Result<Ciphertext, CheckError> {
) -> Result<CiphertextBase<OpOrder>, CheckError> {
if self.is_scalar_left_shift_possible(ct, shift) {
let ct_result = self.unchecked_scalar_left_shift(ct, shift);
Ok(ct_result)
@@ -243,9 +409,9 @@ impl ServerKey {
}
}
pub fn checked_scalar_left_shift_assign(
pub fn checked_scalar_left_shift_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut Ciphertext,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) -> Result<(), CheckError> {
if self.is_scalar_left_shift_possible(ct, shift) {
@@ -265,10 +431,12 @@ impl ServerKey {
///
/// ```rust
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_SMALL_MESSAGE_2_CARRY_2};
/// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
///
/// let msg = 2;
///
/// // Encrypt a message
/// let mut ct = cks.encrypt(msg);
/// // | ct |
/// // | carry | message |
@@ -289,14 +457,46 @@ impl ServerKey {
///
/// assert_eq!(msg << shift, msg_and_carry);
/// assert_eq!((msg << shift) % modulus, msg_only);
///
/// let (cks, sks) = gen_keys(PARAM_SMALL_MESSAGE_2_CARRY_2);
///
/// // Encrypt a message
/// let mut ct = cks.encrypt_small(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);
/// ```
pub fn smart_scalar_left_shift(&self, ct: &mut Ciphertext, shift: u8) -> Ciphertext {
pub fn smart_scalar_left_shift<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_scalar_left_shift(self, ct, shift).unwrap()
})
}
pub fn smart_scalar_left_shift_assign(&self, ct: &mut Ciphertext, shift: u8) {
pub fn smart_scalar_left_shift_assign<OpOrder: PBSOrderMarker>(
&self,
ct: &mut CiphertextBase<OpOrder>,
shift: u8,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_scalar_left_shift_assign(self, ct, shift)

View File

@@ -2,7 +2,7 @@ use super::ServerKey;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::server_key::CheckError;
use crate::shortint::server_key::CheckError::CarryFull;
use crate::shortint::Ciphertext;
use crate::shortint::{CiphertextBase, PBSOrderMarker};
impl ServerKey {
/// Homomorphically subtracts ct_right to ct_left.
@@ -32,7 +32,11 @@ impl ServerKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(cks.decrypt(&ct_res), 2 - 1);
/// ```
pub fn unchecked_sub(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
pub fn unchecked_sub<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.unchecked_sub(self, ct_left, ct_right).unwrap()
})
@@ -65,7 +69,11 @@ impl ServerKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(cks.decrypt(&ct_1) % modulus, 1);
/// ```
pub fn unchecked_sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
pub fn unchecked_sub_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_sub_assign(self, ct_left, ct_right)
@@ -95,7 +103,11 @@ impl ServerKey {
///
/// assert_eq!(true, can_be_subtracted);
/// ```
pub fn is_sub_possible(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> bool {
pub fn is_sub_possible<OpOrder: PBSOrderMarker>(
&self,
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> bool {
// z = ceil( degree / 2^p ) x 2^p
let msg_mod = self.message_modulus.0;
let mut z = (ct_right.degree.0 + msg_mod - 1) / msg_mod;
@@ -132,11 +144,11 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&ct_res.unwrap());
/// assert_eq!(clear_res % modulus, 2);
/// ```
pub fn checked_sub(
pub fn checked_sub<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> Result<Ciphertext, CheckError> {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<CiphertextBase<OpOrder>, CheckError> {
// If the ciphertexts cannot be subtracted without exceeding the degree max
if self.is_sub_possible(ct_left, ct_right) {
let ct_result = self.unchecked_sub(ct_left, ct_right);
@@ -172,10 +184,10 @@ impl ServerKey {
/// let clear_res = cks.decrypt(&ct_1);
/// assert_eq!(clear_res % modulus, 2);
/// ```
pub fn checked_sub_assign(
pub fn checked_sub_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> Result<(), CheckError> {
// If the ciphertexts cannot be subtracted without exceeding the degree max
if self.is_sub_possible(ct_left, ct_right) {
@@ -211,7 +223,11 @@ impl ServerKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(clear_res % modulus, 2);
/// ```
pub fn smart_sub(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
pub fn smart_sub<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_sub(self, ct_left, ct_right).unwrap()
})
@@ -240,7 +256,11 @@ impl ServerKey {
/// let modulus = cks.parameters.message_modulus.0 as u64;
/// assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
/// ```
pub fn smart_sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
pub fn smart_sub_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) {
ShortintEngine::with_thread_local_mut(|engine| {
engine.smart_sub_assign(self, ct_left, ct_right).unwrap()
})
@@ -255,11 +275,11 @@ impl ServerKey {
/// # Warning
///
/// This is an advanced functionality, needed for internal requirements.
pub fn unchecked_sub_with_correcting_term(
pub fn unchecked_sub_with_correcting_term<OpOrder: PBSOrderMarker>(
&self,
ct_left: &Ciphertext,
ct_right: &Ciphertext,
) -> (Ciphertext, u64) {
ct_left: &CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> (CiphertextBase<OpOrder>, u64) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.unchecked_sub_with_correcting_term(self, ct_left, ct_right)
@@ -273,10 +293,10 @@ impl ServerKey {
/// # Warning
///
/// This is an advanced functionality, needed for internal requirements.
pub fn unchecked_sub_with_correcting_term_assign(
pub fn unchecked_sub_with_correcting_term_assign<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &Ciphertext,
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &CiphertextBase<OpOrder>,
) -> u64 {
ShortintEngine::with_thread_local_mut(|engine| {
engine
@@ -291,11 +311,11 @@ impl ServerKey {
/// # Warning
///
/// This is an advanced functionality, needed for internal requirements.
pub fn smart_sub_with_correcting_term(
pub fn smart_sub_with_correcting_term<OpOrder: PBSOrderMarker>(
&self,
ct_left: &mut Ciphertext,
ct_right: &mut Ciphertext,
) -> (Ciphertext, u64) {
ct_left: &mut CiphertextBase<OpOrder>,
ct_right: &mut CiphertextBase<OpOrder>,
) -> (CiphertextBase<OpOrder>, u64) {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.smart_sub_with_correcting_term(self, ct_left, ct_right)

View File

@@ -184,7 +184,7 @@ fn shortint_encrypt_decrypt(param: Parameters) {
let ct = cks.encrypt(clear);
// decryption of ct_zero
// decryption of ct
let dec = cks.decrypt(&ct);
// assert
@@ -256,7 +256,7 @@ fn shortint_keyswitch_bootstrap(param: Parameters) {
let ctxt_0 = cks.encrypt(clear_0);
// keyswitch and bootstrap
let ct_res = sks.keyswitch_bootstrap(&ctxt_0);
let ct_res = sks.clear_carry(&ctxt_0);
// decryption of ct_res
let dec_res = cks.decrypt(&ct_res);
@@ -289,7 +289,7 @@ fn shortint_keyswitch_programmable_bootstrap(param: Parameters) {
//define the accumulator as identity
let acc = sks.generate_accumulator(|n| n % modulus);
// add the two ciphertexts
let ct_res = sks.keyswitch_programmable_bootstrap(&ctxt_0, &acc);
let ct_res = sks.apply_lookup_table(&ctxt_0, &acc);
// decryption of ct_res
let dec_res = cks.decrypt(&ct_res);
@@ -317,7 +317,7 @@ fn shortint_keyswitch_bivariate_programmable_bootstrap(param: Parameters) {
//define the accumulator as identity
let acc = sks.generate_accumulator_bivariate(|x, y| x * 2 * y);
// add the two ciphertexts
let ct_res = sks.keyswitch_programmable_bootstrap_bivariate(&ctxt_0, &ctxt_1, &acc);
let ct_res = sks.unchecked_apply_lookup_table_bivariate(&ctxt_0, &ctxt_1, &acc);
// decryption of ct_res
let dec_res = cks.decrypt(&ct_res);
@@ -406,7 +406,7 @@ fn shortint_generate_accumulator(param: Parameters) {
// encryption of an integer
let ct = cks.encrypt(clear);
let ct_res = sks.keyswitch_programmable_bootstrap(&ct, &acc);
let ct_res = sks.apply_lookup_table(&ct, &acc);
// decryption of ct_res
let dec_res = cks.decrypt(&ct_res);
@@ -493,7 +493,7 @@ fn shortint_smart_add(param: Parameters) {
fn shortint_compressed_public_key_smart_add(param: Parameters) {
let keys = KEY_CACHE.get_from_param(param);
let (cks, sks) = (keys.client_key(), keys.server_key());
let pk = crate::shortint::CompressedPublicKey::new(cks);
let pk = crate::shortint::CompressedPublicKeyBig::new(cks);
//RNG
let mut rng = rand::thread_rng();
@@ -533,7 +533,7 @@ fn shortint_compressed_public_key_smart_add(param: Parameters) {
fn shortint_public_key_smart_add(param: Parameters) {
let keys = KEY_CACHE.get_from_param(param);
let (cks, sks) = (keys.client_key(), keys.server_key());
let pk = crate::shortint::PublicKey::new(cks);
let pk = crate::shortint::PublicKeyBig::new(cks);
//RNG
let mut rng = rand::thread_rng();

View File

@@ -11,7 +11,7 @@ use crate::core_crypto::commons::parameters::*;
use crate::core_crypto::commons::traits::*;
use crate::core_crypto::entities::*;
use crate::shortint::engine::ShortintEngine;
use crate::shortint::{Ciphertext, ClientKey, Parameters, ServerKey};
use crate::shortint::{CiphertextBase, ClientKey, PBSOrderMarker, Parameters, ServerKey};
use serde::{Deserialize, Serialize};
#[cfg(test)]
@@ -79,7 +79,6 @@ impl WopbsKey {
///
/// ```rust
/// use rand::Rng;
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs_message_carry::WOPBS_PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
@@ -96,7 +95,11 @@ impl WopbsKey {
/// let res = cks.decrypt(&ct_res);
/// assert_eq!(res, (m * m) % message_modulus);
/// ```
pub fn generate_lut<F>(&self, ct: &Ciphertext, f: F) -> Vec<u64>
pub fn generate_lut<F, OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
f: F,
) -> Vec<u64>
where
F: Fn(u64) -> u64,
{
@@ -119,7 +122,6 @@ impl WopbsKey {
///
/// ```rust
/// use rand::Rng;
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs_message_carry::WOPBS_PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::wopbs::WopbsKey;
@@ -135,7 +137,11 @@ impl WopbsKey {
/// let res = cks.decrypt_without_padding(&ct_res);
/// assert_eq!(res, (m * m) % message_modulus);
/// ```
pub fn generate_lut_without_padding<F>(&self, ct: &Ciphertext, f: F) -> Vec<u64>
pub fn generate_lut_without_padding<F, OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
f: F,
) -> Vec<u64>
where
F: Fn(u64) -> u64,
{
@@ -157,7 +163,6 @@ impl WopbsKey {
///
/// ```rust
/// use rand::Rng;
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs::WOPBS_PARAM_MESSAGE_3_NORM2_2;
/// use tfhe::shortint::wopbs::WopbsKey;
@@ -173,7 +178,11 @@ impl WopbsKey {
/// let res = cks.decrypt_message_native_crt(&ct_res, message_modulus);
/// assert_eq!(res, (m * m) % message_modulus as u64);
/// ```
pub fn generate_lut_native_crt<F>(&self, ct: &Ciphertext, f: F) -> Vec<u64>
pub fn generate_lut_native_crt<F, OpOrder: PBSOrderMarker>(
&self,
ct: &CiphertextBase<OpOrder>,
f: F,
) -> Vec<u64>
where
F: Fn(u64) -> u64,
{
@@ -198,7 +207,6 @@ impl WopbsKey {
///
/// ```rust
/// use rand::Rng;
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs_message_carry::WOPBS_PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
@@ -215,12 +223,12 @@ impl WopbsKey {
/// let res = cks.decrypt_message_and_carry(&ct_res);
/// assert_eq!(res, 1);
/// ```
pub fn programmable_bootstrapping(
pub fn programmable_bootstrapping<OpOrder: PBSOrderMarker>(
&self,
sks: &ServerKey,
ct_in: &Ciphertext,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
) -> Ciphertext {
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.programmable_bootstrapping(self, sks, ct_in, lut)
@@ -237,7 +245,6 @@ impl WopbsKey {
///
/// ```rust
/// use rand::Rng;
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs_message_carry::WOPBS_PARAM_MESSAGE_2_CARRY_2;
/// use tfhe::shortint::wopbs::*;
@@ -253,7 +260,11 @@ impl WopbsKey {
/// let res = cks.decrypt_message_and_carry(&ct_res);
/// assert_eq!(res, 1);
/// ```
pub fn wopbs(&self, ct_in: &Ciphertext, lut: &[u64]) -> Ciphertext {
pub fn wopbs<OpOrder: PBSOrderMarker>(
&self,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.wopbs(self, ct_in, lut).unwrap())
}
@@ -263,7 +274,6 @@ impl WopbsKey {
///
/// ```rust
/// use rand::Rng;
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs::WOPBS_PARAM_MESSAGE_1_NORM2_2;
/// use tfhe::shortint::wopbs::*;
@@ -277,11 +287,11 @@ impl WopbsKey {
/// let res = cks.decrypt_message_and_carry_without_padding(&ct_res);
/// assert_eq!(res, 1);
/// ```
pub fn programmable_bootstrapping_without_padding(
pub fn programmable_bootstrapping_without_padding<OpOrder: PBSOrderMarker>(
&self,
ct_in: &Ciphertext,
ct_in: &CiphertextBase<OpOrder>,
lut: &[u64],
) -> Ciphertext {
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.programmable_bootstrapping_without_padding(self, ct_in, lut)
@@ -294,7 +304,6 @@ impl WopbsKey {
/// # Example
///
/// ```rust
/// use tfhe::shortint::ciphertext::Ciphertext;
/// use tfhe::shortint::gen_keys;
/// use tfhe::shortint::parameters::parameters_wopbs::WOPBS_PARAM_MESSAGE_3_NORM2_2;
/// use tfhe::shortint::wopbs::*;
@@ -309,11 +318,11 @@ impl WopbsKey {
/// let res = cks.decrypt_message_native_crt(&ct_res, modulus);
/// assert_eq!(res, msg);
/// ```
pub fn programmable_bootstrapping_native_crt(
pub fn programmable_bootstrapping_native_crt<OpOrder: PBSOrderMarker>(
&self,
ct_in: &mut Ciphertext,
ct_in: &mut CiphertextBase<OpOrder>,
lut: &[u64],
) -> Ciphertext {
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.programmable_bootstrapping_native_crt(self, ct_in, lut)
@@ -324,10 +333,10 @@ impl WopbsKey {
/// Extract the given number of bits from a ciphertext.
///
/// # Warning Experimental
pub fn extract_bits(
pub fn extract_bits<OpOrder: PBSOrderMarker>(
&self,
delta_log: DeltaLog,
ciphertext: &Ciphertext,
ciphertext: &CiphertextBase<OpOrder>,
num_bits_to_extract: usize,
) -> LweCiphertextListOwned<u64> {
ShortintEngine::with_thread_local_mut(|engine| {
@@ -345,10 +354,10 @@ impl WopbsKey {
/// Extract the given number of bits from a ciphertext.
///
/// # Warning Experimental
pub fn extract_bits_assign<OutputCont>(
pub fn extract_bits_assign<OutputCont, OpOrder: PBSOrderMarker>(
&self,
delta_log: DeltaLog,
ciphertext: &Ciphertext,
ciphertext: &CiphertextBase<OpOrder>,
num_bits_to_extract: usize,
output: &mut LweCiphertextList<OutputCont>,
) where
@@ -381,14 +390,21 @@ impl WopbsKey {
})
}
pub fn keyswitch_to_wopbs_params(&self, sks: &ServerKey, ct_in: &Ciphertext) -> Ciphertext {
pub fn keyswitch_to_wopbs_params<OpOrder: PBSOrderMarker>(
&self,
sks: &ServerKey,
ct_in: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| {
engine.keyswitch_to_wopbs_params(sks, self, ct_in)
})
.unwrap()
}
pub fn keyswitch_to_pbs_params(&self, ct_in: &Ciphertext) -> Ciphertext {
pub fn keyswitch_to_pbs_params<OpOrder: PBSOrderMarker>(
&self,
ct_in: &CiphertextBase<OpOrder>,
) -> CiphertextBase<OpOrder> {
ShortintEngine::with_thread_local_mut(|engine| engine.keyswitch_to_pbs_params(self, ct_in))
.unwrap()
}

View File

@@ -9,7 +9,7 @@ pub struct GenericShortIntPublicKey<P>
where
P: ShortIntegerParameter,
{
pub(in crate::typed_api::shortints) key: crate::shortint::public_key::PublicKey,
pub(in crate::typed_api::shortints) key: crate::shortint::public_key::PublicKeyBig,
_marker: std::marker::PhantomData<P>,
}
@@ -18,7 +18,7 @@ where
P: ShortIntegerParameter,
{
pub fn new(client_key: &GenericShortIntClientKey<P>) -> Self {
let key = crate::shortint::public_key::PublicKey::new(&client_key.key);
let key = crate::shortint::public_key::PublicKeyBig::new(&client_key.key);
Self {
key,
_marker: Default::default(),

View File

@@ -458,7 +458,7 @@ where
let accumulator = self.key.generate_accumulator(func);
let new_ciphertext = self
.key
.keyswitch_programmable_bootstrap(&ciphertext.ciphertext.borrow(), &accumulator);
.apply_lookup_table(&ciphertext.ciphertext.borrow(), &accumulator);
GenericShortInt {
ciphertext: RefCell::new(new_ciphertext),
id: ciphertext.id,
@@ -470,10 +470,8 @@ where
F: Fn(u64) -> u64,
{
let accumulator = self.key.generate_accumulator(func);
self.key.keyswitch_programmable_bootstrap_assign(
&mut ciphertext.ciphertext.borrow_mut(),
&accumulator,
)
self.key
.apply_lookup_table_assign(&mut ciphertext.ciphertext.borrow_mut(), &accumulator)
}
pub(super) fn bivariate_pbs<F>(
@@ -488,7 +486,7 @@ where
{
let wrapped_f = |lhs: u64, rhs: u64| -> u64 { u64::from(func(lhs as u8, rhs as u8)) };
let ciphertext = self.key.smart_functional_bivariate_pbs(
let ciphertext = self.key.smart_evaluate_bivariate_function(
&mut lhs_ct.ciphertext.borrow_mut(),
&mut rhs_ct.ciphertext.borrow_mut(),
wrapped_f,

View File

@@ -7,7 +7,7 @@ use std::ops::{
use serde::{Deserialize, Serialize};
use crate::shortint::ciphertext::Ciphertext;
use crate::shortint::ciphertext::CiphertextBig as ShortintCiphertext;
use crate::typed_api::errors::OutOfRangeError;
use crate::typed_api::global_state::WithGlobalKey;
@@ -98,7 +98,7 @@ pub struct GenericShortInt<P: ShortIntegerParameter> {
/// of the corresponding `ServerKey` (in tfhe-shortint)
/// require the ciphertext to be a `&mut`,
/// while we also overloads rust operators for have a `&` references
pub(in crate::typed_api::shortints) ciphertext: RefCell<Ciphertext>,
pub(in crate::typed_api::shortints) ciphertext: RefCell<ShortintCiphertext>,
pub(in crate::typed_api::shortints) id: P::Id,
}
@@ -106,7 +106,7 @@ impl<P> GenericShortInt<P>
where
P: ShortIntegerParameter,
{
pub(crate) fn new(inner: Ciphertext, id: P::Id) -> Self {
pub(crate) fn new(inner: ShortintCiphertext, id: P::Id) -> Self {
Self {
ciphertext: RefCell::new(inner),
id,

View File

@@ -1,4 +1,4 @@
use crate::shortint::CompressedCiphertext;
use crate::shortint::CompressedCiphertextBig as ShortintCompressedCiphertext;
use crate::typed_api::keys::RefKeyFromKeyChain;
use crate::typed_api::shortints::client_key::GenericShortIntClientKey;
use crate::typed_api::shortints::parameters::ShortIntegerParameter;
@@ -10,7 +10,7 @@ pub struct CompressedGenericShortint<P>
where
P: ShortIntegerParameter,
{
pub(in crate::typed_api::shortints) ciphertext: CompressedCiphertext,
pub(in crate::typed_api::shortints) ciphertext: ShortintCompressedCiphertext,
pub(in crate::typed_api::shortints) id: P::Id,
}
@@ -18,7 +18,7 @@ impl<P> CompressedGenericShortint<P>
where
P: ShortIntegerParameter,
{
pub(crate) fn new(inner: CompressedCiphertext, id: P::Id) -> Self {
pub(crate) fn new(inner: ShortintCompressedCiphertext, id: P::Id) -> Self {
Self {
ciphertext: inner,
id,