Skip to content

Commit

Permalink
docs(hlapi): document trivial encryption to debug
Browse files Browse the repository at this point in the history
  • Loading branch information
tmontaigu committed Jan 25, 2024
1 parent 0bfe59a commit 35d65bc
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 21 deletions.
1 change: 1 addition & 0 deletions tfhe/docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* [Use the C API](how_to/c_api.md)
* [Use the JS on WASM API](how_to/js_on_wasm_api.md)
* [Use multi-threading using the rayon crate](how_to/rayon_crate.md)
* [Debug](how_to/debug.md)

## Fine-grained APIs
* [Quick Start](fine_grained_api/quick_start.md)
Expand Down
72 changes: 72 additions & 0 deletions tfhe/docs/how_to/debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Debugging FHE Code

Since tfhe-rs 0.5, [trivial ciphertexts](./trivial_ciphertext.md) have another application.
They can be used to allow debugging via a debugger or print statements as well as speeding-up execution time
so that you won't have to spend minutes waiting for execution to progress.

This can greatly improve the pace at which one develops FHE applications.

{% hint style="warning" %}
Keep in mind that trivial ciphertexts are not secure at all, thus an application released/deployed in production
must never receive trivial ciphertext from a client.
{% endhint %}


## Example

To use this feature, simply call your circuits/functions with trivially encrypted values (made using `encrypt_trivial`)
instead of real encryptions (made using `encrypt`)

```rust
use tfhe::prelude::*;
use tfhe::{set_server_key, generate_keys, ConfigBuilder, FheUint128};


fn mul_all(a: &FheUint128, b: &FheUint128, c: &FheUint128) -> FheUint128 {
// Use the debug format ('{:?}'), if you don't want to unwrap()
// and panic if the value is not a trivial.
println!(
"a: {:?}, b: {:?}, c: {:?}",
a.try_decrypt_trivial::<u128>(),
b.try_decrypt_trivial::<u128>(),
c.try_decrypt_trivial::<u128>(),
);
let tmp = a * b;

println!("a * b = {:?}", tmp.try_decrypt_trivial::<u128>());

tmp * c
}


fn main() {
let (cks, sks) = generate_keys(ConfigBuilder::default().build());

set_server_key(sks);

let a = FheUint128::encrypt_trivial(1234u128);
let b = FheUint128::encrypt_trivial(4567u128);
let c = FheUint128::encrypt_trivial(89101112u128);

// since all inputs are trivially encrypted, this is going to be
// much faster
let result = mul_all(&a, &b, &c);
}
```

This example is going to print.
```text
a: Ok(1234), b: Ok(4567), c: Ok(89101112)
a * b = Ok(5635678)
```

If any input to `mul_all` is not a trivial ciphertexts, the computations would be done 100% in FHE, and the program
would output:

```text
a: Err(NotTrivialCiphertextError), b: Err(NotTrivialCiphertextError), c: Err(NotTrivialCiphertextError)
a * b = Err(NotTrivialCiphertextError)
```

Using trivial encryptions as input, the example runs in **980 ms** on a standard 12 cores laptop, using real encryptions
it would run in **7.5 seconds** on a 128-core machine.
47 changes: 31 additions & 16 deletions tfhe/docs/how_to/rayon_crate.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Making rayon and tfhe-rs work together
# Making Rayon And TFHE-RS Work Together

[rayon](https://crates.io/crates/rayon) is a popular create to easily write multi-threaded code in Rust.
[rayon](https://crates.io/crates/rayon) is a popular crate to easily write multi-threaded code in Rust.

It is possible to use rayon to write multi-threaded tfhe-rs code. However due to internal details of `rayon` and
`tfhe-rs`, there is some special setup that needs to be done.
It is possible to use rayon to write multi-threaded TFHE-rs code. However due to internal details of `rayon` and
`TFHE-rs`, there is some special setup that needs to be done.

## Single Client Application

### The problem
### The Problem

The high level api requires to call `set_server_key` on each thread where computations needs to be done.
So a first attempt at using rayon with tfhe-rs might look like this:
So a first attempt at using rayon with `TFHE-rs` might look like this:

```rust
use rayon::prelude::*;
Expand Down Expand Up @@ -46,10 +46,10 @@ fn main() {
}
```

However, due to rayon's work stealing mechanism and tfhe-rs's internals, this may create `BorrowMutError'.
However, due to rayon's work stealing mechanism and TFHE-rs's internals, this may create `BorrowMutError'.


### Working example
### Working Example

The correct way is to call `rayon::broadcast`

Expand Down Expand Up @@ -85,13 +85,18 @@ fn main() {
&xs[1] + &ys[1]
}
);

let a: u8 = a.decrypt(&cks);
let b: u8 = b.decrypt(&cks);
assert_eq!(a, 4u8);
assert_eq!(b, 6u8);
}
```


## Multi-Client Applications

If you application needs to operate on data from different clients concurently, and that you want each client to use
If your application needs to operate on data from different clients concurrently, and that you want each client to use
multiple threads, you will need to create different rayon thread pools

```rust
Expand Down Expand Up @@ -128,29 +133,39 @@ fn main() {
client_1_pool.broadcast(|_| set_server_key(sks1.clone()));
client_2_pool.broadcast(|_| set_server_key(sks2.clone()));

rayon::join(|| {
let ((a1, b1), (a2, b2)) = rayon::join(|| {
client_1_pool.install(|| {
let (a1, b1) = rayon::join(
rayon::join(
|| {
&xs1[0] + &ys1[0]
},
|| {
&xs1[1] + &ys1[1]
}
);
});
)
})
}, || {
client_2_pool.install(|| {
let (a2, b2) = rayon::join(
rayon::join(
|| {
&xs2[0] + &ys2[0]
},
|| {
&xs2[1] + &ys2[1]
}
);
)
})
});

let a1: u8 = a1.decrypt(&cks1);
let b1: u8 = b1.decrypt(&cks1);
assert_eq!(a1, 4u8);
assert_eq!(b1, 6u8);

let a2: u8 = a2.decrypt(&cks2);
let b2: u8 = b2.decrypt(&cks2);
assert_eq!(a2, 203u8);
assert_eq!(b2, 148u8);
}
```

Expand All @@ -177,4 +192,4 @@ fn test_2() {
assert_eq!(result, expected_value);
})
}
```
```
8 changes: 3 additions & 5 deletions tfhe/src/test_user_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,15 @@ mod test_cpu_doc {
"../docs/how_to/overflow_operations.md",
how_to_detect_overflow
);
doctest!(
"../docs/how_to/rayon_crate.md",
how_to_rayon_crate
);
doctest!("../docs/how_to/rayon_crate.md", how_to_rayon_crate);
doctest!("../docs/how_to/debug.md", how_to_debug);

//FINE GRAINED API
doctest!(
"../docs/fine_grained_api/quick_start.md",
fine_grained_api_quick_start
);

// fine_grained_api/Boolean
doctest!(
"../docs/fine_grained_api/Boolean/operations.md",
Expand Down

0 comments on commit 35d65bc

Please sign in to comment.