owned this note
owned this note
Published
Linked with GitHub
# Circom-Tfhe-rs
## Abstract
Circom-tfhe-rs enables users to generate a TFHE circuit that corresponds to the arithmetization of a Circom circuit. In simpler terms, it translates Circom circuits into their TFHE equivalents. Circom code is compiled into an arithmetic circuit using circom-2-arithc and then translated gate by gate to the corresponding tfhe-rs operators.
## Security and Operational Assumptions
TFHE-rs uses padding bits (extra bits on the most significant side) to prevent precision loss or overflow when operations exceed the range of encoded values. Padding is consumed during operations like addition to accommodate carries, ensuring accurate results. Without padding, further computations may produce incorrect outcomes. By default, TFHE-rs ensures 128-bit security with its cryptographic parameters, but advanced users can customize configurations using tools like the [Lattice Estimator](https://github.com/malb/lattice-estimator). For more details, refer to the [TFHE-rs security documentation](https://docs.zama.ai/tfhe-rs/get-started/security_and_cryptography).
Follow these guidelines to ensure correctness when using TFHE-rs:
- Avoiding Overflow: Be cautious of potential overflows during operations. TFHE-rs allows defining padding bits to accommodate carries and prevent overflow errors.
- Key Management: Keep the client key confidential and do not share it. The server key can be distributed to enable homomorphic computations on the server side.
- Data Types: Choose appropriate data types (FheUint or FheInt) and bit sizes based on the expected range of your data to optimize performance and security.
##
## Input files
### Computation
A computation is defined by file: `circuit.circom`
* `circuit.circom` is an extended circom syntax, which supports more operators than the original circom. The list of supported operators can be found [here](https://github.com/namnc/circom-2-arithc/blob/e41f4bfa3b95010fe713a352b4df8e6af1e7c0ae/src/circuit.rs#L25-L37). For example, it could be
```
pragma circom 2.0.0;
template Main() {
signal input a;
signal input b;
signal input c <== 3;
signal output a_add_b <== a + b;
signal output a_mul_c <== a * c;
}
component main = Main();
```
## Workflow
These steps should be follwed to perform a computation
* Generate Tfhe-rs circuit
* Generate Tfhe-rs input
* Run TFHE with the Tfhe circuit and inputs
### 1. Generate Tfhe-rs Circuit
![Screenshot (64)](https://hackmd.io/_uploads/B1iI7Kimyx.png)
#### 1.1 Circom to bristol fashion circuit
[circom-2-arithc](https://github.com/namnc/circom-2-arithc) converts `circuit.circom` to `circuit.txt`, a bristol fashion circuit with gates sorted in topological order. With this order, all inputs to a gate are available when the gate is executed. We can safely execute gates in this order. For example (The image below is for illustrative purposes only and does not represent the accurate arithmetic of the Circom circuit)
![Screenshot (66)](https://hackmd.io/_uploads/BkY2LtiQke.png)
Another file circuit_info.json is also generated. It tells us how to interpret the wires in the bristol fashion circuit - which wires the inputs and outputs correspond to, and which wires are constants and can be assigned with values directly. For example,
```
{
"input_name_to_wire_index": {
"a": 1,
"b": 0
},
"constants": {
"0.c": {
"value": 3,
"wire_index": 2
}
},
"output_name_to_wire_index": {
"a_add_b": 3,
"a_mul_c": 4
}
}
```
This means that the wire with index 1 is the input `a`, the wire with index 0 is the input `b`, the wire with index 2 is the constant `c` with value `3`, the wire with index 3 is the output `a_add_b`, and the wire with index 4 is the output `a_mul_c`.
#### 1.2 Bristol fashion circuit to MP-SPDZ circuit
`generate_tfhe_circuit` generates a tfhe circuit under the TFHE project root. It translates each gate to their corresponding Mtfhe operator. For example, the above bristol fashion circuit is converted to the following tfhe circuit
```
let mut wires:[Option<FheUint8>; 5] = from_fn(|_| None);
// Inputs are assigned to their correct wire indices using circuit_info.json
wires[i]= ..
# wires[3] = a_add_b (2 1 1 0 3 AAdd) and is translated to + operator in tfhe-rs
wires[3] = Some(wires[1].as_ref().unwrap() + wires[0].as_ref().unwrap());
# wires[4] = a_mul_c (2 1 1 2 4 AMul) and is translated to * operator in tfhe-rs
wires[4] = Some(wires[1].as_ref().unwrap() + wires[2].as_ref().unwrap());
//Again with the help of circuit_info.json we decrypt and store output in output.json
for (name, index) in data.output_name_to_wire_index.into_iter() {
let index_usize = index as usize;
let decrypted_result: u8 = wires[index_usize]
.as_ref()
.unwrap()
.decrypt(&client_key);
output_raw.insert(name, decrypted_result);
}
let file = File::create("output.json")?;
serde_json::to_writer(file, &output_raw)?;
```
In the code above,
* `wires` is a list with 5 elements. According to `circuit_info.json`
* `wires[0]` is b
* `wires[1]` is a
* `wires[2]` is c
* `wires[3]` = `wires[1]` + `wires[0]` is the translation of the AAdd gate to the + operator in tfhe-rs. `wires[4]` = `wires[1]` * `wires[2]` is the translation of the AMul gate to the * operator in tfhe-rs.
* Decrypts the output ans stores it in `output.json`
### 2.Generate Tfhe-rs inputs
The user provides an `inputs.json` file, similar to the input format used in `circom-mp-spdz`. This file is then automatically converted into `input_struct.json` by the `main.py` script. The script handles the conversion and stores the input_struct.json file in the `circuit_name` folder,after the TFHE circuits are generated, it is then copied to the `outputs/circuit_name` and `outputs/circuit_name_raw` directories. This process is fully automated, requiring the user only to supply the inputs.json file. This allows the same inputs.json to be used for both MPC and TFHE workflows.
![Screenshot (63)](https://hackmd.io/_uploads/BJE_FdsmJe.png)
For Example , here `input_struct.json` for it's corresposing `input.json`
```
//input_struct.json
{
"in1": [4, 2, 3, 7, 7, 9, 7, 4, 4, 9],
"in2": 9
}
//input.json
{"0.in1[0]": 4, "0.in1[1]": 2, "0.in1[2]": 3, "0.in1[3]": 7, "0.in1[4]": 7, "0.in1[5]": 9, "0.in1[6]": 7, "0.in1[7]": 4, "0.in1[8]": 4, "0.in1[9]": 9, "0.in2": 9}
```
With this `input_struct.json`, the user can easily modify the circuit's inputs.
### 3.Run TFHE with Tfhe-rs circuit and inputs
With the generated circuit and inputs for tfhe-rs, parties can run MP-SPDZ and get the computation result.
For testing,
#### Go to the generated circuit root
```
cd outputs/circuit_name
```
Run the tfhe circuit using below command
```
cargo run --release
```
For additional information, you can refer to [this](https://github.com/Vishalkulkarni45/circom-tfhe-rs).