前言
隐私研究院【PrivacyIN】第一期ZK训练营课程精讲内容上线啦,本期课堂邀请到美国德州农工大学(Texas A&M University)计算机科学与工程学院的助理教授张宇鹏,主要介绍经典零知识证明协议设计原理,课堂主题为《Basic Principles of the Classic ZK Protocols (Groth16 Plonk Stark)》。
此次授课采取小班授课,邀请了数十名来自国内外密码学及相关领域的专家学者作为学员,参加了高强度的90分钟的密码学培训课堂。
课程精讲全文
零知识证明(Zero-Knowledge-Proofs)自1985年由Goldwasser、Micali和 Rackof首次提出至今,随着零知识证明理论和技术的进步,涌现出很多经典零知识证明系统,比如:Groth16,Pinocchio,Plonk,Marlin,Stark,Halo2等,这些零知识证明系统推动着零知识证明从理论逐步进入实用应用,同时理解这些协议的工作机制和构造原理,对于设计ZKP应用系统有着非常重要意义。
本期课堂张宇鹏老师分别对这三种典型协议(non-universal)SNARK、PLONK和STARK进行设计原理分析,主要内容有:多项式承诺、密码学数论简介、PlONK协议、SNARK类协议、STARK协议等。
课堂开始,张宇鹏老师首先对上一堂课的零知识证明系统进行简单回顾,帮助同学们加深对ZKP概念和计算模型的理解。
多项式承诺
多项式承诺(polynomial commitment)是构造零知识证明系统常用密码学工具,其构造模型中prover/verifer为主要参与者,使用交互证明方式构造(可以使用Fiat–Shamir-heuristic转换为非交互方式)。实际可以认为多项式承诺是一个种特殊的零知识证明,其同样满足零知识证明的Correctness、Soundness、Zero-knowledge这些特性。
多项式承诺的基本原理是:
- prover拥有一个多项式,其构建一个关于这个多项式的承诺commitmentδf,然后将承诺δf发送给verifier
- verifier收到的承诺commitmentδf,任意取一点a,发送该点给prover,以请求计算该点上的结果
- prover接收计算请求,使用多项式在a点计算得到f(a),并生成一个证明proof,然后将f(a)和证明proof都发给verifer进行验证
很多经典的零知识证明协议都基于多项式承诺进行构造,比如Plonk、Dark、Stark、Supersonic等。
KZG多项式承诺是非常经典高效的一种多项式承诺构造实现,尤其在Plonk协议中是非常基础的组件。KGZ多项式承诺基于Bilinear-Pairing和生成群(注:后续内容将详细介绍),其中生成群一般为基于椭圆曲线在一个有限域中生成(如选取椭圆曲线后确定g),KGZ承诺主要步骤:
- trust setup生成参数
一般为选取公共参数素数p和g(关联一条椭圆曲线),使用MPC仪式生成:
$$ \left\{ \begin{matrix} g,g^{s},g^{s^{2}},g^{s^{3}},\cdots,g^{s^{d}} \end{matrix} \right\} $$
其中s为随机数且生成过程中将会被丢弃(s保持为秘密)
- 创建承诺和证明
生成群具备加法同态和scale乘法性质,承诺表示为:
$$ g^{f(s)}=g^{\sum{c_{i}s^{i}}}=\Pi\left(g^{s^{i}}\right)^{c_{i}} $$
- 承诺+proof验证
使用Bilinear-Pairing验证:
$$e(g^f(s)/g^f(a),g)=e(g^{s-a},g^{q(s)}$$
是否成立,也即验证了f(s)-f(a)=(s-a)q(s)成立。
密码学数论基础
零知识证明有着非常重的数论理论要求,为了克服重度的数学问题,帮助大家理解经典协议构造背后的数学原理,课程中张宇鹏老师带领大家从最基本的素数定义和模运算开启数论的学习。
素数p,是一个数p大于或等于2且只能被自身p和1整除的整数;
模态算术,是指任何数或者其算术运算值(包括中间运算)都需要模上指定的正整数(如p),这能保证模态运算后的数都落在(0,p)之间,比如模13运算:
-1mod13=-1 +1x13=12;
-1+2mod13,即:(-1mod13)+(2mod13)=(12+2)mod13=1。
群Group是定义在数集合上,对某个运算符满足:
- 封闭性closure(群中的元素,执行该操作符运算后依然在定义的群中)
- 结合律associativity(群中的元素对于该定义操作符运算满足交换律,如:(a+b)+c=a+(b+c))
- 零元identity element(群中存在一个元素e,任何群中的元素与e执行该定义操作都为元素本身)
- 逆元inverse element(群中的任何元素a,都存在一个群中的元素b,满足a+b=e)
例如,对加法+的整数群,对加法取模整数群。
域Field是一个群Group,对于操作(+,x)满足:
- 域Field是一个加法群
- 域Field是一个剔除加法零元,在「x」操作上的一个群
有理数、实数、复数、整数模素数p(有限域)都是域,有限域是密码学很常用的。
有限域有一个特性,其总是可以找到了一个生成元(Generator),生成元对自己循环乘法操作能够得到有限域所有元素,也即得到一个循环群,因此可以用生成元生成的指数形式元素作为有限域的表示,另外目前具备快速的算法能够找到有限域的生成元。
双线性对Bilinear-Pairing一个非常高效的密码学工具,其将一个base乘法循环群中的两个元素对,映射到一个目标target群,即:
$$ e(p^a,Q^b)=e(P,Q)^ab:G \times G \rightarrow G_T $$
Bilinear-Pairing可以用来验证乘法循环群元素间的乘法关系(是否相等),但是不能用来计算,其实现较为复杂,课程中主要介绍了Bilinear-Pairing的运算特性,并提供使用范例,如:
$$e(g^a,G^b)=e{(g,g)}^ab=e(g^ab,g)$$
PLONK协议
为了更好地讲解Plonk构造原理,张宇鹏老师给出一个通用的ZKP构造模型,其中prover拥有秘密数据secret data,计算问题转换为通用的电路C计算问题,prover向verifier证明自己使用secret data作为输入并执行电路得到输出,verifier验证prover的证明proof是否正确。
Plonk协议是一种universal-trusted-setup的零知识证明协议,它使用SRC(Structure-Reference-String)形如:
$$ \left\{ \begin{matrix} g,g^{s},g^{s^{2}},g^{s^{3}},\cdots,g^{s^{d}} \end{matrix} \right\} $$
的结构化参数,这些参数具备通用、可更新的特性。Plonk主要通过设计独特的电路表示,基于KZG承诺和置换permutation来实现。Plonk电路门使用Plonkish格式(区别于R1CS)统一来表示电路门的约束,即:
$$q_{L_i}a_i+q_{R_i}b_i+q_{M_i}a_i \times b_i+q_{O_i}c_i+q_{c_i}=0$$
这样加、乘、公开输入、输出都可以用这个式子表达。
例如加法门可以表示为:
$$q_{L_1}=1,q_{R_1}=1,q_{M_1}=0,q_{O_1}=-1,q_{c_1}=0$$
例如乘法门可以表示为:
$$q_{L_2}=0,q_{R_2}=0,q_{M_2}=1,q_{O_2}=-1,q_{c_1}=0$$
Plonk协议构建主要分为两大部分:电路门约束处理和复制(线)约束处理。
电路门约束处理主要步骤:
prover、verifier预处理,使用多项式插值求解得到系数多项式qL(x)、qR(x)、qM(x)、qO(x)、qC(x);prover得到电路门线输入多项式a(x)、b(x)、c(x),其求解的插值为元根:
$$x=w^i,i=0,\ldots,n-1$$
prover这些多项式压缩成一个多项式,并接着可以得到一个目标多项式t(x):
(注:t(x)原论文实现是由电路门约束和复制约束构建两部分的多项式复合而成的)
prover使用KZG承诺创建a(x)、b(x)、c(x)、t(x)作为证明,提供给verifier进行承诺打开验证正确性。
Plonk的复制约束主要思路是,通过将相等的电路线进行置换(重排),置换后的元素和元素是相等同的,引入置换多项式,然后进一步转换为等价约束多项式:
并最终转换为基于拉格朗日多项式的特殊多项式Z(X),然后使用这个多项式和门约束多项式构成一个压缩的新多项式进行证明和验证。
复制(线)约束的处理主要步骤:
prover和verifier预处理,多项式插值求解置换permutation多项式:
$$S_{ID}(x),S_\delta(x)$$
(注:Plonk原论文使用类似多个permutation函数,原理相似)
- prover对Z(x)等多项式进行KZG承诺,输出证明。
- verifier进行KZG承诺打开和多项式关系正确性验证。
Plonk协议整体执行:
Plonk协议整体执行实际就是对门约束和复制约束的处理,然后构建一个大的门约束和复制约束关联的大多项式约束,主要基于KZG多项式承诺和拉格朗日插值来构建完整协议,最后使用Bilinear-Pairing进行验证。
SNARK协议
传统的SNARK协议,主要是指使用非通用trusted-setup生成零知识证明所需要得公共参数和公共key(证明key和验证key),一般基于Billinear-Pairing构建的简洁非交互零知识证明协议,这里比较经典的构造有Pinocchio和Groth16协议,它们主要是使用R1CS构建电路约束,然后转换为QAP构建多项式证明,并使用Billinear-Pairing对多项式进行验证。
传统的SNARK计算问题一般工作流程如下:
- 将一个计算问题转换为电路问题(表示为电路)
- 将电路表示为R1CS约束(乘法门约束)
- 将R1CS约束通过多项式插值求解得到QAP,将QAP多项式和目标多项式t(x)转换到加密形式的群G,作为证明部分
使用Billinear-Pairing对QAP多项式和目标多项式t(x)进行验证:
$$ \text { Verification: } e\left(\pi_{1}, \pi_{2}\right) / e\left(\pi_{3}, g\right)=e\left(g^{t(s)}, \pi_{4}\right) $$
STARK协议
STARK是一种无需trusted-setup的简洁非交互零知识证明协议,STARK前端主要采用RAM(Random-Access-Memory)Program的方式进行协构建,一个典型的RAM-program由CPU(包括很多寄存器等), 内存Memory,程序执行指令program等组成。
STARK将证明问题转换为证明RAM Program是否正确地执行,这跟传统zkSNARK协议验证电路执行有很大地差异。STARK使用RAM Program进行前端程序构造使得设计程序可以以很少指令代码来运行大批量次数和循环的指令步骤执行,而不会限制于电路大小;Random Access操作在常数复杂度等优点。
STARK使用RAM-to-cuirt-Reduction的技术进行证明,其将整个计算过程中所有跟RAM的交互、CPU State的变化等记录下来,然后连接或聚合起来,并转换成类似电路形式约束去证明和验证RAW Program是否执行正确。
STARK的算数运算是通过一系列的多项式来表示的,如程序执行步骤1的状态为P1(X,⋯,Y),执行步骤2的状态为P2(X,⋯,Y),每个步骤可以构造一个多项式。
STARK的后端实现可以将执行步骤多项式转换为类似SNARK或Plonk方式的多项式约束,然后在某个degree上进行Random linear combination构建一个大的验证多项式,用来证明和验证程序执行正确性。
实际上STARK使用基于默克尔树的FRI protocol (low degree test)来实现后端构建,另外STARK中还需要进行额外的Permutation测试和公共约束,FRI部分的理论较为复杂,课堂中没有深入探讨。
自由讨论环节,张宇鹏耐心地为学员解答了一系列关于协议设计原理的相关问题。
关PrivacyIN
PrivacyIN 隐私学院 (Privacy Institution) 由LatticeX基金会发起,致力于建设开放的密码和隐私技术布道和研究社区。联合全球顶尖的学者、隐私技术开发者推动ZK(零知识证明)、MPC(安全多方计算)、FHE(全同态密码)的创新和落地。
关于LatticeX基金会
LatticeX基金会(LatticeX Foundation)是一家全球范围的开源技术社区,以通过构建复杂计算归还用户数据主权,保护数据隐私,实现数据价值交换为愿景,旨在构建一个完全去中心化的计算互操作网络,在保护数据主权和隐私的前提下促进数据使用权的交易,并为实现LatticeX愿景资助各类学术研究及科研项目。