Nova代码解析

1. 引言

前序博客有:

微软团队2021年论文 《Nova: Recursive Zero-Knowledge Arguments from Folding Schemes》。
本文主要解析代码见:

其主要依赖的库有:

2. 各R1CS基本类型定义

基本类型定义见traits/mod.rs

  • Base:某group的base域内元素。
  • Scalar:某group的scalar域内元素。
  • CompressedGroupElement:某group元素的压缩表示。
  • GroupElement:对压缩group元素的解压缩表示。
  • PreprocessedGroupElement:表示preprocessed group元素。
  • RO:表示某电路友好的sponge类型:其消耗base域元素,挤出scalar域元素。【以RO来定义某哈希函数,实际采用了Poseidon哈希函数】
  • ROCircuit:将RO表示为电路模式。
  • TE:外化proof时所使用的通用Fiat-Shamir transcript。【实际采用了SHA-3(Keccak)哈希函数】
  • CE:基于group scalar值的承诺机制。【实际采用了Pedersen承诺机制】
  • ROConstants:与RO相关的哈希函数常量值。
  • ROConstantsCircuit:与ROCircuit相关的哈希函数常量值。

在这里插入图片描述
相关结构定义见:src/r1cs.rs中:

  • 0)R1CS公共参数定义:【主要用于构建返回公共参数CommitmentKey,其长度取num_cons(约束数)、num_vars(witness W向量长度)、total_nz(A、B、C三个矩阵元素总数之和) 的最大值的next_power_of_two(),】
    pub struct R1CS<G: Group> {
      _p: PhantomData<G>,
    }
    
  • 1)标准R1CS结构中A、B、C矩阵定义:
    • 矩阵A、B、C的列数为:num_vars + num_io + 1,与向量 Z = ( W , u , x ) Z=(W,u,x) Z=(W,u,x)的长度一致,即列号的取值范围为0~(num_vars + num_io)。
    • 矩阵A、B、C的行数num_cons:即对应为总约束数。
    /// A type that holds the shape of the R1CS matrices
    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
    pub struct R1CSShape<G: Group> {
      pub(crate) num_cons: usize, // 矩阵A、B、C的行数,即行号取值范围为0~num_cons-1
      pub(crate) num_vars: usize, // witness $W$ 向量长度
      pub(crate) num_io: usize, // public input/output $x$ 向量长度
      pub(crate) A: Vec<(usize, usize, G::Scalar)>, // 矩阵A以一维向量表示,其中每个元素的格式为(行号,列号,值)
      pub(crate) B: Vec<(usize, usize, G::Scalar)>,
      pub(crate) C: Vec<(usize, usize, G::Scalar)>,
    }
    
  • 2)R1CS instance-witness定义为:【对应Az * Bz = Cz】
    /// A type that holds a witness for a given R1CS instance
    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
    pub struct R1CSWitness<G: Group> {
      W: Vec<G::Scalar>,
    }
    
    /// A type that holds an R1CS instance
    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct R1CSInstance<G: Group> {
      pub(crate) comm_W: Commitment<G>,
      pub(crate) X: Vec<G::Scalar>,
    }
    
  • 3)relaxed R1CS instance-witness定义为:【对应Az * Bz = u*Cz + E】
    /// A type that holds a witness for a given Relaxed R1CS instance
    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
    pub struct RelaxedR1CSWitness<G: Group> {
      pub(crate) W: Vec<G::Scalar>,
      pub(crate) E: Vec<G::Scalar>,
    }
    
    /// A type that holds a Relaxed R1CS instance
    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct RelaxedR1CSInstance<G: Group> {
      pub(crate) comm_W: Commitment<G>,
      pub(crate) comm_E: Commitment<G>,
      pub(crate) X: Vec<G::Scalar>,
      pub(crate) u: G::Scalar,
    }
    

在这里插入图片描述

当采用Spartan来压缩最终的IVC proof时,需将 ( u , x ) ~ \widetilde{(u,x)} (u,x) 以multilinear多项式表示,则要求 ( u , x ) (u,x) (u,x)填充后的长度为power of two,同时要求未填充的 x x x向量的长度为偶数:

	// We require the number of public inputs/outputs to be even
    if num_io % 2 != 0 {
      return Err(NovaError::OddInputLength);
    }

