### ZKSync 中 better_better_cs 如何实现聚合证明（⼆）

48441155ec7006bf7bfac553b5fb7d466d7fcd00 。

aggregation_proof 的⽣成

create_proof 这个函数在 bellman_ce/src/plonk/better_better_cs/proof/mod.rs 中，将近 2000 ⾏代码。

⼤体上，分为以下⼏个步骤：

1. 基本的⼀些检查和预计算// ...

for idx in 0..num_state_polys {

let key = PolyIdentifier::PermutationPolynomial(idx);

let vals = setup.permutation_monomials[idx].clone().fft_using_bitreversed_ntt(

&worker,

&omegas_bitreversed,

&E::Fr::one()

)?.into_coeffs();

let poly = PolynomialProxy::from_owned(poly);

values_storage.setup_map.insert(key, poly);

}

1. ⽣成 state 多项式状态和 witness 多项式状态，且为lookup table 参数⽣成排序好的多项式

// ...

proof.state_polys_commitments.push(commitment);

// ...

proof.witness_polys_commitments.push(commitment);

1. 构造 lookupdataholder，⽤于后续计算

// ...

let data = data_structures::LookupDataHolder::<E> {

eta,

t_poly_monomial: Some(t_poly_monomial),

s_poly_monomial: Some(s_poly_monomial),

selector_poly_monomial: Some(selector_poly),

table_type_poly_monomial: Some(table_type_mononial),

};

1. 对置换多项式进⾏乘积（grand product）计算

// ...

let mut z_2 = grand_products_proto_it.next().unwrap();

&beta_for_copy_permutation);

for (mut p, perm) in grand_products_proto_it.zip(permutation_polys_it) {

z_2.mul_assign(&worker, &p);

}

z_2.batch_inversion(&worker)?;

1. 对商多项式进⾏计算

// ...

let mut t = gate.contribute_into_quotient_for_public_inputs(

required_domain_size,

&input_values,

&mut ldes_storage,

&monomials_storage,

for_gate,

&omegas_bitreversed,

&omegas_inv_bitreversed,

&worker

)?;

// ...

transcript.commit_field_element(&quotient_at_z);

proof.quotient_poly_opening_at_z = quotient_at_z;

1. 根据 lookup table 进⾏线性化

let queries_with_linearization = sort_queries_for_linearization(&self.sorted_gates,

MAX_DILATION);

// ...

for (dilation_value, ids) in

queries_with_linearization.state_polys.iter().enumerate() {...}

for (dilation_value, ids) in

queries_with_linearization.witness_polys.iter().enumerate() {...}

for (gate_idx, queries) in

queries_with_linearization.gate_setup_polys.iter().enumerate() {...}

1. 对多项式的 selectors 进⾏ open 取值

let mut selector_values = vec![];

for s in queries_with_linearization.gate_selectors.iter() {

let gate_index = self.sorted_gates.iter().position(|r| r == s).unwrap();

let key = PolyIdentifier::GateSelector(s.name());

let poly_ref = monomials_storage.gate_selectors.get(&key).unwrap().as_ref();

let value = poly_ref.evaluate_at(&worker, z);

transcript.commit_field_element(&value);

proof.gate_selectors_openings_at_z.push((gate_index, value));

selector_values.push(value);

}

1. 增加拷⻉置换多项式、lookup置换的优化结果// ...

r_poly.sub_assign_scaled(&worker, last_permutation_poly_ref, &factor);

1. 使⽤ lookup 进⾏ query

let query = LookupQuery::<E> {

s_at_z_omega,

grand_product_at_z_omega,

t_at_z,

t_at_z_omega,

selector_at_z,

table_type_at_z,

};

1. 对多项式的 selectors 在 z 进⾏ open 取值

for s in queries_with_linearization.gate_selectors.iter() {

multiopening_challenge.mul_assign(&v);

let key = PolyIdentifier::GateSelector(s.name());

let poly_ref = monomials_storage.get_poly(key);

&multiopening_challenge);

}

1. 将最终的 lookup 值放⼊proof中

if let Some(data) = lookup_data.as_ref() {

// we need to add t(x), selector(x) and table type(x)

multiopening_challenge.mul_assign(&v);

let poly_ref = data.t_poly_monomial.as_ref().unwrap().as_ref();

&multiopening_challenge);

multiopening_challenge.mul_assign(&v);

let poly_ref = data.selector_poly_monomial.as_ref().unwrap().as_ref();

&multiopening_challenge);

multiopening_challenge.mul_assign(&v);

let poly_ref = data.table_type_poly_monomial.as_ref().unwrap().as_ref();

&multiopening_challenge);

}

