Plonk 于2019年由Aztec研究团队提出,和zk-SNARK相比,增强的优势主要有:
(1)通用性,即可信设置与应用无关,仅需要一次可信设置,可以满足所有(电路门数在一定限制内,目前zksync电路门数在 2^20 ~ 2^26之间)的应用;
(2)可更新: setup参数可以任意更新,只要有一个可信参与者,即可保证可信设置的安全性。
原理介绍
Plonk约束系统
与Groth16中采用的R1CS不同,Plonk约束系统的数学表达式为:
其中 代表左边, 代表右边, 代表输出, 代表乘法, 代表常量, 代表左输入, 代表右输入, 代表电路输出, 代表第 个门电路。
多项式转换
类似STARKS或QAPs, 可以利用多项式转换将多个约束融合进一个多项式中, 可以大幅减化零知识证明验证。利用Lagrange插值或FFT变换,将上述步骤中的电路转化为多项式形式,即
其中 为选择多项式。
复制约束
上述的约束系统只是单独对每个电路进行约束,对于电路与电路之间的相互约束无法实现,例如如下述电路中,要约束 ,就需要复制约束(copy constraints)。
Vitalik通过对坐标累加器实例对复制约束作了介绍,例如对于坐标上的点
设定, , 定义坐标累加器为:
其中 , , , 可以得到 。
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
-2 | 1 | 0 | 1 | ||
-1 | 6 | 5 | 8 | ||
1 | -1 | -6 | -30 | -240 |
同理对于点: , 则, , 同样可以得到。
0 | 3 | 2 | 1 | 4 | |
---|---|---|---|---|---|
-2 | 1 | 0 | 1 | ||
-1 | 8 | 5 | 6 | ||
1 | -1 | -8 | -40 | -240 |
的原因为。
上述性质可以推广到跨 集合的复制约束,即对于的复制约束,需要保证:
例如对于某个电路的输出,又作为某些电路的输入, 其中代表索引值,或 电路的值。
生成置换:
为了保证满足复制约束,需要检查:
Plonk证明
-
检查门电路约束
其中: -
检查复制约束
多项式边界条件为:
-
与应用相关的输入:
- , 其中为编码公开输入,需要在运行时计算。
- 置换多项式:
-
用户提供的输入:
-
电路的输入赋值:
-
坐标累加器:
-
商多项式:
-
Plonk协议
置换协议
对于两个长度为 的序列和, 证明者要证明, , 为某个置换,协议过程如下:
-
验证者发送随机值 给证明者;
-
证明者构造两个新的序列: 和, 其中
-
证明者计算新的序列, 其中
即
即为所谓的grand product。证明者将 序列发给验证者。
-
验证者检查以下方程:
其中表示单位元的根,表示对序列的多项式插值。
若验证通过, 则验证者确信成立, 。
多项式承诺
多项式承诺是plonk证明过程中采用的一个基本工具,在不泄露多项式的情况下,使验证者确信对于某个, 是正确的计算结果。
(1) 首先需要计算多项式承诺,为 ,其中为可信设置密秘选取的值,为椭圆曲线基点;
(2) 为了验证f(z), 证明者需要计算:
然后将的承诺发给验证者;
(3) 验证者通过双线性对进行验证:
Plonk协议
-
证明约束
-
预处理输入
-
输入数据
公开输入:, 隐私输入:
-
证明过程
证明过程主要分为以下5轮:
(1)
生成随机盲化标量
生成多项式:
计算承诺第1轮的输出为: .
(2)
计算置换挑战 :
计算置换多项式:
计算第2轮的输出为:
(3) 计算商多项式挑战 :
计算商多项式:
将 分割为次数小于 的多项式 和 次数小于等于的多项式, 即
计算
第3轮输出为:
(4) 计算挑战值 :
计算多项式打开的值:
计算线性多项式:
计算线性多项值:
第4轮的输出为:
(5) 计算挑战值:
计算打开证明的多项式 :
计算打开证明的多项式 :
计算承诺
第5轮的输出为:。
最终生成的证明为:
最后计算多点估值挑战 :
生成的证明约为800 Byte.
- 验证过程
验证者预处理的输入为:
验证密钥约为576 Byte.
验证的过程如下:
(1) 验证;
(2) 验证;
(3) 验证 ;
(4) 计算挑战值 ;
(5) 计算零值多项式: ;
(6) 计算拉格朗日多项式: ;
(7) 计算公开输入多项式: ;
(8) 计算商多项式:
(9)计算部分批量多项式承诺: :
(10)计算全部多项式承诺 :
(11) 计算批量多项式估计:
(12) 采用双线性对进行验证:
实现过程
可信设置
可信设置主要生成CRS (Common Reference String), 对于 个电路的可信设置,需要生成 个元素:
其中, 为椭圆曲线的生成元, 秘密参数,即需要丢弃的有毒废料。可信设置与应用无关。
pub struct Crs<E: Engine, T: CrsType> {
pub g1_bases: Arc<Vec<E::G1Affine>>,
pub g2_monomial_bases: Arc<Vec<E::G2Affine>>,
_marker: std::marker::PhantomData<T>
}
实际生成的 g1_bases
的长度为, 即 为使 的最小整数。
应用相关设置
- 电路生成
为了便于R1CS转化为了Plonk约束系统,zksync 1.0 在实现Plonk的时候对算法进行了部分改进,见文档, Plonk约束系统的数学表达式为:
其中 代表左边, 代表右边, 代表输出, 代表乘法, 代表常量, 代表左输入, 代表右输入, 代表电路输出,代表 的下一步, 代表第 个门电路。
#[derive(Debug, Clone)]
pub struct GeneratorAssembly<E: Engine, P: PlonkConstraintSystemParams<E>> {
m: usize, //
n: usize, // 电路个数
input_gates: Vec<(P::StateVariables, P::ThisTraceStepCoefficients, P::NextTraceStepCoefficients)>, //公开输入的电路,第一个状态变量赋值为-1, 其余为0
aux_gates: Vec<(P::StateVariables, P::ThisTraceStepCoefficients, P::NextTraceStepCoefficients)>, //隐私输入的电路,包括状态变量和系数值
num_inputs: usize, // 公开输入的个数,起始值为1
num_aux: usize, //隐私输入的个数,起始值为1
inputs_map: Vec<usize>,
is_finalized: bool //标记电路是否生成完毕
}
- 多项式计算
将上述步骤中的电路转化为多项式形式,即
其中 为选择多项式, 为下一步多项式, 为置换多项式。
pub struct SetupPolynomials<E: Engine, P: PlonkConstraintSystemParams<E>> {
pub n: usize, // 电路总个数
pub num_inputs: usize, //公开输入的个数
pub selector_polynomials: Vec<Polynomial<E::Fr, Coefficients>>, //选择多项式
// 下一步多项式
pub next_step_selector_polynomials: Vec<Polynomial<E::Fr, Coefficients>>,
//置换多项式
pub permutation_polynomials: Vec<Polynomial<E::Fr, Coefficients>>,
pub(crate) _marker: std::marker::PhantomData<P>,
}
-
生成验证密钥
根据setup生成的验证密钥为:
#[derive(Clone, Debug)] pub struct VerificationKey<E: Engine, P: PlonkConstraintSystemParams<E>> { pub n: usize, //总的电路门数 pub num_inputs: usize, // 公开输入的个数 pub selector_commitments: Vec<E::G1Affine>, //选择多项式承诺 pub next_step_selector_commitments: Vec<E::G1Affine>, // 下一步多项式承诺 pub permutation_commitments: Vec<E::G1Affine>, // 置换多项式承诺 pub non_residues: Vec<E::Fr>, // 二次非剩余 pub g2_elements: [E::G2Affine; 2], //可信设置生成的参数 pub(crate) _marker: std::marker::PhantomData<P>, }
证明过程
证明主要包括五步,主要思路为计算多项式的整除,生成Kate 多项式的承诺及估值。
#[derive(Clone, Debug)]
pub struct Proof<E: Engine, P: PlonkConstraintSystemParams<E>> {
pub num_inputs: usize, // 公开输入个数
pub n: usize, // 总的电路门数
pub input_values: Vec<E::Fr>, // 公开输入的值
pub wire_commitments: Vec<E::G1Affine>, // witness的承诺
pub grand_product_commitment: E::G1Affine, // z多项式的承诺
pub quotient_poly_commitments: Vec<E::G1Affine>, //商多项式t的承诺
pub wire_values_at_z: Vec<E::Fr>, //witness多项式式在z点的值
pub wire_values_at_z_omega: Vec<E::Fr>, //witness多项式在zw点的值
pub grand_product_at_z_omega: E::Fr, //z多项式在zw点的值
pub quotient_polynomial_at_z: E::Fr, //商多项式在z点的值
pub linearization_polynomial_at_z: E::Fr, //线性多项式r在z点的值
pub permutation_polynomials_at_z: Vec<E::Fr>, //置换多项式在z点的值
pub opening_at_z_proof: E::G1Affine, //在z点的承诺证明
pub opening_at_z_omega_proof: E::G1Affine, //在zw点的承诺证明
pub(crate) _marker: std::marker::PhantomData<P>,
}
验证过程
验证主要是对商多项式和Kate多项式承诺的检查。
pub fn verify<E: Engine, P: PlonkConstraintSystemParams<E>, T: Transcript<E::Fr>>(
proof: &Proof<E, P>, // 验证的证明
verification_key: &VerificationKey<E, P>, //验证密钥
transcript_init_params: Option< <T as Prng<E::Fr> >:: InitializationParameters>,
) -> Result<bool, SynthesisError> {
let (valid, _) = verify_and_aggregate::<E, P, T>(proof, verification_key, transcript_init_params)?;
Ok(valid)
}
性能测试
证明生成时间和验证时间分别如下:
和Groth16性能比较如下:
Plonk | Groth16 | |
---|---|---|
MiMC 证明时间 | 5.6s | 16.5s |
SHA-256 证明者时间 | 6.6s | 1.4s |
验证者Gas消耗 | 223K | 203K |
证明size | 0.51kB | 0.13kB |
参考
https://eprint.iacr.org/2019/953
https://vitalik.ca/general/2019/09/22/plonk.html
https://research.metastate.dev/plonk-by-hand-part-1/
https://github.com/matter-labs/proof_system_info_v1.0/blob/master/PlonkUnrolledForEthereum.pdf
https://research.metastate.dev/on-plonk-and-plookup/
网友评论