在这里插入图片描述

2.1 R1CSShape中关键函数

R1CSShape中关键函数有:

  • 1)new():明确创建特定的R1CS矩阵,会对矩阵向量的行列号做是否越界判断。
  • 2)multiply_vec():计算AZ、BZ、CZ矩阵与向量乘积,结果为三个向量值。
  • 3)is_sat_relaxed(ck, U, W):判断一组relaxed R1CS instance-witness是否satisfiable,即需同时满足以下条件:
    • 3.1)witness 中的W.W、W.E向量长度应分别为num_vars和num_cons,instance中的U.X向量长度应为num_io。
    • 3.2)满足Az * Bz = u*Cz + E,其中z=(W.W, U.u, U.X)
    • 3.3)承诺值匹配,即U.comm_W== commit(ck, W.W) 且 U.comm_E== commit(ck, W.E)。
  • 4)is_sat(ck, U, W):判断一组标准 R1CS instance-witness是否satisfiable,即需同时满足以下条件:
    • 4.1)witness 中的W.W向量长度应为num_vars,instance中的U.X向量长度应为num_io。
    • 4.2)满足Az * Bz = Cz,其中z=(W.W, 1, U.X)
    • 4.3)承诺值匹配,即U.comm_W== commit(ck, W.W)。
  • 5)commit_T(ck, U1, W1, U2, W2):计算committed relaxed R1CS folding scheme中的交叉项T的承诺值。其中(U1, W1)为relaxed R1CS instance-witness,(U2, W2)为标准R1CS instance-witness,即有U2.u=1且W2.E为零向量。
    • 5.1)计算: T = A Z 1 ∘ B Z 2 + A Z 2 ∘ B Z 1 − u 1 ⋅ C Z 2 − u 2 ⋅ C Z 1 T=AZ_1\circ BZ_2+AZ_2\circ BZ_1-u_1\cdot CZ_2-u_2\cdot CZ_1 T=AZ1BZ2+AZ2BZ1u1CZ2u2CZ1
    • 5.2)计算T的承诺值commit(ck, T)。
  • 6)pad():当采用Spartan来压缩最终的IVC proof时,需将 W ~ ( ⋅ ) 、 A ~ ( ⋅ , ⋅ ) 、 B ~ ( ⋅ , ⋅ ) 、 C ~ ( ⋅ , ⋅ ) 、 ( u , x ) ~ \widetilde{W}(\cdot)、\widetilde{A}(\cdot,\cdot)、\widetilde{B}(\cdot,\cdot)、\widetilde{C}(\cdot,\cdot)、\widetilde{(u,x)} W ()A (,)B (,)C (,)(u,x) 以multilinear多项式表示,要求将A、B、C矩阵的行列数均填充为power of two;要求将W向量的长度填充为power of two;要求将 ( u , x ) (u,x) (u,x)的长度填充为power of two。为便于表示,实际填充时,取 A、B、C矩阵行数 与 W向量长度 的最大值的next_power_of_two() 为m。
    本pad()函数仅对R1CSShape即A、B、C矩阵的行列进行填充。若只需做行填充,则直接改变num_cons参数值即可;若需做列填充,则将A、B、C 第 “c > (num_vars-1)” 列之后的值的列号调整为"c + m - num_vars"。

2.2 R1CSWitness中关键函数

R1CSWitness中关键函数有:【供Prover调用】

  • 1)new():根据R1CSShape和W向量构建R1CSWitness,要求R1CSShape的num_vars 必须等于 W向量的长度。
  • 2)commit():对R1CSWitness的W向量进行承诺。

2.3 R1CSInstance中关键函数

R1CSInstance中关键函数有:【供Verifier和Prover调用】

  • 1)new():根据R1CSShape、comm_W和X向量构建R1CSInstance,要求R1CSShape的num_io 必须等于 X向量的长度。
  • 2)absorb_in_ro():将R1CSInstance absorb到RO中。注意:
    • comm_W中的base域元素可直接absorb;
    • x向量中的每个scalar域元素需以4个64 bit表示,再逐个scalar_as_base()转换为base域再absorb。【此时需考虑 无需考虑域转换时的溢出问题。】

