Groth16 ZKP: 零知识证明

简介 Groth16 是由 Jens Groth 于 2016 年提出的 zk-SNARK 协议。它是目前区块链领域(如 Zcash, Ethereum L2, Filecoin)应用最广泛的算法。

核心特性:

  • 极致简洁 (Succinct) :证明 π \pi π 仅包含 3 个群元素 (在 BN254 曲线下仅约 128-200 字节)。
  • 验证极快 (Fast Verification) :验证过程仅需 3 次双线性配对 (Pairing) 运算。
  • 需要可信设置 (Trusted Setup):需要为每一个电路单独生成 CRS (Common Reference String)。

整体工作流:

  1. 计算逻辑 (Code) → \rightarrow 算术电路 (Arithmetic Circuit)
  2. 算术电路 → \rightarrow 一阶约束系统 (R1CS)
  3. R1CS → \rightarrow 二次算术程序 (QAP)
  4. Groth16 (基于椭圆曲线和配对的证明生成与验证)

第一节:计算逻辑到算术电路 (Logic to Arithmetic Circuit)

1.1 核心概念转换

零知识证明不直接处理计算机程序(如 C++, Python),而是处理数学多项式 。将代码转化为数学形式的第一步是算术化 (Arithmetization)

传统程序 (CPU) 算术电路 (ZKP) 区别核心
指令流 数据流 电路没有寄存器,只有导线连接
动态执行 (Loops, Jumps) 静态拓扑 (Unrolled Loops) 循环必须展开,路径必须固定
布尔运算 (AND, XOR) 有限域算术 (+, × \times ×) 位运算极其昂贵,需用多项式模拟

1.2 算术电路的构成

电路定义在有限域 F r \mathbb{F}_r Fr 上(模 p p p 的整数域)。

  • 导线 (Wires):承载数值(Witness)。
  • 加法门 (Addition Gate) z = x + y z = x + y z=x+y(计算成本极低,甚至视为免费)。
  • 乘法门 (Multiplication Gate) z = x × y z = x \times y z=x×y(昂贵,决定了生成证明的速度和大小)。

1.3 转换实例:三次方程

假设证明目标:"我知道一个数 x x x,使得 x 3 + x + 5 = 35 x^3 + x + 5 = 35 x3+x+5=35"

第一步:拍平 (Flattening)

将复杂的嵌套计算拆解为单一操作符( o p ∈ { + , × } op \in \{+, \times\} op∈{+,×})的序列。引入中间变量 v i v_i vi。

  • 原始逻辑func(x) { return x*x*x + x + 5 == 35 }
  • 拍平后
    1. v 1 = x ⋅ x v_1 = x \cdot x v1=x⋅x
    2. v 2 = v 1 ⋅ x v_2 = v_1 \cdot x v2=v1⋅x
    3. o u t = v 2 + x + 5 out = v_2 + x + 5 out=v2+x+5

第二步:构建电路门 (Circuit Gates)

将上述步骤转化为电路约束。每个乘法关系对应一个门。

  1. 乘法门 1 ( M 1 M_1 M1):

    • 左输入: x x x
    • 右输入: x x x
    • 输出: v 1 v_1 v1
    • 代数约束 : x ⋅ x − v 1 = 0 x \cdot x - v_1 = 0 x⋅x−v1=0
  2. 乘法门 2 ( M 2 M_2 M2):

    • 左输入: v 1 v_1 v1
    • 右输入: x x x
    • 输出: v 2 v_2 v2
    • 代数约束 : v 1 ⋅ x − v 2 = 0 v_1 \cdot x - v_2 = 0 v1⋅x−v2=0
  3. 加法/线性组合 (作为最终约束):

    • 约束: ( v 2 + x + 5 ) ⋅ 1 = 35 (v_2 + x + 5) \cdot 1 = 35 (v2+x+5)⋅1=35
    • 注:在 R1CS 中,加法通常融合在 A ⋅ B = C A \cdot B = C A⋅B=C 的线性组合中,不需要单独的门。

1.4 处理复杂逻辑 (Difficulties)

对于非代数运算,必须用数学约束模拟:

  1. 布尔约束 (Boolean Check) : 证明一个变量 b b b 是二进制位(0 或 1)。
    • 公式 : b ⋅ ( 1 − b ) = 0 b \cdot (1 - b) = 0 b⋅(1−b)=0
  2. 条件选择 (If-Else / Multiplexer) : 逻辑 if (b) y = x else y = z
    • 公式 : y = b ⋅ x + ( 1 − b ) ⋅ z y = b \cdot x + (1 - b) \cdot z y=b⋅x+(1−b)⋅z
    • 注:必须计算所有分支,通过数学公式"选择"结果。
  3. 位运算 (Bitwise Operations) : 由于域元素 F r \mathbb{F}_r Fr 是大整数,无法直接进行位操作。需要针对单 bit ( a , b ∈ { 0 , 1 } a, b \in \{0,1\} a,b∈{0,1}) 使用代数公式:
    • XOR ( ⊕ \oplus ⊕) : a ⊕ b = a + b − 2 a b a \oplus b = a + b - 2ab a⊕b=a+b−2ab
      • 验证 : 0 + 0 = 0 , 1 + 0 = 1 , 1 + 1 − 2 = 0 0+0=0, 1+0=1, 1+1-2=0 0+0=0,1+0=1,1+1−2=0 (正确)
    • AND ( ∧ \land ∧) : a ∧ b = a ⋅ b a \land b = a \cdot b a∧b=a⋅b
    • OR ( ∨ \lor ∨) : a ∨ b = a + b − a b a \lor b = a + b - ab a∨b=a+b−ab
    • NOT ( ¬ \neg ¬) : ¬ a = 1 − a \neg a = 1 - a ¬a=1−a
  4. 位分解 (Bit Decomposition) : 若要对 32 位整数 X X X 进行位运算,必须先将其拆解为 32 个变量 b 0 ... b 31 b_0 \dots b_{31} b0...b31,并添加约束:
    • 约束 1 (聚合) : X = ∑ i = 0 31 2 i ⋅ b i X = \sum_{i=0}^{31} 2^i \cdot b_i X=∑i=0312i⋅bi
    • 约束 2 (二进制检查) : 对每个 b i b_i bi 都要约束 b i ( 1 − b i ) = 0 b_i(1-b_i)=0 bi(1−bi)=0。
    • 代价:这就是 SHA-256 等哈希函数在 ZK 中极其昂贵的原因(需要数万个约束)。

