TFHE使用流程
TFHE-rs是Zama用Rust从头实现的TFHE算法,与C++版本的TFHE同态密码库没有承接关系。在Rust中使用TFHE-rs的方式很简单直观,另外官方也提供了C的API接口,方便绑定到其他语言使用。
生成密钥
首先导入thfe中的模块,并使用默认参数生成密钥对。
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint8};
fn main() {
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
set_server_key(server_key);
// Do stuff with generated keys
}加密数据
加密两个输入整数,并得到对应密文。在Rust中,为避免数据移动,借用密文数据。
let clear_a = 35u8;
let clear_b = 7u8;
// Encryption
let a = FheUint8::encrypt(clear_a, &client_key);
let b = FheUint8::encrypt(clear_b, &client_key);
// Take a reference to avoid moving data when doing the computation
let a = &a;
let b = &b;
计算加密数据
大部分加密数据可以直接使用Rust内置操作符运算。
// Computation using Rust's built-in operators
let add = a + b;
let sub = a - b;
let mul = a * b;
let div = a / b;
let rem = a % b;
let and = a & b;
let or = a | b;
let xor = a ^ b;
let neg = -a;
let not = !a;
let shl = a << b;
let shr = a >> b;
// Comparison operations need to use specific functions as the definition of the operators in
// rust require to return a boolean which we cannot do in FHE
let eq = a.eq(b);
let ne = a.ne(b);
let gt = a.gt(b);
let lt = a.lt(b);
解密结果
解密密文计算的结果,并通过Rust的assert_eq!宏验证结果。
// Decryption and verification of proper execution
let decrypted_add: u8 = add.decrypt(&client_key);
let clear_add = clear_a + clear_b;
assert_eq!(decrypted_add, clear_add);
let decrypted_sub: u8 = sub.decrypt(&client_key);
let clear_sub = clear_a - clear_b;
assert_eq!(decrypted_sub, clear_sub);
let decrypted_mul: u8 = mul.decrypt(&client_key);
let clear_mul = clear_a * clear_b;
assert_eq!(decrypted_mul, clear_mul);
let decrypted_div: u8 = div.decrypt(&client_key);
let clear_div = clear_a / clear_b;
assert_eq!(decrypted_div, clear_div);
let decrypted_rem: u8 = rem.decrypt(&client_key);
let clear_rem = clear_a % clear_b;
assert_eq!(decrypted_rem, clear_rem);
let decrypted_and: u8 = and.decrypt(&client_key);
let clear_and = clear_a & clear_b;
assert_eq!(decrypted_and, clear_and);
let decrypted_or: u8 = or.decrypt(&client_key);
let clear_or = clear_a | clear_b;
assert_eq!(decrypted_or, clear_or);
let decrypted_xor: u8 = xor.decrypt(&client_key);
let clear_xor = clear_a ^ clear_b;
assert_eq!(decrypted_xor, clear_xor);
let decrypted_neg: u8 = neg.decrypt(&client_key);
let clear_neg = clear_a.wrapping_neg();
assert_eq!(decrypted_neg, clear_neg);
let decrypted_not: u8 = not.decrypt(&client_key);
let clear_not = !clear_a;
assert_eq!(decrypted_not, clear_not);
let decrypted_shl: u8 = shl.decrypt(&client_key);
let clear_shl = clear_a << clear_b;
assert_eq!(decrypted_shl, clear_shl);
let decrypted_shr: u8 = shr.decrypt(&client_key);
let clear_shr = clear_a >> clear_b;
assert_eq!(decrypted_shr, clear_shr);
let decrypted_eq = eq.decrypt(&client_key);
let eq = clear_a == clear_b;
assert_eq!(decrypted_eq, eq);
let decrypted_ne = ne.decrypt(&client_key);
let ne = clear_a != clear_b;
assert_eq!(decrypted_ne, ne);
let decrypted_gt = gt.decrypt(&client_key);
let gt = clear_a > clear_b;
assert_eq!(decrypted_gt, gt);
let decrypted_lt = lt.decrypt(&client_key);
let lt = clear_a < clear_b;
assert_eq!(decrypted_lt, lt);
}TFHE-rs生态
围绕TFHE-rs,Zama构建了:
- fhEVM,一个支持链上智能合约、链下进行加密数据运算的符号运算框架,扩展了EVM的可编程隐私保护。
- Concrete及Concrete ML,自动把Python中的运算编译成加密数据运算的框架,支持保密数据上训练和推理机器学习模型。
此外,一些合作伙伴也基于TFHE-rs或fhEVM扩展了全同态密码在不同场景的应用。

fhEVM框架
Zama主要通过网关服务收取费用,所有的费用都以 $ZAMA 代币支付。
Fhenix L2网络
计划以FHE-Rollup锚定以太坊主网,提供比ZK-Rollup扩容更强的隐私保护。
设计和实现
TFHE-rs采用分层的架构设计,从下往上依次是:
- 硬件抽象层,包括CPU、GPU和HPU上FFT、NTT和CSPRNG实现。
- 核心密码学层,包括参数定义、LWE/GLWE/RLWE、密钥切换和可编程自举。
- 细粒度API层,暴露
boolean、shortint和integer等模块接口。 - 高层次API层,提供密钥管理和包含
FheString、FheInt、FheUint和FheBool等密文类。

