bellman是Zcash团队用Rust语言开发的一个zk-SNARK软件库,实现了Groth16算法。
项目地址:https://github.com/zcash/librustzcash/tree/master/bellman
1. 总体流程
总体流程大致可以分为以下几个步骤:
1.将问题多项式拍平(flatten),构建对应的电路(Circuit)。这一步是由上层应用程序配置的。
2.根据电路生成R1CS(Rank 1 Constraint System)
3.将R1CS转化为QAP(Quadratic Arithmetic Program)。传统做法是通过拉格朗日插值,但是为了降低计算复杂度,可以通过快速傅立叶变换来实现。
4.初始化QAP问题的参数,即CRS(Common Reference Strings)
5.根据CRS和输入创建proof
6.验证proof
下面依次介绍各个步骤的细节。
2. Setup阶段:
Setup阶段最主要的工作是生成CRS数据,相关公式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ykwhzTEF-1594742340878)(零知识证明|bellman源码分析.resources/54C36D90-F201-4370-A78D-565031AAFFD9.png)]
注1:公式中的x对应代码中的变量tau,相应的 x i x^i xi对应于powers_of_tau。
注2: t ( τ ) = ( τ − ω 0 ) ( τ − ω 1 ) . . . ( τ − ω n − 1 ) = τ n − 1 t(\tau)=(\tau-\omega^0)(\tau-\omega^1)...(\tau-\omega^{n-1})=\tau^{n}-1 t(τ)=(τ−ω0)(τ−ω1)...(τ−ωn−1)=τn−1 ,代码中的powers_of_tau.z(&tau)
就是计算该值。
2.1 参数数据结构
pub struct VerifyingKey<E: Engine> {
pub alpha_g1: E::G1Affine,
pub beta_g1: E::G1Affine,
pub beta_g2: E::G2Affine,
pub gamma_g2: E::G2Affine,
pub delta_g1: E::G1Affine,
pub delta_g2: E::G2Affine,
pub ic: Vec<E::G1Affine>
}
其中 i c = β u i ( τ ) + α v i ( τ ) + w i ( τ ) γ ic=\frac{\beta u_i(\tau) + \alpha v_i(\tau) + w_i(\tau)}{ \gamma} ic=γβui(τ)+αvi(τ)+wi(τ)
pub struct Parameters<E: Engine> {
pub vk: VerifyingKey<E>,
pub h: Arc<Vec<E::G1Affine>>,
pub l: Arc<Vec<E::G1Affine>>,
pub a: Arc<Vec<E::G1Affine>>,
pub b_g1: Arc<Vec<E::G1Affine>>,
pub b_g2: Arc<Vec<E::G2Affine>>
}
其中 h = τ i t ( τ ) δ h=\frac{\tau^i t(\tau)}{\delta} h=δτit(τ), l = β u i ( τ ) + α v i ( τ ) + w i ( τ ) δ l=\frac{\beta u_i(\tau) + \alpha v_i(\tau) + w_i(\tau)}{\delta} l=δβui(τ)+αvi(τ)+wi(τ)
最后3个参数a, b_g1, b_g2似乎公式中没有出现,实际上它们是根据 x i x^i xi算出来的QAP多项式的值,也就是 [ u ( x ) ] 1 , [ v ( x ) ] 1 , [ v ( x ) ] 2 [u(x)]_1,[v(x)]_1,[v(x)]_2 [u(x)]1,[v(x)]1,[v(x)]2,后面在计算proof的时候会用到。以a为例,假设其中一个多项式的系数等于 c 0 , c 1 , . . . , c n − 1 c_0,c_1,...,c_{n-1} c0,c1,...,cn−1,则 a = Σ i = 0 n − 1 c i x i