2.4 RelaxedR1CSWitness中关键函数

RelaxedR1CSWitness中关键函数有:【供Prover调用】

  • 1)default():设置RelaxedR1CSWitness中W和E均为零向量。
  • 2)from_r1cs_witness():根据R1CSWitness设置RelaxedR1CSWitness,其中E为零向量。
  • 3)commit():分别对W和E向量进行承诺。
  • 4)fold(W1, W2, T, r):将R1CSWitness W2 fold到 RelaxedR1CSWitness (W1, E1) 中,其中T为上面算的cross term,r为Verifier发送的random challenge。输出为RelaxedR1CSWitness (W, E)。
    实际就是计算: W = W 1 + r ⋅ W 2 , E = E 1 + r ⋅ E 2 W=W_1+r\cdot W_2,E=E_1+r\cdot E_2 W=W1+rW2,E=E1+rE2
  • 5)pad():分别基于R1CSShape的num_vars和num_cons,将W和E向量补零到相应的长度。

2.5 RelaxedR1CSInstance中关键函数

RelaxedR1CSInstance中关键函数有:【供Verifier 和 Prover调用】

  • 1)default():RelaxedR1CSInstance中的comm_W和comm_E为默认群元素,u为scalar零值,X为长度为num_io的零向量。
  • 2)from_r1cs_instance():根据R1CSInstance构建RelaxedR1CSInstance,其中u为scalar 一值。
  • 3)from_r1cs_instance_unchecked():根据comm_W和X构建RelaxedR1CSInstance,其中u为scalar 一值。
  • 4)fold(U1, U2, comm_T, r):将R1CSInstance U2 fold到 RelaxedR1CSInstance (X1, u1, comm_W_1, comm_E_1) 中,其中comm_T为上面算的cross term T的承诺值,r为Verifier发送的random challenge。输出为RelaxedR1CSInstance (X, u, comm_W, comm_E)。
    实际就是计算: x = x 1 + r ⋅ x 2 , W ˉ = W ˉ 1 + r ⋅ W ˉ 2 , E ˉ = E ˉ 1 + r ⋅ T ˉ + r 2 ⋅ E ˉ 2 , u = u 1 + r ⋅ u 2 x=x_1+r\cdot x_2,\bar{W}=\bar{W}_1+r\cdot \bar{W}_2,\bar{E}=\bar{E}_1+r\cdot \bar{T}+r^2\cdot \bar{E}_2,u=u_1+r\cdot u_2 x=x1+rx2,Wˉ=Wˉ1+rWˉ2,Eˉ=Eˉ1+rTˉ+r2Eˉ2,u=u1+ru2。【注意,此处有 u 2 = 1 , E 2 为零向量 u_2=1,E_2为零向量 u2=1,E2为零向量,所以实际计算为 E ˉ = E ˉ 1 + r ⋅ T ˉ , u = u 1 + r \bar{E}=\bar{E}_1+r\cdot \bar{T},u=u_1+r Eˉ=Eˉ1+rTˉ,u=u1+r
  • 5)to_transcript_bytes():将RelaxedR1CSInstance转换拼接为Vec<u8>表示。
  • 6)absorb_in_ro():将RelaxedR1CSInstance absorb到RO中。注意:
    • comm_E和comm_W中的base域元素可直接absorb;
    • scalar域元素u需scalar_as_base()转换为base域再absorb;【此时无需考虑域转换时的溢出问题】
    • x向量中的每个scalar域元素需以4个64 bit表示,再逐个scalar_as_base()转换为base域再absorb。【此时需考虑域转换时的溢出问题。】

3. Non-interactive folding scheme

在这里插入图片描述
详细见src/nifs.rs

  • prove():用于将具有相同结构、相同commitment key的Relaxed R1CS instance-witness tuple (U1, W1) 和 R1CS instance-witness tuple (U2, W2) 进行fold,返回 Relaxed R1CS instance-witness (U, W)
  • verify():用于将具有相同结构、相同commitment key的Relaxed R1CS instance U1 和 R1CS instance U2 进行fold,返回 Relaxed R1CS instance U