数学结构
TFHE使用的环面(Torus)上的元素定义在实数环面上,即所有元素都取模后在区间上。为便于运算,这些浮点数都用定点整数表示。相关的文档说明如下。
//! Converting to torus values.
//!
//! The theory behind some of the homomorphic operators of the library, uses the real torus
//! $\mathbb{T} = \mathbb{R} / \mathbb{Z}$, or the set or real numbers modulo 1 (elements of the
//! torus are in $[0,1)$). In practice, floating-point number are not well suited to performing
//! operations on the torus, and we prefer to use unsigned integer values to represent them.
//! Indeed, unsigned integer can be used to encode the decimal part of the torus element with a
//! fixed precision.
//!
//! Still, in some cases, we may need to represent an unsigned integer as a torus value in
//! floating point representation. For this reason we provide the [`IntoTorus`] and [`FromTorus`]
//! traits which allow to go back and forth between an unsigned integer representation and a
//! floating point representation.高层次API接口
高层次API接口提供开发者友好的接口,屏蔽复杂密码学实现,让开发者集中精力在加密数据计算上。
密文数据类型
高层次API接口主要提供加密数据类型,包括无符号整型和带符号整型:
pub use crate::high_level_api::booleans::{
CompressedFheBool, FheBool, FheBoolConformanceParams, SquashedNoiseFheBool,
};expand_pub_use_fhe_type!(
pub use crate::high_level_api::integers{
FheUint2, FheUint4, FheUint6, FheUint8, FheUint10, FheUint12, FheUint14, FheUint16,
FheUint32, FheUint64, FheUint128, FheUint160, FheUint256, FheUint512, FheUint1024,
FheUint2048,
FheInt2, FheInt4, FheInt6, FheInt8, FheInt10, FheInt12, FheInt14, FheInt16, FheInt32,
FheInt64, FheInt128, FheInt160, FheInt256, FheInt512, FheInt1024, FheInt2048,
};
);还包括数组类型:
pub use cpu::{
CpuFheBoolArray, CpuFheBoolSlice, CpuFheBoolSliceMut, CpuFheIntArray, CpuFheIntSlice,
CpuFheIntSliceMut, CpuFheUintArray, CpuFheUintSlice, CpuFheUintSliceMut, FheBoolId,
};
pub use dynamic::{
FheBoolArray, FheBoolSlice, FheBoolSliceMut, FheIntArray, FheIntSlice, FheIntSliceMut,
FheUintArray, FheUintSlice, FheUintSliceMut,
};参数配置和密钥管理
对于密钥管理,高层次API提供以下类型:
tfhe::ClientKey,客户端密钥,用于加密和解密;tfhe::ServerKey,服务端密钥,用户同态操作;tfhe::generate_keys(),生成密钥对。
此外,还提供tfhe::ConfigBuilder作为参数配置。
使用方法
使用高层次API通常以下面的步骤进行:
- 配置参数:通过
tfhe::ConfigBuilder设置参数; - 密钥生成:调用
tfhe::generate_keys()生成密钥; - 设置服务端密钥:通过上一步的客户端密钥生成一个服务端密钥,也可以反序列化接受的密钥并通过
thfe::set_server_key()设置; - 加密:用客户端密钥加密数据;
- 计算:在密文上执行密文运算;
- 解密:用客户端密钥解密。
一个最简单的使用高层次API的代码片段:
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8};
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
set_server_key(server_key);
let encrypted_a = FheUint8::encrypt(10, &client_key);
let encrypted_b = FheUint8::encrypt(5, &client_key);
let encrypted_result = encrypted_a + encrypted_b;
let decrypted_result: u8 = encrypted_result.decrypt(&client_key);细粒度API接口
细粒度API提供更多控制,是扩展TFHE的主要接口。
不像高层次API生产环境可用并保持稳定,细粒度API更多是内部模块使用,并且可能经常会改变。因此,大部分情况下都不推荐直接使用细粒度API开发应用。 但有一些场景下,如要提供精细的控制(性能测试等)和增加新的后端支持(如ASIC后端),则只能通过细粒度API完成。
这一层提供的API主要包括:
- 布尔类型API(
tfhe::boolean模块),单个数据位的加密数据上逻辑运算; - 小整数类型API(
tfhe::shortint模块),支持最高8位二进制整数的密文运算,支持自举,无操作次数限制; - 整数类型API(
tfhe::integer模块),构建在小整数API之上,支持大整数运算。
除了上面导出的几个模块外,不同的后端如GPU和HPU也导出了类似的模块,便于直接使用与后端相关的操作。这样的模块包括tfhe::integer::gpu和tfhe::integer::hpu。
布尔类型和小整数类型并没有除CPU后端外的定义。
核心密码API接口
核心密码API提供最底层的接口,包含密码原语和TFHE同态密码方案的实现。其中关键组件由:
- FFT实现和数学运算;
- LWE/GLWE密文原语;
- 可编程自举算法;
- 参数管理和其他密码学原语。
使用这一层的常见用法如下。
use tfhe::core_crypto::prelude::*;
// Access to low-level cryptographic primitives执行后端
HPU后端
从逻辑看,TFHE-rs对HPU指令分成两层抽象:
- 整数操作(Integer Operations或IOp),IOp是TFHE-rs定义的高层次操作,通过PCIe发送到HPU控制器,表示一些对加密数据的操作。
- 数位操作(Digit Operations或DOp),DOp则对应着HPU处理单元的微代码指令。
TFHE-rs代码库通过大量的条件编译完成对不同后端的支持。典型的代码片段如:
impl Config {
#[cfg(feature = "hpu")]
pub fn from_hpu_device(hpu_device: &tfhe_hpu_backend::prelude::HpuDevice) -> Self {
let pbs_params =
crate::shortint::parameters::KeySwitch32PBSParameters::from(hpu_device.params());
ConfigBuilder::with_custom_parameters(pbs_params).build()
}
pub fn public_key_encryption_parameters(
&self,
) -> Result<crate::shortint::parameters::CompactPublicKeyEncryptionParameters, crate::Error>
{
self.inner.public_key_encryption_parameters()
}
}扩展后端
增加新的后端支持需要大量改动包括细粒度和高层次API和模块。