1.5 总结

  • 输入:一段代码逻辑。
  • 输出:一张包含输入导线、中间导线、输出导线以及乘法门的"图纸"。
  • Witness :使得电路所有门都成立的一组数值向量(例如 1 , 35 , 3 , 9 , 27 1, 35, 3, 9, 27 1,35,3,9,27)。

第二节:算术电路到 R1CS (Arithmetic Circuit to R1CS)

2.1 什么是 R1CS (Rank-1 Constraint System)

R1CS 是一组定义在有限域上的特殊方程组。它的核心思想是把电路中的每一个乘法门(以及相关的线性组合)都标准化为同一个数学格式

标准公式: 对于每一个逻辑门 i i i,必须满足:
( A i ⋅ s ) × ( B i ⋅ s ) = ( C i ⋅ s ) (\mathbf{A}_i \cdot \mathbf{s}) \times (\mathbf{B}_i \cdot \mathbf{s}) = (\mathbf{C}_i \cdot \mathbf{s}) (Ai⋅s)×(Bi⋅s)=(Ci⋅s)

  • s \mathbf{s} s (Solution Vector): 全局变量解向量(Witness)。
  • A i , B i , C i \mathbf{A}_i, \mathbf{B}_i, \mathbf{C}_i Ai,Bi,Ci: 系数向量。
  • ⋅ \cdot ⋅ (Dot Product) : 向量点积,代表对变量进行线性组合(加法)。
  • × \times ×: 数值乘法。

直译含义 ( 左输入导线的线性组合 ) × ( 右输入导线的线性组合 ) = ( 输出导线的线性组合 ) (\text{左输入导线的线性组合}) \times (\text{右输入导线的线性组合}) = (\text{输出导线的线性组合}) (左输入导线的线性组合)×(右输入导线的线性组合)=(输出导线的线性组合)

2.2 构建解向量 (The Witness Vector s \mathbf{s} s)

为了用矩阵描述电路,首先要将电路中出现过的所有 数值拍平成一个长向量 s \mathbf{s} s。 通常结构如下:
s = 1 , Public Outputs , Public Inputs , Private Inputs , Intermediate Variables \mathbf{s} = \\ 1, \\ \\text{Public Outputs}, \\ \\text{Public Inputs}, \\ \\text{Private Inputs}, \\ \\text{Intermediate Variables} \\ s= 1, Public Outputs, Public Inputs, Private Inputs, Intermediate Variables

  • 常数 1 : 必须包含,用于处理加法中的常数项(如 x + 5 x+5 x+5 中的 5,即 5 × 1 5 \times 1 5×1)。

实例 ( x 3 + x + 5 = 35 x^3+x+5=35 x3+x+5=35) 的向量定义 : 假设变量顺序为 o n e , o u t , x , v 1 , v 2 one, out, x, v_1, v_2 one,out,x,v1,v2,若 x = 3 x=3 x=3,则:
s = 1 , 35 , 3 , 9 , 27 \mathbf{s} = \\ 1, \\ 35, \\ 3, \\ 9, \\ 27 \\ s= 1, 35, 3, 9, 27

2.3 门到约束的转换 (Gate to Constraints)

我们需要为电路中的每一步运算构建 a , b , c \mathbf{a}, \mathbf{b}, \mathbf{c} a,b,c 三个系数向量。

回顾逻辑:

  1. v 1 = x ⋅ x v_1 = x \cdot x v1=x⋅x
  2. v 2 = v 1 ⋅ x v_2 = v_1 \cdot x v2=v1⋅x
  3. o u t = ( v 2 + x + 5 ) ⋅ 1 out = (v_2 + x + 5) \cdot 1 out=(v2+x+5)⋅1 (加法通过乘以常数 1 转化为乘法约束)

约束 1: x ⋅ x = v 1 x \cdot x = v_1 x⋅x=v1

  • 左输入 ( A A A) : 取 x x x (向量第 3 位)。 a 1 = 0 , 0 , 1 , 0 , 0 \mathbf{a}_1 = 0, 0, 1, 0, 0 a1=0,0,1,0,0
  • 右输入 ( B B B) : 取 x x x (向量第 3 位)。 b 1 = 0 , 0 , 1 , 0 , 0 \mathbf{b}_1 = 0, 0, 1, 0, 0 b1=0,0,1,0,0
  • 输出 ( C C C) : 取 v 1 v_1 v1 (向量第 4 位)。 c 1 = 0 , 0 , 0 , 1 , 0 \mathbf{c}_1 = 0, 0, 0, 1, 0 c1=0,0,0,1,0
  • 验证 : ( 1 ⋅ x ) × ( 1 ⋅ x ) = v 1 (1\cdot x) \times (1\cdot x) = v_1 (1⋅x)×(1⋅x)=v1

