atoranzo/euro-digital-zk

GitHub: atoranzo/euro-digital-zk

基于 STARK 零知识证明的数字欧元隐私要求参考实现,解决持有上限的可验证执行与离线支付双花身份追溯问题。

Stars: 0 | Forks: 0

# 数字欧元:两项隐私要求的参考实现 **以毫秒为测量单位,从密码学层面强制执行持有上限和离线支付的成本。** *[西班牙语版本](./README-ES.md)* 这**不是数字欧元**。这是目前正在谈判的法规中两个具体要求的参考实现,并测量了其成本,以便关于技术可行性的辩论能以具体数据说话。 基于零知识证明 (STARK/FRI) 构建,**无需可信设置仪式** (trusted setup ceremony),架构本身具备抗量子安全性。 ## ⚠️ 不隶属于 ECB 或 Eurosystem 这是独立的工作。它不响应任何申请征集,未受任何欧洲机构审查,不应被解读为官方提案。 完整的规范性溯源见 [`REFERENCIAS.md`](./REFERENCIAS.md)。 ## 两项要求 ### 1. 可证实的持有上限 **要求。** 数字欧元法规设想了每人持有金额的上限——讨论过的数字约为 3,000 欧元——作为防止商业银行存款大规模流失的保障措施。 **问题。** 检查上限需要知道余额,这会破坏隐私。 **实现内容。** 结算电路证明转账后接收方的余额**不超过上限**,而无需透露余额。每次收款时都会检查,而非按需检查。 ``` range_check(cap − resulting_balance) ≥ 0 ``` 如果余额超过上限,减法将在有限域 (finite field) 中发生回绕 (wrap around) 且无法通过范围检查。证明将无法生成。 ### 2. 具备类现金隐私的离线支付 **要求。** 通过设备直连进行离线支付,其中*只有付款方和收款方知道细节*。 **问题。** 离线状态下无法查询支付注册表。**没有任何东西能阻止双花 (double-spending)**,也没有任何密码学证明能解决这个问题——所需的信息根本不可用。 **实现内容。** 双花并未被阻止。而是使其**暴露违规者的身份**。 这是 **Chaum, Fiat 和 Naor (1988)** 提出的离线电子现金方案,适配了零知识证明。 每张票据 (note) 都绑定了持有者身份 `u` 和一个随机值 `r`,两者均为 **256 位**(四个域元素)。支付时,商家发出一个不可预测的挑战 `c`,付款方揭示: ``` y[i] = u[i] + r[i] · c for i = 0..4 ``` 这代表**四个点**,分别来自四条线 `f_i(x) = u[i] + r[i]·x`。 | | | |---|---| | 一个点 | 不透露任何信息:`y` 看起来是随机的,因为 `r` 是随机的 | | **两个点** | **能确定这条线,其截距即为 `u`** | **具备类现金隐私,除非你作弊。** ## 测试结果 ``` 121 tests, all passing on stable Rust ``` | 测试 | 验证内容 | |---|---| | `spending_twice_reveals_the_identity` | 两个点确定一条线:身份被恢复 | | `spending_once_reveals_nothing` | 一个点与**任何**身份都保持一致 | | `the_same_challenge_twice_reveals_nothing` | 该方案的漏洞,被编写为测试 | | `a_forged_revelation_is_rejected` | 在 `y` 上撒谎会使双花检测失效 | | `receiving_one_cent_above_the_holding_limit_is_rejected` | 超出一分钱也会被拒绝 | | `receiving_exactly_up_to_the_holding_limit_verifies` | 精确的边界值有效 | | `the_full_flow_detects_a_double_spend_and_identifies_the_offender` | 端到端:两个商家,一张票据,违规者被识别 | | `honest_payers_are_never_identified` | 五次合法支付,无人被识别 | | `one_distinct_challenge_among_many_is_enough` | 违规者必须控制**每一个**挑战才能保持匿名 | 第三个测试值得注意:**如果付款方能迫使在两个商家处遇到相同的挑战,他们就能进行双花而不被识别**。生成不可预测的挑战是商家设备在本电路之外的责任。 ## 测量成本 Release 构建,单台机器,单次运行。适用于数量级比较,**不能作为基准测试**。 ### 离线支付 | | | |---|---| | 在付款方设备上生成证明 | **28.4 ms** | | 在商家终端上验证 | **1.0 ms** | | 证明大小 | 28 KB | | **验证 / 证明** | **3.4%** | | 在无网络连接下累积 100 笔支付 | 需要存入 2.7 MB 数据 | **在手机上 28 毫秒是无法察觉的。** 这将一个合理的疑问——*你真的能在手机上生成零知识证明吗?*——转化为具体数据。 而**在终端上 1 毫秒**意味着商家什么都感觉不到。 ### 作为对比 前身项目的在线结算电路需要 **620 ms** 来生成证明,并产生 **62 KB** 的证明。离线电路**速度快 22 倍且体积缩小了一半**,因为它是一个简单得多的电路:一条通道 (lane),一次 Merkle 攀升,无需复式记账。 在计算层面,离线支付是廉价的部分。 ### 成本与金额无关 | 金额(分) | 证明生成 | |---|---| | 1 | 28.3 ms | | 100 | 29.0 ms | | 5,000 | 27.3 ms | | 14,999 | 24.4 ms | 波动范围:**1.19 倍**,这属于误差噪声。 这是一个**隐私**属性,而非性能属性:如果证明时间随金额变化,观察者通过测量延迟就能推断出金额大小,而无需破解任何证明。 ⚠️ 四个样本是微弱的证据。要排除侧信道攻击 (side-channel),需要进行尚未执行的分析。 ## ⚠️ 这不能做什么 - **欺诈仍然会发生。** 第二个收到支付的商家在对账 (reconciliation) 前会蒙受损失。身份暴露是一种威慑和事后追责手段,**而非预防**。这是离线支付固有的特性。 - **没有溢出流转机制 (waterfall mechanism)。** 法规设想将超额持有路由到关联的支付账户中。此项未实现,因此向已满账户进行合法支付目前会被拒绝,而不是被处理。 - **没有票据发行层和状态层。** 实现了对账功能;但没有实现发行票据。 - **未经任何人审计。** ## 第二个缺陷:64 位身份 第一版使用**单一域元素**表示身份。在 Goldilocks 域中这是 64 位,而找到一次碰撞只需 2³² 次操作——在计算上微不足道。 其后果将比隐私泄露更严重。攻击者可以搜索与无辜者碰撞的身份,故意进行双花,并**让对账指向那个无辜的人**。只需 2³² 次操作就能陷害他人。 现在身份已改为完整的 256 位摘要 (digest),并且揭示的是四个点而不是一个——四条独立的线,共同恢复出完整身份。成本:约束数从 45 增加到 63。可忽略不计。 **这个确切的问题在前身项目中已经作为第 2 号发现被记录在案。** 在这里它之所以再次出现,是因为从头开始编写电路时没有查阅已记录的文档。 这说明了为什么发现的问题应当存活在**代码中**——作为约束或测试——而不仅仅是在文档中。现在有一个测试 `the_identity_is_a_full_digest`,如果有人把它“简化”回去,测试就会失败。 ## 发现的一个设计缺陷——以及是什么发现了它 离线电路的第一版**没有**公开票据承诺 (note commitment)。算术是经过验证的:两次揭示确实能恢复身份。 但对账是**按票据**对支付进行分组的。如果没有公开的承诺,没人能知道哪两次揭示属于同一张票据——因此双花检测在实践中是不可能的,无论算术多么正确。 这个问题只有在编写**端到端流程测试**时才浮出水面:两个商家,一张票据,以及随后进行对账的人。针对算术的单元测试此前全都通过了。 **公开承诺并不会破坏隐私。** 两张不同票据的支付具有不同的承诺,且不可关联。只有对*同一张*票据的两次支付才共享一个承诺——而这正是必须被检测到的。这就是经典离线电子现金的工作原理:银行在存款时看到序列号,重复出现即意味着欺诈。 ## 为什么用 STARK,而不是更快的方案 这项工作建立在一个前身项目的基础上,在该项目中,**同一个结算电路在五种证明系统中实现**,并在相同条件下进行了测量: [ZK-SSL](https://github.com/atoranzo/ZK-SSL-ZK-Sovereign-Settlement-Layer-)。 | | Groth16 | Halo2/IPA | **STARK/FRI** | PLONK/KZG | |---|---|---|---|---| | 可信仪式 (Trusted ceremony) | 每个电路需一次 | 无 | **无** | 通用的 | | 证明生成 | 422 ms | 4.86 s | **39 ms** | 6.85 s | | 验证 | 5 ms | 91 ms | **1 ms** | 8 ms | | 证明大小 | **192 B** | 4,096 B | 36.7 KB | 1,008 B | | 抗量子 (Post-quantum) | 否 | 否 | **是** | 否 | **尽管 Groth16 的证明体积小 320 倍且速度更快,但它被否决了。** 原因对中央银行来说应该很重要:Groth16 和 PLONK/KZG 需要一个可信设置仪式 (trusted setup ceremony)。如果参与者串谋并保留了密钥,**他们就可以伪造证明并凭空创造货币而不留下任何可检测的痕迹**。伪造的证明能通过验证;事后没有任何检测手段。 对于一个职责包含货币主权的机构来说,这种依赖性是永久的——它不会过期——也是不可审计的——你无法验证密钥是否已被销毁。 ## 一项技术发现 实现揭示机制的过程暴露了一些在 AIR 相关资料中未记录的现象: **在结构上保持为常数的列上的约束,其阶数 (degree) 为零,无论其代数形式如何。** 揭示公式 `y − (u + r·c)` 看起来像是 2 阶的,因为它将两列相乘。但这四列都是常数——传输约束强制了这一点——而常数的乘积依然是常数。 产生这种反差且能将其说明白的是:布尔检查 `b·(b−1)` 同样将两列相乘,并且**确实**是 2 阶的,因为该位 (bit) 的值会**随行变化**。 区别不在于表达式。而在于这些列是否会发生变化。 ## 复现 只需稳定的 Rust 版本。无需外部工具链。 ``` git clone https://github.com/atoranzo/euro-digital-zk cd euro-digital-zk cargo test -p zk-circuits --release ``` ## 规范性溯源 每一部分都实现了来自特定公开文档的一项要求。 完整参考见 [`REFERENCIAS.md`](./REFERENCIAS.md)。 | 模块 | 要求 | 文档 | |---|---|---| | 持有上限 | 每位用户的持有金额上限 | `COM(2023) 369 final` | | 离线支付 | 离线支付,类现金隐私 | `COM(2023) 369 final` | | 选择性披露 | 免受中介机构窥探的隐私 | ECB 公众咨询,2021年 | 截至 2026 年 7 月的立法状态:欧洲议会已于 **2026 年 7 月 9 日** 批准开始与理事会进行谈判(416 票赞成,169 票反对,22 票弃权)。持有上限和隐私保证仍悬而未决。预计首次发行目标:**2029 年**。 ## 引用 ``` Toranzo Portela, A. (2026). Digital Euro: reference implementation of two privacy requirements — provable holding limits and offline payment with double-spend identity revelation. [Software] https://github.com/atoranzo/euro-digital-zk ``` 底层方案: ``` Chaum, D., Fiat, A., Naor, M. (1990). Untraceable Electronic Cash. Advances in Cryptology — CRYPTO '88. LNCS vol 403. Springer. ``` ## 许可证 MIT 或 Apache-2.0,任您选择。
标签:STARK, 区块链, 可视化界面, 后量子密码学, 密码学, 手动系统调用, 数字货币, 通知系统, 零知识证明