mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-11 15:48:20 -05:00
Compare commits
2 Commits
0.2.4
...
release/0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b80f449a5 | ||
|
|
a37f6a2e05 |
@@ -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"]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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" %}
|
||||
|
||||
@@ -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"
|
||||
```
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user