约束 2: v 1 ⋅ x = v 2 v_1 \cdot x = v_2 v1⋅x=v2

  • 左输入 ( A A A) : 取 v 1 v_1 v1。 a 2 = 0 , 0 , 0 , 1 , 0 \mathbf{a}_2 = 0, 0, 0, 1, 0 a2=0,0,0,1,0
  • 右输入 ( B B B) : 取 x x x。 b 2 = 0 , 0 , 1 , 0 , 0 \mathbf{b}_2 = 0, 0, 1, 0, 0 b2=0,0,1,0,0
  • 输出 ( C C C) : 取 v 2 v_2 v2。 c 2 = 0 , 0 , 0 , 0 , 1 \mathbf{c}_2 = 0, 0, 0, 0, 1 c2=0,0,0,0,1
  • 验证 : ( 1 ⋅ v 1 ) × ( 1 ⋅ x ) = v 2 (1\cdot v_1) \times (1\cdot x) = v_2 (1⋅v1)×(1⋅x)=v2

约束 3: ( v 2 + x + 5 ) ⋅ 1 = o u t (v_2 + x + 5) \cdot 1 = out (v2+x+5)⋅1=out

这是一次利用 R1CS 特性处理加法的操作。

  • 左输入 ( A A A) : 线性组合 v 2 + x + 5 v_2 + x + 5 v2+x+5。
    • 5 对应常数项 ( 5 × s 0 5 \times \mathbf{s}0 5×s0)。
    • a 3 = 5 , 0 , 1 , 0 , 1 \mathbf{a}_3 = 5, 0, 1, 0, 1 a3=5,0,1,0,1
  • 右输入 ( B B B) : 常数 1。
    • b 3 = 1 , 0 , 0 , 0 , 0 \mathbf{b}_3 = 1, 0, 0, 0, 0 b3=1,0,0,0,0
  • 输出 ( C C C) : 取 o u t out out。
    • c 3 = 0 , 1 , 0 , 0 , 0 \mathbf{c}_3 = 0, 1, 0, 0, 0 c3=0,1,0,0,0
  • 验证 : ( 5 + x + v 2 ) × 1 = o u t (5 + x + v_2) \times 1 = out (5+x+v2)×1=out

2.4 矩阵形式 (Matrix Representation)

将所有约束的向量堆叠起来,形成三个矩阵 A , B , C A, B, C A,B,C。 假设电路有 m m m 个门,解向量长度为 n n n。矩阵维度为 m × n m \times n m×n。
A = 0 0 1 0 0 0 0 0 1 0 5 0 1 0 1 , B = 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 , C = 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 A = \begin{bmatrix} 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 5 & 0 & 1 & 0 & 1 \end{bmatrix}, \quad B = \begin{bmatrix} 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 \end{bmatrix}, \quad C = \begin{bmatrix} 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 \\ 0 & 1 & 0 & 0 & 0 \end{bmatrix} A= 005000101010001 ,B= 001000110000000 ,C= 000001000100010

R1CS 系统定义 : 对于给定的公开输入和私有 Witness 组成的向量 s \mathbf{s} s,如果它是合法的,则必须满足:
( A ⋅ s ) ∘ ( B ⋅ s ) = ( C ⋅ s ) (A \cdot \mathbf{s}) \circ (B \cdot \mathbf{s}) = (C \cdot \mathbf{s}) (A⋅s)∘(B⋅s)=(C⋅s)

( ∘ \circ ∘ 代表阿达玛乘积,即逐元素相乘)

2.5 总结

  • 输入:算术电路图。
  • 输出 :三个稀疏矩阵 A , B , C A, B, C A,B,C。
  • 意义:将复杂的程序逻辑,彻底转化为了线性代数问题(矩阵运算)。
  • 下一步:矩阵是离散的,为了能进行极简验证(Probabilistic Check),我们需要通过多项式插值将其转化为连续形式(QAP)。

第三节:R1CS 到 QAP (R1CS to QAP)

3.1 核心目标

R1CS 虽然严谨,但验证成本很高:如果有 100 万个约束(矩阵有 100 万行),验证者就需要逐行检查。 QAP (Quadratic Arithmetic Program) 的目标是将这 m m m 个离散的约束方程 ,打包成 1 个连续的多项式方程

变换逻辑

  • 矩阵的行 (Rows) → \rightarrow 多项式的求值点 (Evaluation Points)
  • 矩阵的列 (Columns) → \rightarrow 基多项式 (Basis Polynomials)

3.2 拉格朗日插值 (Lagrange Interpolation)

这是实现变换的数学工具。它的作用是找到一个多项式,使其穿过所有指定的坐标点。

