Compare commits

...

2 Commits

Author SHA1 Message Date
Arthur Meyre
2b80f449a5 chore(tfhe): bump version to 0.2.5 2023-07-25 21:00:36 +02:00
Arthur Meyre
a37f6a2e05 fix(integer): set proper MaxDegree for CompressedServerKey
- add shortint API to generate a CompressedServerKey with MaxDegree
- add non regression test based on the user issue
- factorize MaxDegree computation for integer server keys
2023-07-25 21:00:36 +02:00
7 changed files with 79 additions and 18 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "tfhe"
version = "0.2.4"
version = "0.2.5"
edition = "2021"
readme = "../README.md"
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]

View File

@@ -9,7 +9,7 @@ Welcome to this tutorial about TFHE-rs `core_crypto` module.
To use `TFHE-rs`, first it has to be added as a dependency in the `Cargo.toml`:
```toml
tfhe = { version = "0.2.4", features = [ "x86_64-unix" ] }
tfhe = { version = "0.2.5", features = [ "x86_64-unix" ] }
```
This enables the `x86_64-unix` feature to have efficient implementations of various algorithms for `x86_64` CPUs on a Unix-like system. The 'unix' suffix indicates that the `UnixSeeder`, which uses `/dev/random` to generate random numbers, is activated as a fallback if no hardware number generator is available, like `rdseed` on `x86_64` or if the [`Randomization Services`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc) on Apple platforms are not available. To avoid having the `UnixSeeder` as a potential fallback or to run on non-Unix systems (e.g., Windows), the `x86_64` feature is sufficient.
@@ -19,19 +19,19 @@ For Apple Silicon, the `aarch64-unix` or `aarch64` feature should be enabled. `a
In short: For x86\_64-based machines running Unix-like OSes:
```toml
tfhe = { version = "0.2.4", features = ["x86_64-unix"] }
tfhe = { version = "0.2.5", features = ["x86_64-unix"] }
```
For Apple Silicon or aarch64-based machines running Unix-like OSes:
```toml
tfhe = { version = "0.2.4", features = ["aarch64-unix"] }
tfhe = { version = "0.2.5", features = ["aarch64-unix"] }
```
For x86\_64-based machines with the [`rdseed instruction`](https://en.wikipedia.org/wiki/RDRAND) running Windows:
```toml
tfhe = { version = "0.2.4", features = ["x86_64"] }
tfhe = { version = "0.2.5", features = ["x86_64"] }
```
### Commented code to double a 2-bits message in a leveled fashion and using a PBS with the `core_crypto` module.

View File

@@ -5,7 +5,7 @@
To use `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`:
```toml
tfhe = { version = "0.2.4", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
tfhe = { version = "0.2.5", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
```
{% hint style="info" %}

View File

@@ -11,7 +11,7 @@ To serialize our data, a [data format](https://serde.rs/#data-formats) should be
[dependencies]
# ...
tfhe = { version = "0.2.4", features = ["integer","x86_64-unix"]}
tfhe = { version = "0.2.5", features = ["integer","x86_64-unix"]}
bincode = "1.3.3"
```

View File

@@ -46,7 +46,7 @@ fn main() {
Default configuration for x86 Unix machines:
```toml
tfhe = { version = "0.2.4", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.2.5", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).
@@ -190,7 +190,7 @@ To use the `FheUint8` type, the `integer` feature must be activated:
[dependencies]
# Default configuration for x86 Unix machines:
tfhe = { version = "0.2.4", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.2.5", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).
@@ -319,7 +319,7 @@ To use Booleans, the `booleans` feature in our Cargo.toml must be enabled:
# Cargo.toml
# Default configuration for x86 Unix machines:
tfhe = { version = "0.2.4", features = ["boolean", "x86_64-unix"]}
tfhe = { version = "0.2.5", features = ["boolean", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).

View File

@@ -30,6 +30,15 @@ impl From<ServerKey> for crate::shortint::ServerKey {
}
}
/// Compute the [`MaxDegree`] for an integer server key (compressed or uncompressed). This formula
/// provisions a free carry bit. This allows carry propagation between shortint blocks in a
/// [`RadixCiphertext`](`crate::integer::ciphertext::RadixCiphertext`), as that process requires
/// adding a bit of carry from one shortint block to the next, which would overflow and lead to
/// wrong results if we did not provision that carry bit.
fn integer_server_key_max_degree(parameters: crate::shortint::Parameters) -> MaxDegree {
MaxDegree((parameters.message_modulus.0 - 1) * parameters.carry_modulus.0 - 1)
}
impl ServerKey {
/// Generates a server key.
///
@@ -51,13 +60,11 @@ impl ServerKey {
{
// It should remain just enough space to add a carry
let client_key = cks.as_ref();
let max = (client_key.key.parameters.message_modulus.0 - 1)
* client_key.key.parameters.carry_modulus.0
- 1;
let max_degree = integer_server_key_max_degree(client_key.key.parameters);
let sks = crate::shortint::server_key::ServerKey::new_with_max_degree(
&client_key.key,
MaxDegree(max),
max_degree,
);
ServerKey { key: sks }
@@ -84,10 +91,9 @@ impl ServerKey {
mut key: crate::shortint::server_key::ServerKey,
) -> ServerKey {
// It should remain just enough space add a carry
let max =
(cks.key.parameters.message_modulus.0 - 1) * cks.key.parameters.carry_modulus.0 - 1;
let max_degree = integer_server_key_max_degree(cks.key.parameters);
key.max_degree = MaxDegree(max);
key.max_degree = max_degree;
ServerKey { key }
}
}
@@ -98,7 +104,10 @@ pub struct CompressedServerKey {
impl CompressedServerKey {
pub fn new(client_key: &ClientKey) -> CompressedServerKey {
let key = crate::shortint::CompressedServerKey::new(&client_key.key);
let max_degree = integer_server_key_max_degree(client_key.key.parameters);
let key =
crate::shortint::CompressedServerKey::new_with_max_degree(&client_key.key, max_degree);
Self { key }
}
}
@@ -109,3 +118,46 @@ impl From<CompressedServerKey> for ServerKey {
Self { key }
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::integer::RadixClientKey;
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
/// https://github.com/zama-ai/tfhe-rs/issues/460
/// Problem with CompressedServerKey degree being set to shortint MaxDegree not accounting for
/// the necessary carry bits for e.g. Radix carry propagation.
#[test]
fn test_compressed_server_key_max_degree() {
let cks = ClientKey::new(crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2);
// msg_mod = 4, carry_mod = 4, (msg_mod - 1) * carry_mod = 12; minus 1 => 11
let expected_max_degree = MaxDegree(11);
let sks = ServerKey::new(&cks);
assert_eq!(sks.key.max_degree, expected_max_degree);
let csks = CompressedServerKey::new(&cks);
assert_eq!(csks.key.max_degree, expected_max_degree);
let decompressed_sks: ServerKey = csks.into();
assert_eq!(decompressed_sks.key.max_degree, expected_max_degree);
// Repro case from the user
{
let client_key = RadixClientKey::new(PARAM_MESSAGE_2_CARRY_2, 14);
let compressed_eval_key = CompressedServerKey::new(client_key.as_ref());
let evaluation_key = ServerKey::from(compressed_eval_key);
let modulus = (client_key.parameters().message_modulus.0 as u128)
.pow(client_key.num_blocks() as u32);
let mut ct = client_key.encrypt(modulus - 1);
let mut res_ct = ct.clone();
for _ in 0..5 {
res_ct = evaluation_key.smart_add_parallelized(&mut res_ct, &mut ct);
}
let res = client_key.decrypt::<u128, _>(&res_ct);
assert_eq!(modulus - 6, res);
}
}
}

View File

@@ -44,4 +44,13 @@ impl CompressedServerKey {
engine.new_compressed_server_key(client_key).unwrap()
})
}
/// Generate a compressed server key with a chosen maximum degree
pub fn new_with_max_degree(cks: &ClientKey, max_degree: MaxDegree) -> CompressedServerKey {
ShortintEngine::with_thread_local_mut(|engine| {
engine
.new_compressed_server_key_with_max_degree(cks, max_degree)
.unwrap()
})
}
}