在这里插入图片描述
Non-interactive folding scheme测试用例见:

4. 基于folding scheme的IVC

构建一个基于folding scheme的IVC方案,其Prover需证明: z n = F n ( z 0 ) z_n=F^n(z_0) zn=Fn(z0)

修订版Nova Prover算法分为三大块:

  • 1)初始流程
  • 2)base case step:即针对 i = 0 i=0 i=0的情况
  • 3)recursive step(即non-base case):即针对 i ≥ 1 i\geq 1 i1的情况。

每个step, F ′ F' F F F F 和 verifier circuit 组成。
在这里插入图片描述
其中:

  • 1)params:【见下面结构体定义】为哈希运算所需的参数。
  • 2) i i i:表示执行第i个step。
  • 3) z 0 z_0 z0:初始值。
  • 4) z i z_i zi:执行完第i个step的输出值。
  • 5)U:running instance,为relaxed R1CS instance。
  • 6)u:为the instance to be folded in。为R1CS instance。
  • 7)T:对应上图中的 T ˉ \bar{T} Tˉ承诺值.。
  • 8) u i . x u_i.x ui.x对应为“u.X0= Hash(params, U, i, z0, zi)”, h i + 1 h_{i+1} hi+1对应“u.X1= H(params, Unew, i+1, z0, z_{i+1})”。
  • 9)为提升IVC效率,采用cycle of curves实现:【cycle of curves 知识可参看:Halo2学习笔记——背景资料之Elliptic curves(5)
    在这里插入图片描述

src/circuit.rs F ′ F' F对应结构体 NovaAugmentedCircuit

/// The augmented circuit F' in Nova that includes a step circuit F
/// and the circuit for the verifier in Nova's non-interactive folding scheme
pub struct NovaAugmentedCircuit<G: Group, SC: StepCircuit<G::Base>> {
  params: NovaAugmentedCircuitParams,
  ro_consts: ROConstantsCircuit<G>,
  inputs: Option<NovaAugmentedCircuitInputs<G>>,
  step_circuit: SC, // The function that is applied for each step
}

其中:

  • 1) F ′ F' F的输入 对应 结构体 NovaAugmentedCircuitInputs:【其中T对应上图中的 T ˉ \bar{T} Tˉ承诺值。】
    pub struct NovaAugmentedCircuitInputs<G: Group> {
      params: G::Scalar, // Hash(Shape of u2, Gens for u2). Needed for computing the challenge.
      i: G::Base,
      z0: Vec<G::Base>,
      zi: Option<Vec<G::Base>>,
      U: Option<RelaxedR1CSInstance<G>>,
      u: Option<R1CSInstance<G>>,
      T: Option<Commitment<G>>, //承诺值,对应$\bar{T}$
    }
    
  • 2) F ′ F' F的哈希函数 H 1 , H 2 H_1,H_2 H1,H2 对应 结构体 ROConstantsCircuit
  • 3) F ′ F' F哈希运算(absorb入base域,squeeze出scalar域)中域转换时需要的参数:
    pub struct NovaAugmentedCircuitParams {
      limb_width: usize,
      n_limbs: usize,
      is_primary_circuit: bool, // A boolean indicating if this is the primary circuit
    }
    
  • 4) F ′ F' F F F F 对应 结构体 SC: StepCircuit<G::Base>
    /// A helper trait for a step of the incremental computation (i.e., circuit for F)
    pub trait StepCircuit<F: PrimeField>: Send + Sync + Clone {
      /// Return the the number of inputs or outputs of each step
      /// (this method is called only at circuit synthesis time)
      /// `synthesize` and `output` methods are expected to take as
      /// input a vector of size equal to arity and output a vector of size equal to arity  
      fn arity(&self) -> usize;
    
      /// Sythesize the circuit for a computation step and return variable
      /// that corresponds to the output of the step z_{i+1}
      fn synthesize<CS: ConstraintSystem<F>>(
        &self,
        cs: &mut CS,
        z: &[AllocatedNum<F>],
      ) -> Result<Vec<AllocatedNum<F>>, SynthesisError>;
    
      /// return the output of the step when provided with the step's input
      fn output(&self, z: &[F]) -> Vec<F>;
    }
    