变换过程

  1. 定义根 (Roots) :为 R1CS 的每一行(每一个约束门)分配一个索引值 r k r_k rk。
    • 理论上 :可以是 { 1 , 2 , 3 , ... , m } \{1, 2, 3, \dots, m\} {1,2,3,...,m}。
    • 工程上 :为了利用 FFT 加速,使用 单位根 (Roots of Unity) { 1 , ω , ω 2 , ... , ω m − 1 } \{1, \omega, \omega^2, \dots, \omega^{m-1}\} {1,ω,ω2,...,ωm−1}。
  2. 列变换 : 对于矩阵 A A A 的每一列 i i i(对应第 i i i 个变量),我们构造一个多项式 u i ( x ) u_i(x) ui(x),使得在第 k k k 行,多项式的值等于矩阵该位置的元素值。 u i ( r k ) = A k , i u_i(r_k) = A_{k,i} ui(rk)=Ak,i 同理构造 v i ( x ) v_i(x) vi(x) 对应矩阵 B B B, w i ( x ) w_i(x) wi(x) 对应矩阵 C C C。

3.3 构造 QAP 多项式

一旦有了基多项式 { u i ( x ) , v i ( x ) , w i ( x ) } \{u_i(x), v_i(x), w_i(x)\} {ui(x),vi(x),wi(x)},我们将解向量 s \mathbf{s} s 中的数值(Witness)作为系数进行线性组合。

定义三个全局多项式:
U ( x ) = ∑ i = 0 n s i ⋅ u i ( x ) U(x) = \sum_{i=0}^n s_i \cdot u_i(x) U(x)=i=0∑nsi⋅ui(x)
V ( x ) = ∑ i = 0 n s i ⋅ v i ( x ) V(x) = \sum_{i=0}^n s_i \cdot v_i(x) V(x)=i=0∑nsi⋅vi(x)
W ( x ) = ∑ i = 0 n s i ⋅ w i ( x ) W(x) = \sum_{i=0}^n s_i \cdot w_i(x) W(x)=i=0∑nsi⋅wi(x)

  • 含义 U ( x ) U(x) U(x) 代表了在任意 x x x 点,电路左输入导线的加权总和。

3.4 目标多项式 t ( x ) t(x) t(x) (The Target Polynomial)

这是一个系统预设的公有多项式,它的根就是所有约束行的索引。 如果使用单位根,它具有极其简洁的形式:
t ( x ) = ∏ k = 0 m − 1 ( x − ω k ) = x m − 1 t(x) = \prod_{k=0}^{m-1} (x - \omega^k) = x^m - 1 t(x)=k=0∏m−1(x−ωk)=xm−1

它的零点恰好就是我们需要检查约束的所有位置。

3.5 QAP 核心方程与整除性

这是整个转换的终点。 如果 Witness s \mathbf{s} s 是正确的,那么在所有的约束点 x ∈ { r 0 , ... , r m − 1 } x \in \{r_0, \dots, r_{m-1}\} x∈{r0,...,rm−1} 上,都有:
U ( x ) ⋅ V ( x ) − W ( x ) = 0 U(x) \cdot V(x) - W(x) = 0 U(x)⋅V(x)−W(x)=0

根据因式定理 (Factor Theorem) ,如果多项式 P ( x ) = U ( x ) V ( x ) − W ( x ) P(x) = U(x)V(x) - W(x) P(x)=U(x)V(x)−W(x) 在所有根处都为 0,那么它一定能被 t ( x ) t(x) t(x) 整除。 因此,必然存在一个商多项式 H ( x ) H(x) H(x) 使得:
U ( x ) ⋅ V ( x ) − W ( x ) = H ( x ) ⋅ t ( x ) U(x) \cdot V(x) - W(x) = H(x) \cdot t(x) U(x)⋅V(x)−W(x)=H(x)⋅t(x)

3.6 为什么叫"二次" (Quadratic)?

虽然多项式的阶数(Degree)很高(取决于电路规模 m m m),但约束关系的代数结构是: ( 线性组合 ) × ( 线性组合 ) − ( 线性组合 ) = 0 (\text{线性组合}) \times (\text{线性组合}) - (\text{线性组合}) = 0 (线性组合)×(线性组合)−(线性组合)=0 这在代数定义上属于二次约束 (Quadratic Constraint)。这是双线性配对(只能做一次乘法)所能验证的极限。

3.7 总结

  • 输入 :R1CS 矩阵和解向量 s \mathbf{s} s。
  • 输出 :一组多项式 U ( x ) , V ( x ) , W ( x ) , H ( x ) U(x), V(x), W(x), H(x) U(x),V(x),W(x),H(x) 和目标 t ( x ) t(x) t(x)。
  • 核心优势 : 验证者不再需要检查 100 万个方程。根据 Schwartz-Zippel 引理 ,验证者只需要随机挑选一个点 τ \tau τ,检查 U ( τ ) V ( τ ) − W ( τ ) = ? H ( τ ) t ( τ ) U(\tau)V(\tau) - W(\tau) \overset{?}{=} H(\tau)t(\tau) U(τ)V(τ)−W(τ)=?H(τ)t(τ) 是否成立。
    • 如果在这个随机点成立,那么整个多项式在全域相等的概率接近 100%。
    • 这就是 zk-SNARKs "Succinct"(简洁)特性的来源。

第四节:Groth16 原理 (Groth16 Protocol over QAP)

4.1 核心数学工具

