Zama 发布了 TFHE-rs v1.0 稳定版,该版本稳定了 x86 CPU 后端的高级 API,并确保向后兼容,提升了密码学安全性,优化了分布式协议的性能。此外,还发布了 TFHE-rs 手册,详细介绍了后端的实现,并简化了贡献流程。通过贡献 Zama Bounty Program 还可以获得奖励,此外,GPU 后端也在开发中。
/
2025 年 2 月 27 日
-
Jean-Baptiste Orfila
本月,Zama 发布了 TFHE-rs v1.0,这是 TFHE-rs 库的第一个稳定版本。这标志着一个重要的里程碑,稳定了 x86 CPU 后端的高级 API,同时确保了向后兼容性。
换句话说,你现在可以依赖 TFHE-rs API,而无需担心未来更新中的重大更改。
此版本中最重要的改进是密钥参数的改进,这增强了密码安全性,保持了性能,并优化了它们在分布式协议中的使用。此更新还引入了官方手册和简化的贡献流程,这两者都将在本文中详细介绍。
值得注意的是,计算错误的概率已降低到小于 2-128,同时保持了性能。实际上,这意味着发生错误的概率与打破现代密码学标准的可能性一样微不足道。
在发布 TFHE-rs v1.0 的同时,Zama 发布了其 TFHE-rs 手册 的第一版,详细介绍了后端中的所有实现。
TFHE-rs 手册涵盖:
另一点重要的是,与文档不同,该手册侧重于高斯噪声分布,与学术文献中使用的标准定义保持一致。
此版本中的一个核心增强是密码参数的改进,将计算错误的概率从小于 2-64 降低到小于 2-128。
虽然通常对用户隐藏,但密码参数是 TFHE-rs 的基础,可确保计算的安全性、效率和正确性。
直到最近,TFHE-rs 的标准参数集还保证了计算的正确性,错误概率低于 2-64——对于传统的客户端-服务器用例来说,这实际上可以忽略不计。然而,最近的研究表明,在可以访问加密和解密数据的场景中,可能会出现某些理论攻击。虽然使用以前的参数集在计算上仍然不可行——需要平均 263 次计算才能成功——但此更新进一步加强了针对此类可能性的安全性。
Zama 设计 TFHE-rs 旨在为所有应用程序提供最高级别的安全性。使用 TFHE-rs v1.0,密码参数已得到改进,以将计算错误概率降低到 2-128 以下,与标准密码安全级别保持一致,并确保即使在分布式协议中也具有鲁棒性。
通常,将失败概率从 2-64 降低到 2-128 至少会使计算时间增加一倍。但是,TFHE-rs 通过实现一种称为漂移缓解的新技术,将速度降低限制在 10% 左右(有关更多详细信息,请参见相关科学文章)。
由于 TFHE-rs 是 Zama 区块链协议的支柱,使开发人员能够使用 FHE 编写机密智能合约。这个新版本旨在更好地支持分布式协议——其中私钥和公钥的生成可能在多个用户之间共享——TFHE-rs v1.0 现在默认使用 TUniform 噪声分布。这种 Uniform 变体避免了高斯分布施加的约束。
对于喜欢传统方法的用户,基于高斯分布的密码参数仍然可用。
TFHE-rs 文档提供了有关选择密码参数和理解不同分布的全面指南。
为了获得更深入的技术见解,文档中还提供了使用新参数集执行的基准测试,包括整数运算和像 bootstrapping 这样的低级运算的基准测试。
下面是如何在客户端-服务器设置中使用 TFHE-rs 的一个简单演示。
为了使这个示例简单明了,我们有意省略了诸如公钥加密及其相关的零知识证明之类的高级功能——这些功能通常用于分布式环境中,以使用户可以共享一个通用的加密密钥并验证 ciphertext 是否已正确形成。
此示例侧重于核心工作流程,模拟客户端和服务器之间的交互:
use tfhe::prelude::*;
use tfhe::shortint::parameters::{COMP_PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_2_CARRY_2};
use tfhe::{
set_server_key, CompressedCiphertextListBuilder, FheAsciiString, FheBool, FheInt64, FheUint16,
FheUint2, FheUint32,
};
fn main() {
// Use aliases for ease of use, do not use aliases for production (not stable through time)
// 为了方便使用,可以使用别名,但不要在生产环境中使用别名(随时间推移不稳定)
let config = tfhe::ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2)
.enable_compression(COMP_PARAM_MESSAGE_2_CARRY_2)
.build();
// On the client side, generate the ClientKey, must remain SECRET
// 在客户端,生成 ClientKey,必须保密
let client_key = tfhe::ClientKey::generate(config);
// Also generate the ServerKey which will allow the server to perform computations, this one is
// sent to the server
// 还要生成 ServerKey,这将允许服务器执行计算,这个密钥被发送到服务器
let server_key = tfhe::ServerKey::new(&client_key);
// Encrypt some values required by service provider
// 加密服务提供商需要的一些值
let ct1 = FheUint32::encrypt(17_u32, &client_key);
let ct2 = FheInt64::encrypt(-1i64, &client_key);
let ct3 = FheBool::encrypt(false, &client_key);
let ct4 = FheUint2::encrypt(3u8, &client_key);
let ct5 = FheAsciiString::encrypt("1.0!", &client_key);
// On the server side, once the server key has been received, set it as the active key
// 在服务器端,一旦收到服务器密钥,就将其设置为活动密钥
set_server_key(server_key);
// The server does some computations without seeing the data
// 服务器在看不到数据的情况下进行一些计算
let ct1_res = ct1 + 25;
let ct2_res = 43 + ct2;
let ct3_res = ct3 & true;
let ct4_res = ct4 - 1;
let ct5_res = ct5.len().into_ciphertext();
// We can compress the data to send or store smaller amounts of data to the client
// 我们可以压缩数据以发送或存储更少的数据量到客户端
let compressed_list = CompressedCiphertextListBuilder::new()
.push(ct1_res)
.push(ct2_res)
.push(ct3_res)
.push(ct4_res)
.push(ct5_res)
.build()
.unwrap();
// On the client side after receiving the compressed data
// 在客户端收到压缩数据后
let a: FheUint32 = compressed_list.get(0).unwrap().unwrap();
let b: FheInt64 = compressed_list.get(1).unwrap().unwrap();
let c: FheBool = compressed_list.get(2).unwrap().unwrap();
let d: FheUint2 = compressed_list.get(3).unwrap().unwrap();
let e: FheUint16 = compressed_list.get(4).unwrap().unwrap();
let a: u32 = a.decrypt(&client_key);
assert_eq!(a, 42);
let b: i64 = b.decrypt(&client_key);
assert_eq!(b, 42);
let c = c.decrypt(&client_key);
assert!(!c);
let d: u8 = d.decrypt(&client_key);
assert_eq!(d, 2);
let e: u16 = e.decrypt(&client_key);
assert_eq!(e, 4);
// The compressed data can be reused by the server if it kept it on disk
// 如果服务器将压缩数据保留在磁盘上,则可以重复使用
let recovered_a: FheUint32 = compressed_list.get(0).unwrap().unwrap();
let new_a = recovered_a << 4u32;
// The result can be sent uncompressed to the Client, which can also decrypt this new result
// 结果可以以未压缩的形式发送到客户端,客户端也可以解密这个新结果
let new_a: u32 = new_a.decrypt(&client_key);
assert_eq!(new_a, a << 4);
}
在 Zama,作为一家开源密码学公司不仅仅是一个要求,更是我们积极拥抱的东西。开放性推动了创新、协作和我们技术的不断改进。
TFHE-rs 的构建考虑到了这种理念,欢迎通过两种主要方式进行贡献:
1. 通过 Zama Bounty Program 为 TFHE-rs 做出贡献:一次一个挑战,推动 FHE 的发展
Zama Bounty Program 奖励开发人员解决推动 TFHE-rs 前进的技术挑战。每个季度都会开放一个新的 TFHE-rs bounty,参与者的解决方案通常会导致库的重大改进。
最近的一个例子是 homomorphic string 功能,它最初是作为 bounty 贡献而开始的,后来被集成到主存储库中。感谢这个添加,用户现在可以运行以下代码来检查一个 substring 是否包含在另一个字符串中:
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, ClearString, ConfigBuilder, FheAsciiString};
fn main() {
let config = ConfigBuilder::default().build();
let (cks, sks) = generate_keys(config);
set_server_key(sks);
// Encrypt without padding, does not hide the string length and has better performance
// 使用无填充加密,不隐藏字符串长度,并具有更好的性能
let string = FheAsciiString::try_encrypt("TFHE-rs rocks!", &cks).unwrap();
// Encrypt with padding, hide the true length of the string
// 使用填充加密,隐藏字符串的真实长度
let search_string = FheAsciiString::try_encrypt_with_padding("is meh", 1, &cks).unwrap();
// We can also use clear strings
// 我们也可以使用 clear strings
let clear_search_string = ClearString::new("rocks".to_string());
// Does our initial string contain "is meh"?
// 我们的初始字符串是否包含 "is meh"?
let does_not_contain = string.contains(&search_string);
// Does our initial string contain "rocks"?
// 我们的初始字符串是否包含 "rocks"?
let contains = string.contains(&clear_search_string);
// Decrypt
// 解密
let decrypted_does_not_contain = does_not_contain.decrypt(&cks);
let decrypted_contains = contains.decrypt(&cks);
// Check all worked properly
// 检查是否一切正常
assert!(!decrypted_does_not_contain);
assert!(decrypted_contains);
}
可以在字符串文档中找到此新功能的优点的详细比较。
其他几个 bounty 驱动的贡献也已集成到 TFHE-rs 中,包括 homomorphic SHA-256:
Bounty Program 的下一个季度即将开始!关注官方 Bounty Program 存储库参与。期待你的贡献!
2. 直接为 TFHE-rs 做出贡献:构建、改进和创新
我们引入了一个简化的贡献流程,使开发人员和研究人员可以更轻松地向 TFHE-rs 添加新功能和改进。无论你是构建应用程序还是尝试新的原型,都可以按照以下步骤将你的工作集成到库中:
一旦被接受,你的贡献将像库中的任何其他功能一样,随着时间的推移得到维护。
展望未来,TFHE-rs 正在朝着两个关键目标发展:
未找到项目。
Concrete ↗ Concrete ML ↗ FHEVM ↗ TFHE-rs ↗
博客 文档 ↗ GITHUB ↗ FHE 资源 ↗ 研究论文 ↗ Bounty Program ↗ FHE 状态操作系统
与专家交谈 联系我们 X Discord Telegram 所有社区渠道
在电子时代,隐私对于一个开放的社会是必要的。隐私不是秘密。私事是不想让全世界知道的事,但秘密是不想让任何人知道的事。隐私是有选择地向世界展示自己的力量。如果双方有某种交易,那么每一方都会记住他们的互动。每一方都可以谈论自己对这件事的记忆;谁能阻止它呢?可以制定法律来禁止它,但是言论自由甚至比隐私更重要,对于一个开放的社会来说,言论自由至关重要;我们不寻求限制任何言论。如果许多人在同一个论坛上一起发言,每个人都可以对所有其他人发言,并将关于个人和其他方的信息汇总在一起。电子通信的力量使这种群体言论成为可能,并且它不会仅仅因为我们可能想要它而消失。由于我们渴望隐私,我们必须确保交易的每一方只了解该交易直接必需的信息。由于任何信息都可以被谈论,我们必须确保我们尽可能少地透露信息。在大多数情况下,个人身份并不重要。当我在商店购买杂志并给店员现金时,没有必要知道我是谁。当我要求我的电子邮件提供商发送和接收消息时,我的提供商不需要知道我在和谁说话或我说什么或别人对我说什么;我的提供商只需要知道如何将消息发送到那里以及我欠他们多少费用。当我的身份被交易的底层机制揭示时,我就没有隐私。我不能在这里有选择地展示自己;我必须始终展示自己。因此,开放社会中的隐私需要匿名交易系统。到目前为止,现金一直是主要的此类系统。匿名交易系统不是秘密交易系统。匿名系统赋予个人在需要时以及仅在需要时才透露其身份的权力;这是隐私的本质。开放社会中的隐私也需要密码学。如果我说了一些话,我希望只有我打算让其听到的人才能听到。如果我的言论内容对全世界开放,我就没有隐私。加密是表达对隐私的渴望,而使用弱密码进行加密则表示对隐私的渴望不太强烈。此外,当默认设置为匿名时,为了有保证地显示自己的身份,需要使用密码签名。我们不能期望政府、公司或其他大型、没有面孔的组织出于仁慈而赋予我们隐私。谈论我们对他们有利,我们应该期望他们会谈论。试图阻止他们的言论是与信息现实作斗争。信息不仅仅是想自由,它渴望自由。信息会扩展以填充可用的存储空间。信息是谣言的年轻、更强大的表弟;信息比谣言跑得更快,拥有更多的眼睛,知道更多,并且比谣言理解得更少。如果我们希望拥有任何隐私,我们必须捍卫自己的隐私。我们必须走到一起并创建允许进行匿名交易的系统。几个世纪以来,人们一直通过耳语、黑暗、信封、关闭的门、秘密握手和信使来捍卫自己的隐私。过去的技术不允许强大的隐私,但是电子技术可以。我们密码朋克致力于构建匿名系统。我们正在使用密码学、匿名邮件转发系统、数字签名和电子货币来捍卫我们的隐私。密码朋克编写代码。我们知道必须有人编写软件来捍卫隐私,并且由于除非我们所有人都这样做,否则我们无法获得隐私,因此我们将编写它。我们发布我们的代码,以便我们的密码朋克同伴可以练习和使用它。我们的代码供世界各地的人免费使用。如果你不认可我们编写的软件,我们并不太关心。我们知道软件无法被销毁,并且一个广泛分散的系统无法被关闭。密码朋克谴责对密码学的法规,因为加密从根本上来说是一种私人行为。事实上,加密行为将信息从公共领域移除。即使是反对密码学的法律也只能达到一个国家的边界和暴力的手臂。密码学将不可避免地在全球范围内传播,随之而来的是它使之成为可能的匿名交易系统。为了使隐私得到广泛应用,它必须成为社会契约的一部分。人们必须走到一起并部署这些系统以实现共同利益。隐私的范围仅限于一个社会中同伴的合作。我们密码朋克寻求你的问题和疑虑,并希望我们可以与你互动,以免我们欺骗自己。但是,我们不会因为某些人可能不同意我们的目标而改变我们的路线。密码朋克正在积极致力于使网络对于隐私更加安全。让我们一起加快步伐前进。作者:Eric Hughes。1993 年 3 月 9 日。
- 原文链接: zama.ai/post/tfhe-rs-v1-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!