4.1 NovaAugmentedCircuit中关键函数

F ′ F' F对应结构体 NovaAugmentedCircuit的关键函数有:

  • 1)new():为input relaxed R1CS instances创建新的verification circuit。
  • 2)alloc_witness():依次给 F ′ F' F的各输入参数赋值:params、i、z_0、z_i、U、u、T。
  • 3)synthesize_base_case(u):对应“修订版Nova Prover算法——base case step”,即针对 i = 0 i=0 i=0情况。其中u为R1CS instance。
    • 3.1)若params.is_primary_circuit为true,则设置relaxed R1CS instance U_default中:W = E = 0, u = 0, X0 = X1 = 0。
    • 3.2)若params.is_primary_circuit为false,则根据R1CS instance u来 设置relaxed R1CS instance U_default。
  • 4)synthesize_non_base_case(params, i, z_0, z_i, U, u, T, arity):对应“修订版Nova Prover算法——recursive step(即non-base case)”,即针对 i ≥ 1 i\geq 1 i1的情况。其中arity对应各z_i向量长度。
    • 4.1)检查u.x[0] = Hash(params, U, i, z0, zi) 是否成立,结果为check_pass。
    • 4.2)运行NIFS Verifier:与src/nifs.rs中的verify()函数思路一致,将具有相同结构、相同commitment key的Relaxed R1CS instance U 和 R1CS instance u 进行fold,返回 Relaxed R1CS instance U_fold。【本质为计算 U i + 1 U_{i+1} Ui+1。】
  • 5)synthesize():依次做如下操作:
    • 5.1)调用alloc_witness():依次给 F ′ F' F的各输入参数赋值:params、i、z_0、z_i、U、u、T。
    • 5.2)判断i值是否为0,若为0则is_base_case为true,否则为false。
    • 5.3)调用synthesize_base_case(u):对应“修订版Nova Prover算法——base case step”,即针对 i = 0 i=0 i=0情况。其中u为R1CS instance。返回relaxed R1CS instance Unew_base(U_default)。
    • 5.4)调用synthesize_non_base_case(params, i, z_0, z_i, U, u, T, arity):对应“修订版Nova Prover算法——recursive step(即non-base case)”,即针对 i ≥ 1 i\geq 1 i1的情况。其中arity对应各z_i向量长度。返回Unew_non_base( U_fold) 和 check_non_base_pass(check_pass)。
    • 5.5)要求:”check_non_base_pass必须为true“,否则 “is_base_case必须为true(表示在base case step)”。【采用AllocatedBit::nor(NOT a) AND (NOT b))来约束】
    • 5.6)计算Unew(即计算U_{I+1}):若is_base_case为true,设置Unew为 Unew_base(U_default);否则设置Unew为Unew_non_base( U_fold)。
    • 5.7)计算i_new=i+1。
    • 5.8)计算z_{i+1}(即计算z_next):
      • 5.8.1)若is_base_case为true,则设置z_input为z_0;否则设置z_input为z_i。
      • 5.8.2)调用step_circuit.synthesize(z_input),本质是计算z_next=F(z_input)。
      • 5.8.3)要求z_next向量长度必须等于arity。
    • 5.9)计算u.X1= H(params, Unew, i+1, z0, z_{i+1})。

src/circuit.rs中test_recursive_circuit()测试用例中的TrivialTestCircuit,对应 F ( x ) = x F(x)=x F(x)=x计算。

5. Nova:基于Folding scheme的高速recursive SNARK