Groth16 建立在椭圆曲线对 (Elliptic Curve Pairings) 之上。

  • 群结构 : 定义三个循环群 G 1 , G 2 , G T G_1, G_2, G_T G1,G2,GT,阶为质数 r r r。生成元分别为 g ∈ G 1 , h ∈ G 2 g \in G_1, h \in G_2 g∈G1,h∈G2。
  • 符号 : x 1 = x ⋅ g x_1 = x \cdot g x1=x⋅g, x 2 = x ⋅ h x_2 = x \cdot h x2=x⋅h。
  • 双线性配对 (Bilinear Pairing) : 映射 e : G 1 × G 2 → G T e: G_1 \times G_2 \rightarrow G_T e:G1×G2→GT。
    • 关键性质: e ( a 1 , b 2 ) = e ( 1 1 , 1 2 ) a b e(a_1, b_2) = e(1_1, 1_2)^{ab} e(a1,b2)=e(11,12)ab。这使得我们可以验证加密数据的乘法关系。

4.2 第一步:可信设置 (Trusted Setup)

为了生成 CRS (Common Reference String),必须采样一组随机数(有毒废料),并在生成密钥后销毁。

随机采样 : α , β , γ , δ , τ ∈ F r ∗ \alpha, \beta, \gamma, \delta, \tau \in \mathbb{F}_r^* α,β,γ,δ,τ∈Fr∗。

生成密钥:

  1. 验证密钥 ( v k vk vk): 用于处理公开输入和最终检查。

    v k = ( α 1 , β 2 , γ 2 , δ 2 , { β u i ( τ ) + α v i ( τ ) + w i ( τ ) γ 1 } i = 0 l ) vk = \left( \\alpha_1, \\beta_2, \\gamma_2, \\delta_2, \{ \\frac{\\beta u_i(\\tau) + \\alpha v_i(\\tau) + w_i(\\tau)}{\\gamma}1 \}{i=0}^l \right) vk=(α1,β2,γ2,δ2,{γβui(τ)+αvi(τ)+wi(τ)1}i=0l)

    • 最后一项是针对公开输入 ( i = 0 ... l i=0 \dots l i=0...l) 的预计算。
  2. 证明密钥 ( p k pk pk) : 必须包含生成 A , B , C A, B, C A,B,C 所需的所有群元素。

    p k = ( α 1 , β 1 , δ 1 ⏟ G1 常数 , { τ i 1 } i = 0 d − 1 ⏟ G1 幂次 , { β u i ( τ ) + α v i ( τ ) + w i ( τ ) δ 1 } i = l + 1 m ⏟ G1 私有 Witness , { τ i t ( τ ) δ 1 } i = 0 d − 2 ⏟ G1 H项 , β 2 , δ 2 ⏟ G2 常数 , { τ i 2 } i = 0 d − 1 ⏟ G2 幂次 ) pk = \left( \underbrace{\\alpha1, \\beta1, \\delta1}{\text{G1 常数}}, \underbrace{\{ \\tau\^i1 \}{i=0}^{d-1}}{\text{G1 幂次}}, \underbrace{\{ \\frac{\\beta u_i(\\tau) + \\alpha v_i(\\tau) + w_i(\\tau)}{\\delta}1 \}{i=l+1}^m}{\text{G1 私有 Witness}}, \underbrace{\{ \\frac{\\tau\^i t(\\tau)}{\\delta}1 \}{i=0}^{d-2}}_{\text{G1 H项}}, \underbrace{\\beta2, \\delta2}{\text{G2 常数}}, \underbrace{\{ \\tau\^i2 \}{i=0}^{d-1}}{\text{G2 幂次}} \right) pk= G1 常数 α1,β1,δ1,G1 幂次 {τi1}i=0d−1,G1 私有 Witness {δβui(τ)+αvi(τ)+wi(τ)1}i=l+1m,G1 H项 {δτit(τ)1}i=0d−2,G2 常数 β2,δ2,G2 幂次 {τi2}i=0d−1

    • 注: p k pk pk 必须包含 β 1 \\beta_1 β1 和 { τ i 2 } \{\\tau\^i_2\} {τi2} 才能完成 C C C 和 B B B 的计算。

4.3 第二步:证明生成 (Proving)

证明者拥有 Witness a = { a 0 , ... , a m } \mathbf{a} = \{a_0, \dots, a_m\} a={a0,...,am},满足 QAP 方程 U ( x ) V ( x ) − W ( x ) = h ( x ) t ( x ) U(x)V(x) - W(x) = h(x)t(x) U(x)V(x)−W(x)=h(x)t(x)。 为了实现零知识,证明者采样随机数 r , s ∈ F r r, s \in \mathbb{F}_r r,s∈Fr。

