Skip to content

Commit 9d33b4b

Browse files
committed
docs(frontend): add documentation for concrete-rust
1 parent ebef4fb commit 9d33b4b

2 files changed

Lines changed: 207 additions & 0 deletions

File tree

docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* [Debugging and artifact](execution-analysis/debug.md)
3939
* [Performance](optimization/summary.md)
4040
* [GPU acceleration](execution-analysis/gpu_acceleration.md)
41+
* [Rust integration](execution-analysis/rust_integration.md)
4142
* Other
4243
* [Statistics](compilation/statistics.md)
4344
* [Progressbar](execution-analysis/progressbar.md)
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Rust Integration
2+
3+
This document explains how to use Fully Homomorphic Encryption (FHE) modules developed with **concrete-python** directly in Rust programs using the **Concrete** toolchain.
4+
5+
This workflow enables rapid prototyping in Python and seamless deployment in Rust, combining the flexibility of Python with the safety and performance of Rust.
6+
7+
## Overview
8+
9+
- Write and compile FHE modules in Python using `concrete-python`.
10+
- Import the compiled module artifact into Rust using the `concrete-macro` crate.
11+
- Use the generated Rust APIs for encryption, evaluation, and decryption.
12+
13+
## Prerequisites
14+
15+
- Python 3.8+
16+
- Rust 1.70+
17+
- `concrete-python` (>=2.10)
18+
- `concrete` and `concrete-macro` Rust crates (>=2.10.1-rc1)
19+
20+
## Regular example
21+
22+
### Step 1: Define and Compile a Module in Python
23+
24+
Write your FHE logic in Python and compile it to an artifact compatible with the Rust toolchain. Here is an example of a small and simple module:
25+
26+
```python
27+
from concrete import fhe
28+
29+
@fhe.module()
30+
class MyModule:
31+
@fhe.function({"x": "encrypted"})
32+
def inc(x):
33+
return (x + 1) % 256
34+
35+
@fhe.function({"x": "encrypted"})
36+
def dec(x):
37+
return (x - 1) % 256
38+
39+
inputset = fhe.inputset(fhe.uint8)
40+
module = MyModule.compile({"inc": inputset, "dec": inputset})
41+
42+
module.server.save(path="MyModule.zip", via_mlir=True)
43+
```
44+
45+
This produces a `MyModule.zip` artifact containing the compiled FHE module.
46+
47+
### Step 2: Set Up the Rust Project
48+
49+
Initialize a new Rust project and add the required dependencies.
50+
51+
```shell
52+
cargo init
53+
cargo add concrete@=2.10.1-rc1 concrete-macro@=2.10.1-rc1
54+
```
55+
56+
Place the `MyModule.zip` artifact in your project directory.
57+
58+
### Step 3: Import the Python-Compiled Module in Rust
59+
60+
Use the `concrete_macro::from_concrete_python_export_zip!` macro to import the module at build time.
61+
62+
```rust
63+
mod my_module {
64+
use concrete_macro::from_concrete_python_export_zip;
65+
from_concrete_python_export_zip!("MyModule.zip");
66+
}
67+
```
68+
69+
This macro unpacks the artifact, triggers recompilation, reads metadata, and generates Rust APIs for the module's functions.
70+
71+
### Step 4: Use the Module in Rust
72+
73+
You can now use the FHE functions in Rust. The following example demonstrates a full FHE workflow:
74+
75+
```rust
76+
use concrete::common::Tensor;
77+
78+
fn main() {
79+
// Prepare input and expected output tensors
80+
let input = Tensor::new(vec![5], vec![]);
81+
let expected_output = Tensor::new(vec![6], vec![]);
82+
83+
// Key generation
84+
let mut secret_csprng = concrete::common::SecretCsprng::new(0u128);
85+
let mut encryption_csprng = concrete::common::EncryptionCsprng::new(0u128);
86+
let keyset = my_module::new_keyset(secret_csprng.pin_mut(), encryption_csprng.pin_mut());
87+
let client_keyset = keyset.get_client();
88+
89+
// Create client stub for the 'inc' function
90+
let mut inc_client = my_module::client::inc::ClientFunction::new(&client_keyset, encryption_csprng);
91+
92+
// Encrypt input and obtain evaluation keys
93+
let encrypted_input = inc_client.prepare_inputs(input);
94+
let evaluation_keys = keyset.get_server();
95+
96+
// Create server stub for the 'inc' function
97+
let mut inc_server = my_module::server::inc::ServerFunction::new();
98+
99+
// Evaluate the function on encrypted data
100+
let encrypted_output = inc_server.invoke(&evaluation_keys, encrypted_input);
101+
102+
// Decrypt the output
103+
let decrypted_output = inc_client.process_outputs(encrypted_output);
104+
105+
// Check correctness
106+
assert_eq!(decrypted_output.values(), expected_output.values());
107+
}
108+
```
109+
110+
## TFHE-rs Ciphertext Interoperability
111+
112+
Starting from Concrete v2.11, you can define and use modules that operate directly on TFHE-rs ciphertexts, enabling seamless interoperability between Concrete and TFHE-rs in Rust.
113+
114+
### Step 1: Define and Compile a Module with TFHE-rs Types in Python
115+
116+
You can define a module in Python that uses TFHE-rs integer types as arguments and outputs. For example:
117+
118+
```python
119+
from concrete import fhe
120+
from concrete.fhe import tfhers
121+
122+
TFHERS_UINT_8_3_2_4096 = tfhers.TFHERSIntegerType(
123+
False,
124+
bit_width=8,
125+
carry_width=3,
126+
msg_width=2,
127+
params=tfhers.CryptoParams(
128+
lwe_dimension=909,
129+
glwe_dimension=1,
130+
polynomial_size=4096,
131+
pbs_base_log=15,
132+
pbs_level=2,
133+
lwe_noise_distribution=0,
134+
glwe_noise_distribution=2.168404344971009e-19,
135+
encryption_key_choice=tfhers.EncryptionKeyChoice.BIG,
136+
),
137+
)
138+
139+
@fhe.module()
140+
class MyModule:
141+
142+
@fhe.function({"x": "encrypted", "y": "encrypted"})
143+
def my_func(x, y):
144+
x = tfhers.to_native(x)
145+
y = tfhers.to_native(y)
146+
return tfhers.from_native(x + y, TFHERS_UINT_8_3_2_4096)
147+
148+
def t(v):
149+
return tfhers.TFHERSInteger(TFHERS_UINT_8_3_2_4096, v)
150+
151+
inputset = [(t(0), t(0)), (t(2**6), t(2**6))]
152+
my_module = MyModule.compile({"my_func": inputset})
153+
my_module.server.save("test_tfhers.zip", via_mlir=True)
154+
```
155+
156+
This produces a `test_tfhers.zip` artifact compatible with Rust and TFHE-rs.
157+
158+
### Step 2: Use the Module with TFHE-rs Ciphertexts in Rust
159+
160+
You can import and use the module in Rust, passing and receiving native TFHE-rs ciphertexts:
161+
162+
```rust
163+
mod precompile {
164+
use concrete_macro::from_concrete_python_export_zip;
165+
from_concrete_python_export_zip!("src/test_tfhers.zip");
166+
}
167+
168+
use tfhe::prelude::{FheDecrypt, FheEncrypt};
169+
use tfhe::shortint::parameters::v0_10::classic::gaussian::p_fail_2_minus_64::ks_pbs::V0_10_PARAM_MESSAGE_2_CARRY_3_KS_PBS_GAUSSIAN_2M64;
170+
use tfhe::{generate_keys, FheUint8};
171+
172+
fn main() {
173+
// Key generation for TFHE-rs
174+
let config = tfhe::ConfigBuilder::with_custom_parameters(V0_10_PARAM_MESSAGE_2_CARRY_3_KS_PBS_GAUSSIAN_2M64);
175+
let (client_key, _) = generate_keys(config);
176+
177+
// Build Concrete keyset with TFHE-rs client key
178+
let mut secret_csprng = concrete::common::SecretCsprng::new(0u128);
179+
let mut encryption_csprng = concrete::common::EncryptionCsprng::new(0u128);
180+
let keyset = precompile::KeysetBuilder::new()
181+
.with_key_for_my_func_0_arg(&client_key)
182+
.generate(secret_csprng.pin_mut(), encryption_csprng.pin_mut());
183+
let server_keyset = keyset.get_server();
184+
185+
// Encrypt inputs using TFHE-rs
186+
let arg_0 = FheUint8::encrypt(6u8, &client_key);
187+
let arg_1 = FheUint8::encrypt(4u8, &client_key);
188+
189+
// Evaluate the Concrete circuit on TFHE-rs ciphertexts
190+
let mut server = precompile::server::my_func::ServerFunction::new();
191+
let output = server.invoke(&server_keyset, arg_0, arg_1);
192+
193+
// Decrypt the result using TFHE-rs
194+
let decrypted: u8 = output.decrypt(&client_key);
195+
assert_eq!(decrypted, 10);
196+
}
197+
```
198+
199+
This workflow allows you to combine the high-level graph optimizations of Concrete with the operator-level flexibility of TFHE-rs, all within Rust.
200+
201+
## Notes
202+
203+
- The module must be compiled with `via_mlir=True` to be loaded in the Rust program.
204+
- The Rust API is currently in beta and may evolve in future releases.
205+
- The Python and Rust environments must use compatible versions of the Concrete toolchain.
206+
- When using TFHE-rs ciphertext interoperability, ensure that the TFHE-rs client key used for encryption matches the one registered in the Concrete keyset for the corresponding argument.

0 commit comments

Comments
 (0)