在这里插入图片描述

  • 1)params.is_primary_circuit为true,对应待证明relation R 1 \mathcal{R}_1 R1
    在这里插入图片描述
  • 2)params.is_primary_circuit为false,对应待证明relation R 2 \mathcal{R}_2 R2
    在这里插入图片描述
    具体见src/lib.rs中:
  • 1)Nova公共参数见PublicParams结构体:【有G2::Base=G1::Scalar。以G1 curve为primary,StepCircuit C1对应的计算基于G1::Scalar;以G2 curve为secondary,StepCircuit C2对应的计算基于G2::Scalar。】【要求 z0_primary.len() == pp.F_arity_primary 且 z0_secondary.len() == pp.F_arity_secondary】
    /// A type that holds public parameters of Nova
    #[derive(Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct PublicParams<G1, G2, C1, C2>
    where
      G1: Group<Base = <G2 as Group>::Scalar>,
      G2: Group<Base = <G1 as Group>::Scalar>,
      C1: StepCircuit<G1::Scalar>,
      C2: StepCircuit<G2::Scalar>,
    {
      F_arity_primary: usize,
      F_arity_secondary: usize,
      ro_consts_primary: ROConstants<G1>, // 对应H1函数,absorb G1 Base field元素,squeeze G1 Scalar field元素
      ro_consts_circuit_primary: ROConstantsCircuit<G2>, // 验证H2计算。
      ck_primary: CommitmentKey<G1>, // primary曲线上的commitment key 
      r1cs_shape_primary: R1CSShape<G1>, // primary曲线上计算对应的R1CSShape
      ro_consts_secondary: ROConstants<G2>, // 对应H2函数,,absorb G2 Base field元素,squeeze G2 Scalar field元素
      ro_consts_circuit_secondary: ROConstantsCircuit<G1>, // 验证H1计算。
      ck_secondary: CommitmentKey<G2>, // secondary曲线上的commitment key 
      r1cs_shape_secondary: R1CSShape<G2>, // secondary曲线上计算对应的R1CSShape
      augmented_circuit_params_primary: NovaAugmentedCircuitParams, // 域转换溢出处理参数等,其中is_primary_circuit应为true
      augmented_circuit_params_secondary: NovaAugmentedCircuitParams, // 域转换溢出处理参数等,其中is_primary_circuit应为false
      digest: G1::Scalar, // digest of everything else with this field set to G1::Scalar::ZERO
      _p_c1: PhantomData<C1>,
      _p_c2: PhantomData<C2>,
    }
    
  • 2)IVC中基于cycle of curves的递归step对应 结构体RecursiveSNARK
    • r_W_primary和r_U_primary:对应 W i ( 1 ) , U i ( 1 ) \mathbb{W_i^{(1)}},\mathbb{U_i^{(1)}} Wi(1)Ui(1)
    • r_W_secondary和r_U_secondary:对应 W i ( 2 ) , U i ( 2 ) \mathbb{W_i^{(2)}},\mathbb{U_i^{(2)}} Wi(2)Ui(2)
    • l_w_secondary和l_u_secondary:对应 𝕨 i ( 2 ) _i^{(2)} i(2),𝕦 i ( 2 ) _i^{(2)} i(2)
    • zi_primary和zi_secondary:对应 z i ( 1 ) z_i^{(1)} zi(1) z i ( 2 ) z_i^{(2)} zi(2)
    /// A SNARK that proves the correct execution of an incremental computation
    #[derive(Clone, Debug, Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct RecursiveSNARK<G1, G2, C1, C2>
    where
      G1: Group<Base = <G2 as Group>::Scalar>,
      G2: Group<Base = <G1 as Group>::Scalar>,
      C1: StepCircuit<G1::Scalar>,
      C2: StepCircuit<G2::Scalar>,
    {
      r_W_primary: RelaxedR1CSWitness<G1>,
      r_U_primary: RelaxedR1CSInstance<G1>,
      r_W_secondary: RelaxedR1CSWitness<G2>,
      r_U_secondary: RelaxedR1CSInstance<G2>,
      l_w_secondary: R1CSWitness<G2>,
      l_u_secondary: R1CSInstance<G2>,
      i: usize,
      zi_primary: Vec<G1::Scalar>,
      zi_secondary: Vec<G2::Scalar>,
      _p_c1: PhantomData<C1>,
      _p_c2: PhantomData<C2>,
    }
    
  • 3)压缩最后一个step的IVC proof,对应CompressedSNARK结构体:【其中RelaxedR1CSSNARKTrait实现见src/spartan/pp.rs。】
    /// A SNARK that proves the knowledge of a valid `RecursiveSNARK`
    #[derive(Clone, Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct CompressedSNARK<G1, G2, C1, C2, S1, S2>
    where
      G1: Group<Base = <G2 as Group>::Scalar>,
      G2: Group<Base = <G1 as Group>::Scalar>,
      C1: StepCircuit<G1::Scalar>,
      C2: StepCircuit<G2::Scalar>,
      S1: RelaxedR1CSSNARKTrait<G1>,
      S2: RelaxedR1CSSNARKTrait<G2>,
    {
      r_U_primary: RelaxedR1CSInstance<G1>,
      r_W_snark_primary: S1,
    
      r_U_secondary: RelaxedR1CSInstance<G2>,
      l_u_secondary: R1CSInstance<G2>,
      nifs_secondary: NIFS<G2>,
      f_W_snark_secondary: S2,
    
      zn_primary: Vec<G1::Scalar>,
      zn_secondary: Vec<G2::Scalar>,
    
      _p_c1: PhantomData<C1>,
      _p_c2: PhantomData<C2>,
    }
    
    /// A type that holds the prover key for `CompressedSNARK`
    #[derive(Clone, Debug, Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct ProverKey<G1, G2, C1, C2, S1, S2>
    where
      G1: Group<Base = <G2 as Group>::Scalar>,
      G2: Group<Base = <G1 as Group>::Scalar>,
      C1: StepCircuit<G1::Scalar>,
      C2: StepCircuit<G2::Scalar>,
      S1: RelaxedR1CSSNARKTrait<G1>,
      S2: RelaxedR1CSSNARKTrait<G2>,
    {
      pk_primary: S1::ProverKey,
      pk_secondary: S2::ProverKey,
      _p_c1: PhantomData<C1>,
      _p_c2: PhantomData<C2>,
    }
    
    /// A type that holds the verifier key for `CompressedSNARK`
    #[derive(Clone, Serialize, Deserialize)]
    #[serde(bound = "")]
    pub struct VerifierKey<G1, G2, C1, C2, S1, S2>
    where
      G1: Group<Base = <G2 as Group>::Scalar>,
      G2: Group<Base = <G1 as Group>::Scalar>,
      C1: StepCircuit<G1::Scalar>,
      C2: StepCircuit<G2::Scalar>,
      S1: RelaxedR1CSSNARKTrait<G1>,
      S2: RelaxedR1CSSNARKTrait<G2>,
    {
      F_arity_primary: usize,
      F_arity_secondary: usize,
      ro_consts_primary: ROConstants<G1>,
      ro_consts_secondary: ROConstants<G2>,
      digest: G1::Scalar,
      vk_primary: S1::VerifierKey,
      vk_secondary: S2::VerifierKey,
      _p_c1: PhantomData<C1>,
      _p_c2: PhantomData<C2>,
    }
    