构造 π = ( A 1 , B 2 , C 1 ) \pi = (A_1, B_2, C_1) π=(A1,B2,C1):

  1. 计算 A A A ( G 1 G_1 G1 群):

    A = α 1 + ∑ i = 0 m a i u i ( τ ) 1 1 + r δ 1 A = \\alpha1 + \sum{i=0}^m a_i u_i(\tau)1_1 + r\\delta_1 A=α1+i=0∑maiui(τ)11+rδ1

    • 意义: 对 U ( τ ) U(\tau) U(τ) 的加密评估,加上 α \alpha α 偏移和 r r r 混淆。
  2. 计算 B B B ( G 2 G_2 G2 群):

    B = β 2 + ∑ i = 0 m a i v i ( τ ) 1 2 + s δ 2 B = \\beta2 + \sum{i=0}^m a_i v_i(\tau)1_2 + s\\delta_2 B=β2+i=0∑maivi(τ)12+sδ2

    • 意义: 对 V ( τ ) V(\tau) V(τ) 的加密评估,加上 β \beta β 偏移和 s s s 混淆。
  3. 计算 C C C ( G 1 G_1 G1 群 - 核心推导) : 为了满足配对等式,需根据 A ⋅ B A \cdot B A⋅B 的展开式构造 C C C。

    C = ∑ i = l + 1 m a i β u i ( τ ) + α v i ( τ ) + w i ( τ ) δ 1 + h ( τ ) t ( τ ) δ 1 ⏟ 利用 pk 计算私有部分 + A s + B r − r s δ ⏟ 平衡随机项 C = \underbrace{\sum_{i=l+1}^m a_i \left\\frac{\\beta u_i(\\tau) + \\alpha v_i(\\tau) + w_i(\\tau)}{\\delta}\\right1 + \left\\frac{h(\\tau)t(\\tau)}{\\delta}\\right1}{\text{利用 pk 计算私有部分}} + \underbrace{As + Br - rs\delta}{\text{平衡随机项}} C=利用 pk 计算私有部分 i=l+1∑maiδβui(τ)+αvi(τ)+wi(τ)1+δh(τ)t(τ)1+平衡随机项 As+Br−rsδ

    • 注意 : 计算 B r Br Br 时需要用到 p k pk pk 中的 β 1 \\beta_1 β1 以及 G 1 G_1 G1 上的 V ( τ ) 1 V(\\tau)_1 V(τ)1。

4.4 第三步:验证 (Verification)

验证者接收 π = ( A , B , C ) \pi = (A, B, C) π=(A,B,C) 和公开输入 a p u b = { a 1 , ... , a l } \mathbf{a}_{pub} = \{a_1, \dots, a_l\} apub={a1,...,al}。

  1. 计算公开输入项 L p u b 1 L_{pub}_1 Lpub1:

    L p u b 1 = ∑ i = 0 l a i β u i ( τ ) + α v i ( τ ) + w i ( τ ) γ 1 L_{pub}1 = \sum{i=0}^l a_i \left \\frac{\\beta u_i(\\tau) + \\alpha v_i(\\tau) + w_i(\\tau)}{\\gamma} \\right_1 Lpub1=i=0∑laiγβui(τ)+αvi(τ)+wi(τ)1

  2. 执行配对检查:

    e ( A , B ) = ? e ( α , β ) ⋅ e ( L p u b , γ ) ⋅ e ( C , δ ) e(A, B) \overset{?}{=} e(\alpha, \beta) \cdot e(L_{pub}, \gamma) \cdot e(C, \delta) e(A,B)=?e(α,β)⋅e(Lpub,γ)⋅e(C,δ)

4.5 严谨性推导:为什么等式成立?

将验证等式右边 (RHS) 的指数部分展开,证明其等于 A ⋅ B A \cdot B A⋅B。

RHS 展开:
RHS = α β + L p u b γ + C δ \text{RHS} = \alpha\beta + L_{pub}\gamma + C\delta RHS=αβ+Lpubγ+Cδ

代入 L p u b L_{pub} Lpub 和 C C C 的定义(忽略群同构,看作代数):
= α β + ∑ i = 0 l a i ( β u i + α v i + w i ) ⏟ 公开部分 + ( ∑ i = l + 1 m a i ( β u i + α v i + w i ) + h t ) ⏟ 私有部分 + δ ( A s + B r − r s δ ) = \alpha\beta + \underbrace{\sum_{i=0}^l a_i(\beta u_i + \alpha v_i + w_i)}{\text{公开部分}} + \underbrace{\left( \sum{i=l+1}^m a_i(\beta u_i + \alpha v_i + w_i) + ht \right)}_{\text{私有部分}} + \delta(As + Br - rs\delta) =αβ+公开部分 i=0∑lai(βui+αvi+wi)+私有部分 (i=l+1∑mai(βui+αvi+wi)+ht)+δ(As+Br−rsδ)

合并公开和私有部分的求和 ∑ i = 0 m \sum_{i=0}^m ∑i=0m:
= α β + ( β U ( τ ) + α V ( τ ) + W ( τ ) ) + h ( τ ) t ( τ ) + δ ( A s + B r − r s δ ) = \alpha\beta + (\beta U(\tau) + \alpha V(\tau) + W(\tau)) + h(\tau)t(\tau) + \delta(As + Br - rs\delta) =αβ+(βU(τ)+αV(τ)+W(τ))+h(τ)t(τ)+δ(As+Br−rsδ)

利用 QAP 核心关系 W + h t = U V W + ht = UV W+ht=UV:
= α β + β U + α V + U V + δ ( A s + B r − r s δ ) = \alpha\beta + \beta U + \alpha V + UV + \delta(As + Br - rs\delta) =αβ+βU+αV+UV+δ(As+Br−rsδ)

这正是 A ⋅ B = ( α + U + r δ ) ( β + V + s δ ) A \cdot B = (\alpha + U + r\delta)(\beta + V + s\delta) A⋅B=(α+U+rδ)(β+V+sδ) 的展开形式。

4.6 参数作用总结

  • τ \tau τ: 多项式求值的秘密坐标,保证计算基于 QAP。
  • α , β \alpha, \beta α,β : 强制 A A A 和 B B B 包含特定的线性结构,确保 U V UV UV 乘积被正确构造。
  • γ \gamma γ : 绑定公开输入 。验证者必须使用 v k vk vk 中的 γ \gamma γ 项,无法篡改 Public Input。
  • δ \delta δ : 绑定私有 Witness 。证明者必须使用 p k pk pk 中的 δ \delta δ 项构造 C C C,无法篡改 Private Witness。
  • r , s r, s r,s : 提供零知识性 ,使 A , B A, B A,B 的分布随机化,隐藏真实的 U , V U, V U,V 值。

