09. Plonky2:Goldilocks、宽门 PLONK 与 FRI 多项式测试
版本口径:协议公式主要对应 Polygon Zero 的 2022 年 Plonky2 技术稿;实现参数对应已弃用仓库主分支快照
5d9da5a。二者不一致处会显式指出。
1. 先把名字说准确
Plonky2 不是“原始 PLONK 换了一套 Rust 实现”,也不是传统意义上以 KZG 为后端的 PLONK。
更准确的分层是:
1
2
3
4
5
6
7
8
9
10
11
关系 / 程序
↓
宽 trace 上的 PLONKish custom gates
↓
PLONK permutation argument 处理 copy constraints
↓
约束合并与 quotient identity
↓
基于 Merkle + FRI 的批量多项式测试
↓
Fiat–Shamir 非交互化
因此:
\[\boxed{ \text{Plonky2} = \text{PLONKish arithmetization} + \text{DEEP/FRI-style polynomial testing}. }\]它从 PLONK 继承的是:
- 一行一个 gate instance 的电路视图;
- wire columns、selector/constants;
- permutation grand product;
- quotient polynomial identity;
- 随机点 $\zeta$ 上的约束检查。
它没有采用经典 PLONK 的 KZG opening,而是:
- 对低度扩展后的 evaluation vectors 建 Merkle tree;
- 用 FRI 检查承诺向量接近低次多项式;
- 用 DEEP quotient 把“声称的点值”绑定到这些向量。
flowchart LR
A["CircuitBuilder<br/>变量与 copy constraints"] --> B["宽 PLONKish trace<br/>custom gates"]
B --> C["wire / selector / sigma 多项式"]
C --> D["permutation Z<br/>partial products"]
D --> E["约束随机合并 C_j"]
E --> F["quotient q_j = C_j / Z_H"]
F --> G["LDE + Merkle caps"]
G --> H["DEEP batch + FRI"]
H --> I["非交互 argument"]
2. Goldilocks 域为什么是核心选择
2.1 模数
Plonky2 的基础域是
\[\mathbb F_p, \qquad p=2^{64}-2^{32}+1.\]这个素数通常称为 Goldilocks prime。它同时满足:
- 域元素可装进一个 64-bit word;
- $p-1=2^{32}(2^{32}-1)$,有很大的二次幂子群;
- 模数的特殊形状使 128-bit 乘积能快速约减。
由
\[p=2^{64}-2^{32}+1\]可得
\[2^{64}\equiv 2^{32}-1\pmod p\]以及
\[2^{96} =2^{32}2^{64} \equiv 2^{32}(2^{32}-1) =2^{64}-2^{32} \equiv -1 \pmod p.\]2.2 128-bit 乘积的特殊约减
把一个不超过 128 bit 的整数写为
\[n=n_0+2^{64}n_1+2^{96}n_2,\]其中 $n_0$ 为低 64 bit,$n_1,n_2$ 各为 32 bit。则
\[\begin{aligned} n &\equiv n_0+(2^{32}-1)n_1-n_2 \pmod p. \end{aligned}\]右侧只需:
- 位移;
- 加减;
- 根据 carry/borrow 做一次条件修正。
这比对任意 64-bit 素数做通用 Montgomery reduction 更贴近 CPU 原生指令。真正的性能还取决于 lazy reduction、SIMD、内存布局与具体微架构;“模数形状好”不是单独的 benchmark 结论。
2.3 二进制 FFT 友好性
因为
\[2^{32}\mid p-1,\]$\mathbb F_p^*$ 中存在阶为 $2^{32}$ 的元素,所以可直接构造最大规模 $2^{32}$ 的 two-adic 乘法子群。
对大小为 $N=2^m$、$m\le 32$ 的 trace,可选择
\[H=\langle\omega\rangle, \qquad |H|=N,\]并通过 radix-2 FFT 做:
- 插值;
- low-degree extension;
- quotient-domain evaluation;
- FRI folding 所需的 coset 运算。
这说明 Goldilocks 的优势不是只有“64 bit 小域”,而是:
\[\boxed{ \text{小字长} + \text{特殊约减} + \text{高 two-adicity}. }\]2.4 为什么还需要扩域
64-bit 基础域不足以让每个随机线性组合错误都自动小到可忽略。Plonky2 在需要较大 challenge space 的位置使用二次扩域
\[\mathbb E = \mathbb F_p[\varphi]/(\varphi^2-7).\]任意扩域元素写为
\[a+b\varphi, \qquad a,b\in\mathbb F_p, \qquad \varphi^2=7.\]其乘法为
\[(a+b\varphi)(c+d\varphi) = (ac+7bd)+(ad+bc)\varphi.\]扩域大小约为
\[|\mathbb E|=p^2\approx 2^{128}.\]这里必须区分两件事:
- trace、Merkle leaves、FFT 的大部分工作仍在基础域 $\mathbb F_p$;
- $\zeta$、FRI folding challenges 等关键随机量可落在 $\mathbb E$。
这种“基础域做吞吐、扩域买 soundness”的分工后来也成为许多 small-field STARK 的常见设计。
3. 从三列 PLONK 到 135 列宽 trace
3.1 一行不是固定的加乘门
经典 PLONK 常用三列 $a,b,c$ 和一个类似
\[q_Mab+q_La+q_Rb+q_Oc+q_C=0\]的通用门。
Plonky2 更接近 TurboPLONK:每一种 gate 可以声明若干多项式约束。例如 division gate 用 wires
\[(w_1,w_2,w_3,w_4)=(x,y,q,i)\]并约束
\[w_3w_2-w_1=0, \qquad w_2w_4-1=0.\]第二个约束同时保证 $y\ne0$,因为 witness 必须给出 $i=y^{-1}$。
3.2 源码默认宽度
最终仓库的 standard_recursion_config 配置为:
| 参数 | 值 | 含义 |
|---|---|---|
num_wires | 135 | 每行总 wire 数 |
num_routed_wires | 80 | 参加 permutation argument 的 wires |
| advice wires | 55 | 不参加 copy permutation 的局部辅助 wires |
num_constants | 2 | 每行可用常量列数 |
num_challenges | 2 | 对小域 soundness 子协议的并行挑战数 |
max_quotient_degree_factor | 8 | quotient degree factor 上限 |
zero_knowledge | false | 标准递归配置本身不启用 ZK |
因此常见的“Plonky2 有 135 列”还不完整。更重要的是
\[135=80\text{ routed}+55\text{ advice}.\]3.3 routed wire 与 advice wire
若两个远处 cells 必须相等,builder 添加 copy constraint:
\[w_j(\omega^r)=w_k(\omega^s).\]这两个位置必须是 routed wires,因为它们会进入 permutation argument。
而某个 gate 内部独占的中间量,例如:
- $y^{-1}$;
- Poseidon 某一轮 S-box 的中间值;
- 插值的临时乘积;
若不需要连接到别行,可放在 advice wire。这样能减少:
- $\sigma_j$ permutation polynomials 数量;
- grand-product 每行的乘积宽度;
- opening 数量;
- verifier 工作。
advice 并不是“不受约束”。它仍必须满足本行 gate equations,只是不参与全局 wiring permutation。
flowchart TB
subgraph ROW["某个 gate row"]
R1["routed wire<br/>可连到远处 cell"]
R2["routed wire<br/>进入 permutation"]
A1["advice wire<br/>仅由本行约束"]
A2["advice wire<br/>不进入 permutation"]
end
R1 --> P["copy-permutation argument"]
R2 --> P
A1 --> G["custom-gate equations"]
A2 --> G
R1 --> G
R2 --> G
4. 一个 selector 如何复用给多个 gate
4.1 直接 one-hot selector 的问题
若有 $k$ 种 custom gates,为每种 gate 各放一个 selector polynomial
\[s_j(\omega^i)\in\{0,1\}\]会增加 $k$ 个预处理多项式和 opening 负担。
4.2 gate 编号 selector
对一组 gates $G$,可用一个 selector $S(X)$ 编码当前行的全局 gate index。记 gate $g_j$ 的 index 为 $j$:
\[S(\omega^i)=j \quad\Longleftrightarrow\quad \text{第 }i\text{ 行使用 }g_j.\]若整个电路只需要一个 selector polynomial,则每一行都属于这个唯一 group。要只激活 $g_j$,可构造 filter(与源码只差一个整体符号):
\[F_j(S) = \prod_{\substack{k\in G\\k\ne j}} (S-k), \qquad \deg_S F_j=|G|-1.\]但当源码把 gates 分成两个或更多 selector groups 时,属于其他 group 的行在本 group 的 selector 中不取某个 gate index,而取哨兵值
\[u=\texttt{UNUSED\_SELECTOR}.\]因此多 group 情形必须再加入一个零点:
\[\boxed{ F_j(S) = (S-u) \prod_{\substack{k\in G\\k\ne j}} (S-k), \qquad \deg_S F_j=|G|. }\]于是:
- 当 $S(\omega^i)=k\ne j$ 时,乘积中出现零因子;
- 多 group 时,当该行属于其他 group、$S(\omega^i)=u$ 时,额外因子关闭本组所有 gates;
- 当 $S(\omega^i)=j$ 时,$F_j(S(\omega^i))\ne0$。
若 gate $g_j$ 的第 $\ell$ 个约束为 $C_{j,\ell}$,实际约束是
\[F_j(S(X))C_{j,\ell}(X)=0 \quad\text{on }H.\]4.3 为什么还要把 gates 分组
若原 gate constraint 的 formal degree 为 $d_j$,selector 本身作为一个已承诺 polynomial 代入后,filtered constraint 的 formal degree 上界分两种情况:
\[\deg\bigl(F_j(S(X))C_{j,\ell}(X)\bigr) \le \begin{cases} d_j+|G|-1, &\text{只有一个 selector group},\\[2mm] d_j+|G|, &\text{存在多个 selector groups}. \end{cases}\]因此源码把 gates 贪心分组,使每组满足类似
\[\begin{cases} |G|-1+\max_{g\in G}\deg(g)\le d_{\max}, &\text{单 group 特例},\\ |G|+\max_{g\in G}\deg(g)\le d_{\max}, &\text{多 group}. \end{cases}\]每组使用一个 selector polynomial,在:
- selector 数量;
- quotient degree;
- opening 成本
之间取平衡。
这是 Plonky2 “custom gate 很多但 selector 不一定很多”的关键。
5. copy constraints:宽 permutation 与部分积
5.1 位置标签
设 trace domain
\[H=\{1,\omega,\ldots,\omega^{N-1}\},\]有 $r$ 个 routed columns。给每个 cell $(j,i)$ 一个唯一标签
\[\operatorname{id}_j(\omega^i).\]copy wiring 定义一个 cell permutation $\sigma$,对应预处理多项式满足
\[\sigma_j(\omega^i) = \operatorname{id}_{\sigma(j,i)}.\]5.2 随机压缩 value 与位置
对随机 $\beta,\gamma$,定义
\[\begin{aligned} u_j(X)&=w_j(X)+\beta\operatorname{id}_j(X)+\gamma,\\ v_j(X)&=w_j(X)+\beta\sigma_j(X)+\gamma. \end{aligned}\]若 wire values 沿 wiring permutation 一致,则整个 domain 上的两个 multisets 相同:
\[\prod_{x\in H}\prod_{j=1}^{r}u_j(x) = \prod_{x\in H}\prod_{j=1}^{r}v_j(x).\]5.3 grand product recurrence
定义 accumulator $Z$,令
\[Z(1)=1\]并在每行满足
\[Z(\omega X) \prod_{j=1}^{r}v_j(X) = Z(X) \prod_{j=1}^{r}u_j(X).\]最后配合边界约束闭合 $Z$。方向可因实现记号相反,但本质是:
\[\frac{Z(\omega X)}{Z(X)} = \prod_j\frac{u_j(X)}{v_j(X)}.\]5.4 80 个 routed wires 不能直接相乘
若直接使用全部 $r=80$ 个 factors,约束 degree 过高。Plonky2 引入 partial-product polynomials。
设单个约束最多容纳 $d$ 个 factors,源码默认 quotient degree factor 上限为
\[d=8.\]把
\[(u_1,\ldots,u_r), \qquad (v_1,\ldots,v_r)\]分块。令
\[P_0(X)=Z(X), \qquad P_t(X) = P_{t-1}(X) \prod_{j\in B_t} \frac{u_j(X)}{v_j(X)}.\]为了避免电路约束中出现除法,实际检查
\[P_{t-1}(X) \prod_{j\in B_t}u_j(X) - P_t(X) \prod_{j\in B_t}v_j(X) =0.\]最后一个 accumulator 对接 $Z(\omega X)$。
flowchart LR
Z0["Z(X)"] --> B1["乘第 1 组<br/>最多 8 对 factors"]
B1 --> P1["partial product π_1(X)"]
P1 --> B2["乘第 2 组"]
B2 --> P2["partial product π_2(X)"]
P2 --> BM["继续分块"]
BM --> Z1["Z(ωX)"]
对 $r$ 个 factors,每块至多 $d$ 个,额外 partial products 数量大致为
\[\left\lceil\frac rd\right\rceil-1.\]这说明 custom wide trace 并非免费:宽度减短了行数,却会增加 permutation 的多项式数量和部分积。
5.5 小域下的重复挑战
经典 PLONK 常把 $1/\lvert\mathbb F\rvert$ 量级错误视为足够小。Goldilocks 只有约 64 bit,不能这样做。
例如一个错误 permutation 逃过随机 $(\beta,\gamma)$ 检查的粗略概率可含
\[\varepsilon_{\mathrm{perm}} \lesssim \frac Np.\]用独立挑战重复 $s$ 次,可把对应项压到近似
\[\left(\frac Np\right)^s.\]最终源码默认 num_challenges = 2,目标是约 100-bit 的整体配置;技术稿用“三次重复可在特定 $N$ 上达到 128 bit”作说明。不能把技术稿的示例次数、源码默认次数和任意 trace 长度混为一谈。
6. 约束如何成为 quotient
6.1 所有局部等式在 $H$ 上为零
将 gate、permutation、边界、lookup 等约束记为
\[C_0(X),\ldots,C_{m-1}(X).\]验证者采样 $\alpha$,做随机线性组合
\[C_\alpha(X) = \sum_{i=0}^{m-1}\alpha^i C_i(X).\]若所有约束在 $H$ 上成立,则
\[Z_H(X)=X^N-1\]整除 $C_\alpha$:
\[Q(X) = \frac{C_\alpha(X)}{Z_H(X)}\]是低次多项式。
6.2 为什么要拆 quotient
若
\[\deg C_\alpha<dN,\]则
\[\deg Q<(d-1)N.\]基础 trace polynomials 通常按 degree 小于 $N$ 的对象承诺。于是把高次 quotient 拆成若干 chunks:
\[Q(X) = Q_0(X)+X^NQ_1(X)+\cdots+X^{(t-1)N}Q_{t-1}(X),\]每个 $Q_i$ 的 degree 小于 $N$。
在随机点 $\zeta$ 上重组:
\[Q(\zeta) = \sum_{i=0}^{t-1}\zeta^{iN}Q_i(\zeta).\]这里描述的正是固定 Plonky2 源码的做法:prover 直接按每 $N$ 个系数切分 quotient_poly.chunks(degree),所以这些是 monomial chunks,verifier 使用 $\zeta^N$ 的幂进行 Horner 重组。disjoint-subdomain 的消失多项式基重组属于旧版 Plonky3/QED Plonky2.5 等其他协议形状,不能与本节固定 Plonky2 的 chunk 语义混用。
6.3 随机点恒等式
prover 给出所有相关多项式在 $\zeta$ 与必要 rotations 上的 openings。verifier 重算
\[C_\alpha(\zeta)\]并检查
\[\boxed{ C_\alpha(\zeta) = Z_H(\zeta)Q(\zeta). }\]如果两边对应的多项式并不恒等,随机 $\zeta\in\mathbb E$ 命中其根的概率受 degree 与 $\lvert\mathbb E\rvert$ 控制。
7. 公开输入不是一列任意长 PI polynomial
Plonky2 先在电路中把公开输入
\[x_0,\ldots,x_{\ell-1}\]哈希为四个域元素
\[h=(h_0,h_1,h_2,h_3),\]再把它们 routed 到一个 PublicInputGate,约束对应 wires 等于这四个 digest elements。
这把约束系统中的公开输入接口从“长度 $\ell$ 的多项式”压成固定四个 field elements。
但安全边界是:
- proof object 仍携带原始 public inputs;
- verifier 必须使用完全相同的无歧义编码与 hash;
- transcript 必须吸收 public-input hash;
- application 必须检查 public inputs 是自己期望的 statement,而不能只调用“proof valid”。
8. Poseidon 为什么做成一整行 gate
8.1 参数
Plonky2 默认 Poseidon 置换的技术稿参数为:
- state width:12 个 Goldilocks elements;
- S-box:$x^7$;
- full rounds:8;
- partial rounds:22。
8.2 单个 Poseidon gate
一般 AIR 会用多行表达一个 permutation,每轮一行。Plonky2 反过来使用一个很宽的 PoseidonGate 表达整次 permutation。
为使最高 constraint degree 保持在 7,电路为 S-box 输入安排大量 intermediate wires,然后约束
\[y=x^7.\]优点:
- round constants 可直接固化在 gate 描述中;
- 不需要额外 periodic/preprocessed columns;
- 递归 verifier 的 Merkle hashing 行数更少。
代价:
- trace 很宽;
- 需要 135 wires 的配置;
- gate-specific layout 更复杂。
技术稿报告递归电路大约 75% 用于 Merkle proof verification,所以 hash gate 的设计直接决定 recursion threshold。
8.3 MDS 优化
技术稿选择第一行为
\[[1,1,2,1,8,32,2,256,4096,8,65536,1024]\]的 circulant MDS matrix。大量系数是二次幂,方便用位移、SIMD lane permutation 和延迟约减优化。
注意:这是具体实现参数,不是“任意 Poseidon 都自动同样快”。
9. 从 Merkle commitment 到 FRI opening
9.1 对 evaluation matrix 承诺
对多项式组
\[\mathbf p=(p_0,\ldots,p_{k-1})\]先在扩展 domain $L$ 上求值:
\[\operatorname{LDE}(\mathbf p) = \bigl(p_j(x)\bigr)_{x\in L,\,j\in[k]}.\]每个 $x$ 对应的整行 evaluations 放在同一 Merkle leaf:
\[\operatorname{leaf}_x = \bigl(p_0(x),\ldots,p_{k-1}(x)\bigr).\]因此一个 Merkle opening 可同时认证同一点上的多列。
9.2 Merkle cap
Plonky2 在递归配置中不只发送单个 root,而发送树上某一高度的全部节点,称为 cap。
若 cap height 为 $c$,cap 包含
\[2^c\]个 digests。源码默认 $c=4$,即 16 个 digests。
效果:
- 每条 authentication path 少做 $c$ 次 hash;
- path 长度固定,适合静态电路;
- proof 中承诺本身变大。
9.3 单点 opening 转成 DEEP quotient
若声称
\[p(\zeta)=y,\]定义
\[b(X)=\frac{p(X)-y}{X-\zeta}.\]当且仅当 $y$ 真的是 $p(\zeta)$ 时,分子被 $X-\zeta$ 整除,$b$ 是低次多项式。
若要同时打开许多 $(p_i,\zeta_i,y_i)$,采样 batch challenge $\rho$,组合为
\[B(X) = \sum_i\rho^i \frac{p_i(X)-y_i}{X-\zeta_i}.\]然后对 $B$ 的 committed evaluation behavior 做一次 FRI,而不是每个 opening 各跑一次。
10. FRI 折叠的 Plonky2 形式
10.1 一般 $a$ 元折叠
设当前 polynomial 写成
\[f(X) = \sum_{j=0}^{a-1}X^j f_j(X^a),\]其中 $a=2^b$。verifier 采样 $\beta$,定义下一层
\[f_{\mathrm{next}}(Y) = \sum_{j=0}^{a-1}\beta^j f_j(Y).\]degree 大致缩小 $a$ 倍。
对一个大小为 $a$ 的 coset,只要打开整组 evaluations,就能插值出 $f_0,\ldots,f_{a-1}$ 在相应点的值,并检查下一层 leaf 与折叠结果一致。
10.2 early stopping
不必一直折到常数。若最后 degree 已足够小,prover 直接发送 final polynomial coefficients,verifier:
- 检查其 degree bound;
- 在 query 归约后的点上求值;
- 与最后一次 fold 结果比较。
10.3 技术稿与最终源码配置不同
| 来源 | recursion-oriented folding 描述 |
|---|---|
| 2022 技术稿 | 固定 arity 8,使 verifier gate 形状统一 |
最终源码 standard_recursion_config | ConstantArityBits(4, 5),即反复做 $2^4=16$ 元折叠,直到 final degree bits 不超过 5,或受 cap height 限制 |
这不是数学矛盾,而是实现参数演进。阅读 benchmark 或 proof format 时必须绑定具体 commit/release。
11. 源码默认 FRI 参数逐项解释
最终 standard_recursion_config:
| 参数 | 默认值 | 数学意义 |
|---|---|---|
rate_bits | 3 | RS code rate $2^{-3}=1/8$,LDE blowup 为 8 |
cap_height | 4 | 每个 cap 有 $2^4=16$ 个 digests |
proof_of_work_bits | 16 | query 前 grinding 16 bit |
reduction_strategy | ConstantArityBits(4,5) | 最大 16 元 fold,final degree 至多约 $2^5$ |
num_query_rounds | 28 | 28 个 query indices |
security_bits | 100 | 配置目标,不是由字段名自动保证的定理 |
最粗略的旧式 conjectural heuristic 会把
\[\text{FRI query contribution} \approx \text{rate\_bits}\times\text{queries} =3\cdot28=84\]再加 16-bit grinding 得到约 100 bits。
但这只是 ethSTARK 风格 conjectural 估计,不是完整 proven soundness:
- 还要计入 ALI/DEEP、constraint batching、field-size errors;
- correlated agreement / proximity-gap 的精确界很关键;
- hash collision resistance 构成上限;
- Fiat–Shamir 还需要随机预言机模型下的分析。
因此“28 queries + 16 PoW = 100 bit”应理解为该版本的参数设计目标,而非可脱离协议形状复用的公式。
12. 完整 transcript 顺序
令:
- $C_{\mathrm{cs}}$:constants 与 $\sigma$ 的预处理 cap;
- $C_w$:wire LDE cap;
- $C_Z$:permutation $Z$ 与 partial products 的 cap;
- $C_Q$:quotient chunks cap;
- $h_{\mathrm{PI}}$:公开输入 hash;
- $d_{\mathrm{circ}}$:circuit digest。
源码挑战顺序可概括为:
sequenceDiagram
participant P as Prover
participant T as Fiat-Shamir transcript
participant V as Verifier
P->>T: FRI 参数、circuit digest、PI hash
P->>T: wire cap C_w
T-->>P: permutation beta_j 与 gamma_j
P->>T: Z 与 partial-products cap C_Z
T-->>P: constraint-combination alpha_j
P->>T: quotient cap C_Q
T-->>P: OOD point zeta in extension field
P->>T: zeta 上的 claimed openings
T-->>P: FRI batch challenge rho
P->>T: 各层 FRI caps
T-->>P: folding challenges
P->>T: final polynomial 与 PoW witness
T-->>P: query indices
P->>V: Merkle paths 与 coset openings
顺序的原则是:
\[\boxed{ \text{任何 challenge 必须在其要约束的 prover message 之后采样。} }\]例如若 $\zeta$ 在 $C_Q$ 之前生成,prover 可针对已知 $\zeta$ 选择 quotient commitment;若 query indices 在 FRI caps 之前生成,prover 可只修补被查询位置。
13. verifier 最后究竟检查什么
把验证拆成三层最清楚。
13.1 commitment authentication
对每个 query:
- 重新哈希 wire、$Z$/partial products、quotient、FRI layers 的 Merkle paths;
- 检查所得节点属于相应 cap。
13.2 FRI consistency
对每一层:
- 把 query 所在 coset 的 evaluations 插值;
- 用 folding challenge 计算下一值;
- 检查它等于下一层被认证的 evaluation;
- 最后与 final polynomial evaluation 相等。
13.3 PLONK identity
用 $\zeta$ 上 openings 重算:
- custom gate constraints;
- selector filters;
- permutation recurrence 与边界;
- partial-product relations;
- 公开输入 hash binding;
- lookup constraints(若存在)。
然后检查
\[C_{\alpha_j}(\zeta) = Z_H(\zeta)Q_j(\zeta)\]对所有重复 challenge $j$ 成立。
注意:FRI 只证明“承诺向量接近合适 degree 的 Reed–Solomon codeword”;PLONK identity 才证明这些 codewords 共同描述合法 circuit witness。二者缺一不可。
14. zero-knowledge 是显式开关
最终默认递归配置:
\[\texttt{zero\_knowledge=false}.\]另有
1
CircuitConfig::standard_recursion_zk_config()
启用 hiding 机制。
技术稿描述的主要思路包括:
- 在 padding 到二次幂前向 trace 添加随机 rows;
- 对 permutation accumulator 添加成对随机 rows并维持 copy constraints;
- 不在原 trace domain 上直接发送 witness evaluations,而使用 coset;
- 对 Merkle leaf 加随机 salt,使 vector commitment hiding。
因此应区分:
\[\text{validity argument} \ne \text{zero-knowledge argument}.\]如果配置、proof type 或 wrapper 没有启用并正确分析 blinding,不能仅因项目属于 ZK 生态就声称 witness privacy。
15. 一个小型端到端代数例子
假设只有一个 division gate,位于第 $i$ 行:
\[(x_i,y_i,q_i,r_i)\]其中 $r_i$ 声称是 $y_i^{-1}$。selector filter 为 $F_{\mathrm{div}}$。
本行约束:
\[\begin{aligned} c_0(X) &= F_{\mathrm{div}}(X) \bigl(q(X)y(X)-x(X)\bigr),\\ c_1(X) &= F_{\mathrm{div}}(X) \bigl(y(X)r(X)-1\bigr). \end{aligned}\]随机组合:
\[C_\alpha(X) =c_0(X)+\alpha c_1(X)+\alpha^2c_{\mathrm{perm}}(X)+\cdots.\]合法 trace 使
\[Z_H\mid C_\alpha.\]prover 承诺 $x,y,q,r,Z,\pi,Q$ 的 LDE,发送 $\zeta$ 上点值,并用 FRI 证明这些 openings 与低度 codewords 一致。verifier 检查:
\[\begin{aligned} C_\alpha(\zeta) &= F_{\mathrm{div}}(\zeta) \bigl(q(\zeta)y(\zeta)-x(\zeta)\bigr)\\ &\quad+ \alpha F_{\mathrm{div}}(\zeta) \bigl(y(\zeta)r(\zeta)-1\bigr) +\cdots\\ &=Z_H(\zeta)Q(\zeta). \end{aligned}\]若 $y_i=0$,不存在 $r_i$ 使 $y_ir_i=1$,所以 witness 生成器不能通过第二个约束。
这个例子显示三种绑定各司其职:
- gate constraint:本行语义;
- permutation:跨行 wiring;
- FRI:所有声称多项式的低度性与 openings。
16. 安全与实现边界
16.1 100 bit 是 conjectured target
官方仓库明确说默认 FRI 参数面向约 100-bit conjectured security。不能把它改写成无条件 100-bit 定理。
16.2 默认 Poseidon 参数的单独安全估计
官方 README 同时指出:默认 width 12、8 full + 22 partial、$x^7$ 的 Poseidon 配置,根据其引用的 BBLP22 分析可能只有约 95-bit,而非完整 100-bit。
在协议实现满足规范、native verifier 与 recursive verifier 语义一致的前提下,密码学安全上限不超过最弱的已分析组件:
\[\lambda_{\mathrm{crypto}} \le \min( \lambda_{\mathrm{FRI}}, \lambda_{\mathrm{hash}}, \lambda_{\mathrm{algebraic}}, \lambda_{\mathrm{FS}} ).\]实现正确性不应被伪装成另一个可相加或可取最小值的“security bits”项。更准确的逻辑结构是
\[\boxed{ \mathsf{ImplementationConformsToSpec} \quad\Longrightarrow\quad \Pr[\mathsf{CryptoBad}]\le\varepsilon_{\mathrm{crypto}}. }\]若 parser、transcript、约束或递归 verifier 存在 bug,接受关系可能整体偏离规范;除非另行给出明确的随机故障模型,否则不存在通用的 $\lambda_{\mathrm{implementation}}$ 可以放进上式。
16.3 技术稿仍标为 draft
2022 文档清楚标注 DRAFT,且含未完成的 ZK 说明。该文档可用于理解设计,但部署审计不能把草稿当最终形式化 specification。
16.4 仓库已弃用
Plonky2 官方仓库已标注不再更新或支持,并建议使用 Plonky3。弃用不等于已生成 proofs 立刻失效,但意味着:
- 新发现未必修复;
- 依赖与工具链继续老化;
- 新项目不应默认采用旧配置;
- 长期维护者需要自行承担 fork、审计与参数责任。
16.5 verifier 必须固定 shape
安全 statement 不只有 proof bytes,还包括:
\[(\text{circuit digest}, \text{common circuit data}, \text{FRI params}, \text{hash config}, \text{public inputs}).\]任何从不可信 proof 动态推导、却未被 verifier policy 固定或 transcript 绑定的 shape,都可能成为 statement substitution 或解析歧义入口。
17. 技术稿参数与最终实现参数对照
| 项目 | 技术稿描述 | 最终源码默认 |
|---|---|---|
| 基础域 | Goldilocks | Goldilocks |
| challenge 扩域 | $\mathbb F_p[X]/(X^2-7)$ | quadratic extension |
| trace width | 135 | 135 |
| routed wires | 讨论宽 permutation | 80 |
| quotient factor | 部分积每组 8 | 最大 8 |
| Poseidon | width 12,8F+22P,$x^7$ | 同一默认族 |
| recursion FRI arity | 固定 8 | 常用固定 16 元策略 |
| FRI rate | speed 模式常用 $1/8$ | $1/8$ |
| query / PoW | 以目标安全解释 | 28 queries + 16-bit grinding |
| 默认 ZK | 描述 hiding 技术 | standard recursion config 为 false;另有 ZK config |
18. 总结
Plonky2 快速递归的数学原因不是某一个“神奇优化”,而是多层共同对齐:
\[\boxed{ \begin{aligned} &\text{Goldilocks:64-bit + 高 two-adicity}\\ &+\text{宽 custom gates:减少 verifier 行数}\\ &+\text{advice wires:缩小 permutation}\\ &+\text{partial products:控制宽 permutation degree}\\ &+\text{Poseidon 整置换 gate:降低 Merkle verifier 行数}\\ &+\text{FRI/Merkle cap:透明且递归友好的 polynomial test}. \end{aligned} }\]代价同样清晰:
- 宽 trace 与专用 gate layout;
- 小域 soundness 必须精细重复与扩域;
- proof 较 pairing-SNARK 大;
- 默认配置未必 ZK;
- FRI 与 Poseidon 安全目标含 conjectural/组件级边界;
- 项目本身已经弃用。
19. 一手资料
- Plonky2 技术稿:Fast Recursive Arguments with PLONK and FRI
- Plonky2 官方仓库与弃用、安全说明
- 源码
CircuitConfig::standard_recursion_config - 源码 FRI reduction strategies
- 源码 challenge/transcript 顺序
- 固定源码 selector grouping
- 固定源码 selector filter(含
UNUSED_SELECTOR因子) - 固定源码 monomial quotient chunks
- 源码 permutation partial products
上一篇:FRI 与 DEEP-FRI
下一篇:Plonky2 递归原理与工程
返回:总目录