5.1 PublicParams中关键函数

PublicParams中关键函数有:

  • 1)setup():创建PublicParams
  • 2)num_constraints():返回 primary电路 和 secondary电路的约束数。
  • 3)num_variables():返回 primary电路 和 secondary电路的witness变量数。

5.2 RecursiveSNARK中关键函数

RecursiveSNARK中关键函数有:

  • 1)setup():针对 i = 0 i=0 i=0的情况,根据StepCircuit c_primary和StepCircuit c_secondary,以及z0_primary和z_0_secondary,构建 ( W 1 ( 1 ) , U 1 ( 1 ) ) (\mathbb{W_1^{(1)}},\mathbb{U_1^{(1)}}) (W1(1)U1(1)) ( W 1 ( 2 ) , U 1 ( 2 ) ) (\mathbb{W_1^{(2)}},\mathbb{U_1^{(2)}}) (W1(2)U1(2)) ( ( (𝕨 1 ( 2 ) _1^{(2)} 1(2),𝕦 1 ( 2 ) ) _1^{(2)}) 1(2))

  • 2)prove_step (
    &mut self,
    pp: &PublicParams<G1, G2, C1, C2>,
    c_primary: &C1,
    c_secondary: &C2,
    z0_primary: VecG1::Scalar,
    z0_secondary: VecG2::Scalar,):其中self为RecursiveSNARK结构体。

    • 2.1)若self.i=0,则直接修改self.i=1,然后返回self。【对应base case step】
    • 2.2)若self.i > 0,则根据 z i ( 1 ) , z i ( 2 ) z_i^{(1)},z_i^{(2)} zi(1),zi(2) ( W i ( 1 ) , U i ( 1 ) ) (\mathbb{W_i^{(1)}},\mathbb{U_i^{(1)}}) (Wi(1)Ui(1)) ( W i ( 2 ) , U i ( 2 ) ) (\mathbb{W_i^{(2)}},\mathbb{U_i^{(2)}}) (Wi(2)Ui(2)) ( ( (𝕨 i ( 2 ) _i^{(2)} i(2),𝕦 i ( 2 ) ) _i^{(2)}) i(2)),计算 z i + 1 ( 1 ) , z i + 1 ( 2 ) z_{i+1}^{(1)},z_{i+1}^{(2)} zi+1(1),zi+1(2) ( W i + 1 ( 1 ) , U i + 1 ( 1 ) ) (\mathbb{W_{i+1}^{(1)}},\mathbb{U_{i+1}^{(1)}}) (Wi+1(1)Ui+1(1)) ( W i + 1 ( 2 ) , U i + 1 ( 2 ) ) (\mathbb{W_{i+1}^{(2)}},\mathbb{U_{i+1}^{(2)}}) (Wi+1(2)Ui+1(2)) ( ( (𝕨 i + 1 ( 2 ) _{i+1}^{(2)} i+1(2),𝕦 i + 1 ( 2 ) ) _{i+1}^{(2)}) i+1(2))。【对应non-base case step,即recursive step】
  • 3)verify(
    &self,
    pp: &PublicParams<G1, G2, C1, C2>,
    num_steps: usize,
    z0_primary: &[G1::Scalar],
    z0_secondary: &[G2::Scalar],
    ):其中self为RecursiveSNARK结构体,返回self.zi_primary和self.zi_secondary。
    验证第num_steps的RecursiveSNARK的正确性,要求:【(relaxed) R1CS instances U i ( 1 ) , U i ( 2 ) \mathbb{U_i^{(1)}},\mathbb{U_i^{(2)}} Ui(1),Ui(2)和𝕦 i ( 2 ) _i^{(2)} i(2)的public input/output数必须为2。
    在这里插入图片描述