第五节:实战演练------Keyless Account (Google OIDC) 认证原理

场景目标 : 用户拥有一份由 Google 签发的 JWT (JSON Web Token) ,其中包含 Google 的 RSA 签名。用户想向区块链合约证明:"我是这个 JWT 的拥有者,且这个 JWT 授权了当前交易使用的临时公钥 ( p k e p h pk_{eph} pkeph),但我不想把 JWT 原始内容暴露在链上。"


5.1 初始状态:输入数据 (Inputs)

在将数据喂给 Groth16 之前,我们需要将业务数据转化为有限域 F r \mathbb{F}_r Fr 上的向量。

A. 解向量 (Witness Vector a \mathbf{a} a)

假设电路已经过 R1CS 转换。向量 a \mathbf{a} a 包含所有输入变量:
a = a p u b ∣ a p r i v \mathbf{a} = \\ \\mathbf{a}_{pub} \\ \| \\ \\mathbf{a}_{priv} \\ a= apub ∣ apriv

1. 公开输入 ( a p u b \mathbf{a}_{pub} apub - 链上合约已知):

  • a 0 = 1 \mathbf{a}0 = 1 a0=1 (常数项)
  • a 1 = Hash ( p k e p h , salt_commitment ) \mathbf{a}1 = \text{Hash}(pk_{eph}, \text{salt\_commitment}) a1=Hash(pkeph,salt_commitment) (Nonce/临时公钥指纹)
  • a 2 = Hash ( P K G o o g l e ) \mathbf{a}2 = \text{Hash}(PK_{Google}) a2=Hash(PKGoogle) (Google 公钥指纹)

2. 私有输入 ( a p r i v \mathbf{a}_{priv} apriv - 用户本地持有):

  • a 3 ... k \mathbf{a}3 \\dots k a3...k: JWT Header & Payload (包含用户的 Google ID, iss, aud 等)
  • a k + 1 ... m \mathbf{a}k+1 \\dots m ak+1...m: RSA Signature (Google 对 JWT 的 2048 位数字签名)
  • a m + 1 \mathbf{a}m+1 am+1: Salt (用户隐私盐值)

B. 电路逻辑 (The Circuit Logic)

这个电路包含成千上万个乘法门(主要是 RSA 模幂运算),但核心逻辑可以简化为两个超级约束:

  1. 验签约束 : RSA_Verify ( Payload , Signature , P K G o o g l e ) = = True \text{RSA\Verify}(\text{Payload}, \text{Signature}, PK{Google}) == \text{True} RSA_Verify(Payload,Signature,PKGoogle)==True
  2. 绑定约束 : Payload.nonce = = Hash ( p k e p h , Salt ) \text{Payload.nonce} == \text{Hash}(pk_{eph}, \text{Salt}) Payload.nonce==Hash(pkeph,Salt)

