ZCash Halo2 代码解析

1. 引言

针对代码库:

其中:

  • src/arithmetic.rs:定义了多种multiexp、fft、poly evaluation、inner product、 q ( x ) = f ( x ) x − b q(x)=\frac{f(x)}{x-b} q(x)=xbf(x)多项式求商、函数并行运行parallelize() l o g 2 log_2 log2 以及 lagrange插值 运算。
  • src/poly.rs:定义的为单变量多项式:【有2种表示方式:Polynomial<G, Coeff>为系数表示;Polynomial<G, LagrangeCoeff>为Lagrange点值表示。】
/// Represents a univariate polynomial defined over a field and a particular 
/// basis.
pub struct Polynomial<F, B> {
    values: Vec<F>,
    _marker: PhantomData<B>, 
}

rotate用于将Lagrange点值表示的值左右移动, L ( X ) , L ( ω X ) , L ( ω − 1 X ) L(X),L(\omega X), L(\omega^{-1}X) L(X),L(ωX),L(ω1X) 具有的特征为:

	let poly_rotated_cur = poly.rotate(Rotation::cur());
    let poly_rotated_next = poly.rotate(Rotation::next());
    let poly_rotated_prev = poly.rotate(Rotation::prev());

    let poly = domain.lagrange_to_coeff(poly);
    let poly_rotated_cur = domain.lagrange_to_coeff(poly_rotated_cur);
    let poly_rotated_next = domain.lagrange_to_coeff(poly_rotated_next);
    let poly_rotated_prev = domain.lagrange_to_coeff(poly_rotated_prev);

    let x = Scalar::rand();

    assert_eq!(
        eval_polynomial(&poly[..], x),
        eval_polynomial(&poly_rotated_cur[..], x)
    );
    assert_eq!(
        eval_polynomial(&poly[..], x * domain.omega),
        eval_polynomial(&poly_rotated_next[..], x)
    );
    assert_eq!(
        eval_polynomial(&poly[..], x * domain.omega_inv),
        eval_polynomial(&poly_rotated_prev[..], x)
    );

2. polynomial commitment(系数表示法)

  • src/poly/commitment/msm.rs:实现的为multiscalar multiplication运算。
  • src/poly/domain.rs:主要包含了EvaluationDomain,用于表示在scalar field域内的各种多项式运算。如计算Lagrange basis polynomial、多项式的点值与系数表示之间的相互转换、
  • src/poly/commitment.rs:定义了polynomial commitment scheme的公共参数:
pub struct Params<C: CurveAffine> {
    pub(crate) k: u32,
    pub(crate) n: u64,
    pub(crate) g: Vec<C>, // 对以系数表示的多项式进行commit
    pub(crate) g_lagrange: Vec<C>, //对以点值表示的多项式进行commit
    pub(crate) h: C,
    pub(crate) u: C,
}

其中定义了2种commitment实现,分别是对以系数表示的多项式的commit方法,和经FFT转换为点值表示的多项式的commit_lagrange方法,二者的实际commit效果是一样的:

assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));

同时,实现了从buffer读写Params参数的接口。

2.1 单点polynomial commitment scheme(系数表示法)

可参考:

具体见src/poly/commitment/*.rs中,相应的测试用例见src/poly/commitment.rs中的test_opening_proof()

其中:

  • create_proof()过程对应为 Halo2 学习笔记——设计之Proving system之Inner product argument(6) 中的第2节的 P C D L . O p e n PC_{DL}.Open PCDL.Open算法。
  • verify_proof()过程对应为Halo2 学习笔记——设计之Proving system之Inner product argument(6) 中的第2节的 P C D L . C h e c k PC_{DL}.Check PCDL.Check算法,但是相应的 ∏ i = 1 k ( u i + u i − 1 x 2 i − 1 ) \prod_{i=1}^{k}(u_i+u_i^{-1}x^{2^i-1}) i=1k(ui+ui1x2i1)由Verifier通过compute_b()函数计算得出,而未进行分摊。
    若使用compute_s()函数计算 g ( X ) = ∏ i = 1 k ( u i + u i − 1 X 2 i − 1 ) g(X)=\prod_{i=1}^{k}(u_i+u_i^{-1}X^{2^i-1}) g(X)=i=1k(ui+ui1X2i1)多项式的系数,并通过compute_g()函数计算commtiment值 G = c o m m i t ( g ( X ) ) + H G=commit(g(X))+H G=commit(g(X))+H。具体体现在Guard结构体中。

2.2 多点polynomial commitment scheme(系数表示法)

multiopen对应的测试用例参见src/poly/multiopen.rs中的test_roundtrip()

可参考:

其中src/poly/multiopen.rs中的 x 1 , x 2 , x 3 , x 4 x_1,x_2,x_3,x_4 x1,x2,x3,x4 challenge参数的含义参考 Halo2 学习笔记——设计之Proving system之Multipoint opening argument(5) 第2节“Optimization steps”:

  • x 1 x_1 x1 challenge:用于compress openings at the same point sets together。
  • x 2 x_2 x2 challenge:用于keep the multi-point quotient polynomial terms linearly independent。
  • x 3 x_3 x3 challenge:为challenge open point。
  • x 4 x_4 x4 challenge:用于将 分组后的多个多项式 + 组合后的一个quotient多项式 组合在一起。即用于Collapse the openings of the various remaining polynomials at x 3 x_3 x3 together。

通过以上challenge,即可将multi-point open转换为单个多项式,然后直接调用单点Polynomial commitment scheme进行证明即可。

/// A polynomial query at a point
#[derive(Debug, Clone)]
pub struct ProverQuery<'a, C: CurveAffine> { // 为Prover端输入
    /// point at which polynomial is queried
    pub point: C::Scalar,
    /// coefficients of polynomial
    pub poly: &'a Polynomial<C::Scalar, Coeff>,
    /// blinding factor of polynomial
    pub blind: commitment::Blind<C::Scalar>,
}

/// A polynomial query at a point
#[derive(Debug, Clone)]
pub struct VerifierQuery<'r, 'params: 'r, C: CurveAffine> { // 为Verifier端输入
    /// point at which polynomial is queried
    point: C::Scalar,
    /// commitment to polynomial
    commitment: CommitmentReference<'r, 'params, C>, // 有2种类型,Commitment或MSM。
    /// evaluation of polynomial at query point
    eval: C::Scalar,
}

3 Plonk lookup argument(Lagrange点值表示法)

可参考:

具体代码参见:src/plonk/lookup.rs,相应的测试用例见tests/plonk_api.rs中的plonk_api()

#[derive(Clone, Debug)]
pub(crate) struct Argument<F: Field> {
    pub input_expressions: Vec<Expression<F>>,
    pub table_expressions: Vec<Expression<F>>,
}

4. Halo2 circuit

  • expression:
/// Low-degree expression representing an identity that must hold over the committed columns.
#[derive(Clone, Debug)]
pub enum Expression<F> {
    /// This is a constant polynomial
    Constant(F),
    /// This is a virtual selector
    Selector(Selector),
    /// This is a fixed column queried at a certain relative location
    Fixed {
        /// Query index
        query_index: usize,
        /// Column index
        column_index: usize,
        /// Rotation of this query
        rotation: Rotation,
    },
    /// This is an advice (witness) column queried at a certain relative location
    Advice {
        /// Query index
        query_index: usize,
        /// Column index
        column_index: usize,
        /// Rotation of this query
        rotation: Rotation,
    },
    /// This is an instance (external) column queried at a certain relative location
    Instance {
        /// Query index
        query_index: usize,
        /// Column index
        column_index: usize,
        /// Rotation of this query
        rotation: Rotation,
    },
    /// This is a negated polynomial
    Negated(Box<Expression<F>>),
    /// This is the sum of two polynomials
    Sum(Box<Expression<F>>, Box<Expression<F>>),
    /// This is the product of two polynomials
    Product(Box<Expression<F>>, Box<Expression<F>>),
    /// This is a scaled polynomial
    Scaled(Box<Expression<F>>, F),
}
pub struct MockProver<F: Group + Field> {
    n: u32,
    cs: ConstraintSystem<F>,

    /// The regions in the circuit.
    regions: Vec<Region>,
    /// The current region being assigned to. Will be `None` after the circuit has been
    /// synthesized.
    current_region: Option<Region>,

    // The fixed cells in the circuit, arranged as [column][row].
    fixed: Vec<Vec<CellValue<F>>>,
    // The advice cells in the circuit, arranged as [column][row].
    advice: Vec<Vec<CellValue<F>>>,
    // The instance cells in the circuit, arranged as [column][row].
    instance: Vec<Vec<F>>,

    selectors: Vec<Vec<bool>>,

    permutation: permutation::keygen::Assembly,

    // A range of available rows for assignment and copies.
    usable_rows: Range<usize>,
}
/// The value of a particular cell within the circuit.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum CellValue<F: Group + Field> {
    // An unassigned cell.
    Unassigned,
    // A cell that has been assigned a value.
    Assigned(F),
    // A unique poisoned cell.
    Poison(usize),
}

4.1 Constraint System

pub struct ConstraintSystem<F: Field> {
    pub(crate) num_fixed_columns: usize,
    pub(crate) num_advice_columns: usize,
    pub(crate) num_instance_columns: usize,
    pub(crate) num_selectors: usize,
    pub(crate) selector_map: Vec<Column<Fixed>>,
    pub(crate) gates: Vec<Gate<F>>,
    pub(crate) advice_queries: Vec<(Column<Advice>, Rotation)>,
    // Contains an integer for each advice column
    // identifying how many distinct queries it has
    // so far; should be same length as num_advice_columns.
    num_advice_queries: Vec<usize>,
    pub(crate) instance_queries: Vec<(Column<Instance>, Rotation)>,
    pub(crate) fixed_queries: Vec<(Column<Fixed>, Rotation)>,

    // Permutation argument for performing equality constraints
    pub(crate) permutation: permutation::Argument,

    // Vector of lookup arguments, where each corresponds to a sequence of
    // input expressions and a sequence of table expressions involved in the lookup.
    pub(crate) lookups: Vec<lookup::Argument<F>>,

    // Vector of fixed columns, which can be used to store constant values
    // that are copied into advice columns.
    pub(crate) constants: Vec<Column<Fixed>>,

    pub(crate) minimum_degree: Option<usize>,
}

pub struct Rotation(pub i32); // 0表示当前行,1表示下一行,-1表示前一行

// Permutation argument
pub(crate) struct Argument {
    /// A sequence of columns involved in the argument.
    columns: Vec<Column<Any>>,
}

// Lookup argument
pub(crate) struct Argument<F: Field> {
    pub input_expressions: Vec<Expression<F>>,
    pub table_expressions: Vec<Expression<F>>,
}
/// Low-degree expression representing an identity that must hold over the committed columns.
#[derive(Clone, Debug)]
pub enum Expression<F> {
    /// This is a constant polynomial
    Constant(F),
    /// This is a virtual selector
    Selector(Selector),
    /// This is a fixed column queried at a certain relative location
    Fixed {
        /// Query index
        query_index: usize,
        /// Column index
        column_index: usize,
        /// Rotation of this query
        rotation: Rotation,
    },
    /// This is an advice (witness) column queried at a certain relative location
    Advice {
        /// Query index
        query_index: usize,
        /// Column index
        column_index: usize,
        /// Rotation of this query
        rotation: Rotation,
    },
    /// This is an instance (external) column queried at a certain relative location
    Instance {
        /// Query index
        query_index: usize,
        /// Column index
        column_index: usize,
        /// Rotation of this query
        rotation: Rotation,
    },
    /// This is a negated polynomial
    Negated(Box<Expression<F>>),
    /// This is the sum of two polynomials
    Sum(Box<Expression<F>>, Box<Expression<F>>),
    /// This is the product of two polynomials
    Product(Box<Expression<F>>, Box<Expression<F>>),
    /// This is a scaled polynomial
    Scaled(Box<Expression<F>>, F),
}

4.2 Region

struct Region {
    /// The name of the region. Not required to be unique.
    name: String,
    /// The row that this region starts on, if known.
    start: Option<usize>,
    /// The selectors that have been enabled in this region. All other selectors are by
    /// construction not enabled.
    enabled_selectors: HashMap<Selector, Vec<usize>>,
    /// The cells assigned in this region. We store this as a `Vec` so that if any cells
    /// are double-assigned, they will be visibly darker.
    cells: Vec<(Column<Any>, usize)>,
}

pub struct Selector(pub(crate) usize, bool);

pub struct Column<C: ColumnType> { //其中ColumnType为trait。
    index: usize,
    column_type: C,
}

pub enum Any {
    /// An Advice variant
    Advice,
    /// A Fixed variant
    Fixed,
    /// An Instance variant
    Instance,
}

4.3 permutation keygen Assembly

pub(crate) struct Assembly {
    columns: Vec<Column<Any>>,
    pub(crate) mapping: Vec<Vec<(usize, usize)>>,
    aux: Vec<Vec<(usize, usize)>>,
    sizes: Vec<Vec<usize>>,
}

5. 要点

对于自定义的MyCircuit,需自己:

  • configure() 函数中配置相应的 advice(private)变量、instance(public)变量、constant(fixed and private)变量。
  • synthesize() 函数中设置相应的 circuit逻辑运算。

猜你喜欢

转载自blog.csdn.net/mutourend/article/details/120676219