5.3 CompressedSNARK中关键函数

对step i 的IVC proof z i ( 1 ) , z i ( 2 ) z_i^{(1)},z_i^{(2)} zi(1),zi(2) ( W i ( 1 ) , U i ( 1 ) ) (\mathbb{W_i^{(1)}},\mathbb{U_i^{(1)}}) (Wi(1)Ui(1)) ( W i ( 2 ) , U i ( 2 ) ) (\mathbb{W_i^{(2)}},\mathbb{U_i^{(2)}}) (Wi(2)Ui(2)) ( ( (𝕨 i ( 2 ) _i^{(2)} i(2),𝕦 i ( 2 ) ) _i^{(2)}) i(2)) 进行压缩,CompressedSNARK中关键函数有:【其中RelaxedR1CSSNARKTrait实现见src/spartan/pp.rssrc/spartan/mod.rs。】

  • 1)setup():根据PublicParams构建ProverKey和VerifierKey。
  • 2)prover():根据ProverKey,对RecursiveSNARK进行证明。返回CompressedSNARK结构。
    证明过程主要分为两大块:
    • 2.1)compression without SNARKs:
      在这里插入图片描述
    • 2.2)compression with SNARKs:【可采用Spartan来压缩】
      在这里插入图片描述
  • 3)verify(
    &self,
    vk: &VerifierKey<G1, G2, C1, C2, S1, S2>,
    num_steps: usize,
    z0_primary: VecG1::Scalar,
    z0_secondary: VecG2::Scalar,
    ) :其中self为prove()输出的CompressedSNARK结构。
    在这里插入图片描述

Nova系列博客

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值