5.2 证明生成 (Prover's Computation - Off-Chain)

用户在本地(浏览器/App)生成证明。他拥有 p k pk pk (Proving Key) 和完整的 Witness a \mathbf{a} a。 为了实现零知识(隐藏 Signature 和 Salt),用户选择随机数 r , s ∈ F r r, s \in \mathbb{F}_r r,s∈Fr。

1. 计算多项式快照

用户将 a \mathbf{a} a 代入基多项式,在秘密点 τ \tau τ 处求值(实际上是通过 p k pk pk 中的椭圆曲线点进行线性组合):

  • U J W T ( τ ) U_{JWT}(\tau) UJWT(τ): 代表 JWT 数据和 RSA 签名的多项式总和。
  • V J W T ( τ ) V_{JWT}(\tau) VJWT(τ): 对应于电路逻辑的右输入总和。
  • W J W T ( τ ) W_{JWT}(\tau) WJWT(τ): 对应于电路逻辑的输出总和。

逻辑正确性保证 : 因为用户的 JWT 签名是真的,且 Nonce 匹配,所以必定存在商多项式 H ( x ) H(x) H(x) 使得: U J W T ( τ ) ⋅ V J W T ( τ ) − W J W T ( τ ) = H ( τ ) t ( τ ) U_{JWT}(\tau) \cdot V_{JWT}(\tau) - W_{JWT}(\tau) = H(\tau)t(\tau) UJWT(τ)⋅VJWT(τ)−WJWT(τ)=H(τ)t(τ)

2. 生成加密点 A , B , C A, B, C A,B,C

用户利用 p k pk pk 计算出三个混淆后的点:

  • 计算 A A A (在 G 1 G_1 G1) : A = α 1 + U J W T ( τ ) 1 + r δ 1 A = \\alpha_1 + U_{JWT}(\\tau)_1 + r\\delta_1 A=α1+UJWT(τ)1+rδ1

    • 隐喻 : 这里面包含了用户的 RSA 签名 信息,但被随机数 r r r 和系统参数 α \alpha α 彻底打乱了。
  • 计算 B B B (在 G 2 G_2 G2) : B = β 2 + V J W T ( τ ) 2 + s δ 2 B = \\beta_2 + V_{JWT}(\\tau)_2 + s\\delta_2 B=β2+VJWT(τ)2+sδ2

    • 隐喻 : 电路验证逻辑的另一半,同样被随机数 s s s 混淆。
  • 计算 C C C (在 G 1 G_1 G1 - 核心粘合剂) : C = 1 δ ( Private p a r t ( β U + α V + W ) + H ( τ ) t ( τ ) ) + ( A s + B r − r s δ ) C = \frac{1}{\delta} \left( \text{Private}_{part}(\beta U + \alpha V + W) + H(\tau)t(\tau) \right) + (As + Br - rs\delta) C=δ1(Privatepart(βU+αV+W)+H(τ)t(τ))+(As+Br−rsδ)

    • 隐喻 : C C C 包含了所有私有数据的校验和,以及商 H H H。它是为了让等式平衡而构造的"补丁"。

输出 : 用户发送 π = ( A , B , C ) \pi = (A, B, C) π=(A,B,C) 和公开的 p k e p h pk_{eph} pkeph 到链上。


5.3 链上验证 (Verifier's Computation - On-Chain Contract)

智能合约(Verifier)不知道 JWT 长什么样,也不知道 Google 签名是多少。它只有 v k vk vk 和用户提交的 p k e p h pk_{eph} pkeph。

1. 构建公开挑战 ( L p u b L_{pub} Lpub)

合约根据接收到的 p k e p h pk_{eph} pkeph 和写死在合约里的 Google 公钥指纹,计算公开输入的线性组合:
L p u b 1 = 1 ⋅ IC 0 + Hash ( p k e p h ) ⋅ IC 1 + Hash ( P K G o o g l e ) ⋅ IC 2 L_{pub}1 = 1 \cdot \\text{IC}_0 + \text{Hash}(pk{eph}) \cdot \\text{IC}_1 + \text{Hash}(PK_{Google}) \cdot \\text{IC}_2 Lpub1=1⋅IC0+Hash(pkeph)⋅IC1+Hash(PKGoogle)⋅IC2

(注: IC i \text{IC}_i ICi 是 v k vk vk 中预计算好的 β u i + α v i + w i γ \frac{\beta u_i + \alpha v_i + w_i}{\gamma} γβui+αvi+wi)

2. 最终配对检查 (The Pairing Check)

合约执行以下指令(消耗约 200k Gas):
e ( A , B ) = ? e ( α , β ) ⋅ e ( L p u b , γ ) ⋅ e ( C , δ ) e(A, B) \overset{?}{=} e(\alpha, \beta) \cdot e(L_{pub}, \gamma) \cdot e(C, \delta) e(A,B)=?e(α,β)⋅e(Lpub,γ)⋅e(C,δ)

5.4 深度解析:为什么这个等式能确权?

让我们看看如果用户作弊会发生什么,以此反推验证的有效性。

情景一:用户拿了一个伪造的 JWT(签名不对)

  1. 在电路运算中,RSA 模幂约束无法满足。
  2. 导致 U ⋅ V − W U \cdot V - W U⋅V−W 产生了一个无法被 t ( x ) t(x) t(x) 整除的余数 R ( x ) R(x) R(x)。
  3. 用户在计算 C C C 时,无法消除分母中的 δ \delta δ(因为余数项没法除尽)。
  4. 为了强行生成 C C C,用户只能瞎填一个点。
  5. 链上验算时: e ( C , δ ) e(C, \delta) e(C,δ) 产生的值将无法填补 e ( A , B ) e(A, B) e(A,B) 展开后的缺口。
  6. 结果:验证失败。

情景二:用户拿了别人的真实 JWT(偷来的),但想绑定自己的 Key

  1. JWT 签名是真的,RSA 约束通过。
  2. 但是 Nonce 绑定约束 失败:
    JWT.nonce ≠ Hash ( p k u s e r _ f a k e , salt ) \text{JWT.nonce} \neq \text{Hash}(pk_{user\_fake}, \text{salt}) JWT.nonce=Hash(pkuser_fake,salt)
  3. 同样导致多项式无法整除。
  4. 结果:验证失败。

情景三:用户想根据 A , B A, B A,B 反推 Google 签名

  1. A = α + U + r δ A = \alpha + U + r\delta A=α+U+rδ。
  2. 由于 r r r 是用户本地生成的随机数,对于链上观察者来说, A A A 只是一个随机点。
  3. 根据离散对数难题 ,无法从点 A A A 还原出数值 U U U。
  4. 结果:隐私 100% 安全。

5.5 总结:Groth16 在 Keyless 中的数据流

步骤 数据状态 可见性 含义
Input JWT_String, Signature, Salt Private (用户本地) 原始凭证
Circuit RSA_Check, Nonce_Check Public (电路逻辑) 验证规则
Proof A , B , C A, B, C A,B,C (三个椭圆曲线点) Public (链上) "我知道凭证"的数学证据
Verify e ( A , B ) = ... e(A,B) = \dots e(A,B)=... Public (合约执行) 零知识放行

通过 Groth16,区块链合约得以在看不见 Google 签名的情况下,确信 Google 确实为该用户签发了证书。

相关推荐
vibecoding日记7 小时前
双非如何快速入职字节等大厂大模型?真实案例分析:推理优化和投机解码
算法·求职·大模型工程师
yszaygr213810 小时前
Verilog参数化游程编码RLE模块
算法
望易10 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络14 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
HjhIron1 天前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术2 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望2 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法