1. 计算 z、z_omega 处的 open 值，最后组装 proof 在这个函数中，我们看到了熟悉的 MainGate 函数，从上⼀版如何实现聚合中，我们知道这个⽤于⻔的设计，可以实现 custom gate，达到优化电路的⽬的。⽽除开 custom gate，ZKSync 中还使⽤了plonkup（即 plonk + lookup table） 来提升效率。

lookup table，prover需要证明witness在这个table⾥，详细内容请参⻅ZKSwap团队解读Plookup原理。

ZKSync 对 plonkup 的实现，并不是将 custom gate 和 plonkup 分开的，⽽是结合在⼀起来优化电路设计

lookup 的使⽤

contribute_into_linearization_for_public_inputs 函数，我们以它为例，来看看 lookup 的使⽤。这个

let open_at_z_omega = polys.pop().unwrap().0;

let open_at_z = polys.pop().unwrap().0;

let opening_at_z = commit_using_monomials(

&open_at_z,

&mon_crs,

&worker

)?;

let opening_at_z_omega = commit_using_monomials(

&open_at_z_omega,

&mon_crs,

&worker

)?;

proof.opening_proof_at_z = opening_at_z;

proof.opening_proof_at_z_omega = opening_at_z_omega;fn contribute_into_linearization_for_public_inputs(

&self,

_domain_size: usize,

_public_inputs: &[E::Fr],

_at: E::Fr,

queried_values: &std::collections::HashMap<PolynomialInConstraint, E::Fr>,

monomials_storage: & AssembledPolynomialStorageForMonomialForms<E>,

challenges: &[E::Fr],

worker: &Worker

) -> Result<Polynomial<E::Fr, Coefficients>, SynthesisError> {}

⽤到的传⼊参数有 hashmap 格式的 queried_values、单项式缓存值、随机数数组。queried_values 这个参

pub struct SortedGateQueries<E: Engine>{

pub state_polys: Vec<Vec<PolyIdentifier>>, // state 多项式

pub witness_polys: Vec<Vec<PolyIdentifier>>, // witness 多项式

pub gate_selectors: Vec<Box<dyn GateInternal<E>>>, // gate 的selectors

pub gate_setup_polys: Vec<Vec<Vec<PolyIdentifier>>>, // gate setup 多项式

}

fn sort_queries_for_linearization<E: Engine>(gates: & Vec<Box<dyn GateInternal<E>>>,

max_dilation: usize)

-> SortedGateQueries<E> {

}

WitnessPolynomial ， GateSetupPolynomial 的不同类型，将多项式存⼊ SortedGateQueries 中。

&worker,

&omegas_inv_bitreversed,

&values_storage,

true

)?;

monomials_storage.extend_from_setup(setup)?;

// 可以看到，⾮常⾼效的get取到了数据

let a_value =

*queried_values.get(&PolynomialInConstraint::from_id(PolyIdentifier::VariablesPolynomia

l(0)))

.ok_or(SynthesisError::AssignmentMissing)?;

let b_value =

*queried_values.get(&PolynomialInConstraint::from_id(PolyIdentifier::VariablesPolynomia

l(1)))

.ok_or(SynthesisError::AssignmentMissing)?;

let c_value =

*queried_values.get(&PolynomialInConstraint::from_id(PolyIdentifier::VariablesPolynomia

l(2)))

.ok_or(SynthesisError::AssignmentMissing)?;

let d_value =

*queried_values.get(&PolynomialInConstraint::from_id(PolyIdentifier::VariablesPolynomia

l(3)))

.ok_or(SynthesisError::AssignmentMissing)?;

let d_next_value =

*queried_values.get(&PolynomialInConstraint::from_id_and_dilation(PolyIdentifier::Varia

blesPolynomial(3), 1))

.ok_or(SynthesisError::AssignmentMissing)?;

let name = <Self as GateInternal<E>>::name(&self);

// get_ploy 也是查找table的⽅式获取多项式

// Q_a * A

let mut result = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

0)).clone();

result.scale(&worker, a_value);

// Q_b * B

let poly_ref = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

1));

// Q_c * Clet poly_ref = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

2));

// Q_d * D

let poly_ref = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

3));

// Q_m AB

let mut tmp = a_value;

tmp.mul_assign(&b_value);

let poly_ref = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

4));

// Q_const

let poly_ref = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

5));

// Q_dNext * D_next

let poly_ref = monomials_storage.get_poly(PolyIdentifier::GateSetupPolynomial(name,

6));

result.scale(&worker, challenges[0]);

// 结果都存⼊result中

Ok(result)

table，直接查询⽽不是再次计算，加快⽣成速度，提升 prover 效率。

https://github.com/matter-labs/zksync

https://github.com/matter-labs/bellman

https://eprint.iacr.org/2020/315.pdf

• 发表于 2021-06-08 17:26
• 阅读 ( 92 )
• 学分 ( 1 )
• 分类：交易所

ZKSwap

17 篇文章, 206 学分