mirror of https://github.com/zcash/halo2.git
Add commit_product() to lookup::prover
This commit is contained in:
parent
46eed7be93
commit
2d0f4a11e3
|
@ -176,6 +176,200 @@ impl Argument {
|
||||||
permuted_table_commitment,
|
permuted_table_commitment,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a Lookup with input columns, table columns, and the permuted
|
||||||
|
/// input column and permuted table column, this method constructs the
|
||||||
|
/// grand product polynomial over the lookup. The grand product polynomial
|
||||||
|
/// is used to populate the Product<C> struct. The Product<C> struct is
|
||||||
|
/// added to the Lookup and finally returned by the method.
|
||||||
|
pub(in crate::plonk) fn commit_product<
|
||||||
|
C: CurveAffine,
|
||||||
|
HBase: Hasher<C::Base>,
|
||||||
|
HScalar: Hasher<C::Scalar>,
|
||||||
|
>(
|
||||||
|
&self,
|
||||||
|
permuted: &Permuted<C>,
|
||||||
|
pk: &ProvingKey<C>,
|
||||||
|
params: &Params<C>,
|
||||||
|
theta: C::Scalar,
|
||||||
|
beta: C::Scalar,
|
||||||
|
gamma: C::Scalar,
|
||||||
|
advice_values: &[Polynomial<C::Scalar, LagrangeCoeff>],
|
||||||
|
fixed_values: &[Polynomial<C::Scalar, LagrangeCoeff>],
|
||||||
|
aux_values: &[Polynomial<C::Scalar, LagrangeCoeff>],
|
||||||
|
transcript: &mut Transcript<C, HBase, HScalar>,
|
||||||
|
) -> Result<Product<C>, Error> {
|
||||||
|
let permuted = permuted.clone();
|
||||||
|
let unpermuted_input_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>> = self
|
||||||
|
.input_columns
|
||||||
|
.iter()
|
||||||
|
.map(|&input| match input.column_type() {
|
||||||
|
Any::Advice => advice_values[input.index()].clone(),
|
||||||
|
Any::Fixed => fixed_values[input.index()].clone(),
|
||||||
|
Any::Aux => aux_values[input.index()].clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let unpermuted_table_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>> = self
|
||||||
|
.table_columns
|
||||||
|
.iter()
|
||||||
|
.map(|&table| match table.column_type() {
|
||||||
|
Any::Advice => advice_values[table.index()].clone(),
|
||||||
|
Any::Fixed => fixed_values[table.index()].clone(),
|
||||||
|
Any::Aux => aux_values[table.index()].clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Goal is to compute the products of fractions
|
||||||
|
//
|
||||||
|
// (a_1(\omega^i) + \theta a_2(\omega^i) + ... + beta)(s_1(\omega^i) + \theta(\omega^i) + ... + \gamma) /
|
||||||
|
// (a'(\omega^i) + \beta)(s'(\omega^i) + \gamma)
|
||||||
|
//
|
||||||
|
// where a_j(X) is the jth input column in this lookup,
|
||||||
|
// where a'(X) is the compression of the permuted input columns,
|
||||||
|
// s_j(X) is the jth table column in this lookup,
|
||||||
|
// s'(X) is the compression of the permuted table columns,
|
||||||
|
// and i is the ith row of the column.
|
||||||
|
let mut lookup_product = vec![C::Scalar::one(); params.n as usize];
|
||||||
|
|
||||||
|
// Denominator uses the permuted input column and permuted table column
|
||||||
|
parallelize(&mut lookup_product, |lookup_product, start| {
|
||||||
|
for ((lookup_product, permuted_input_value), permuted_table_value) in lookup_product
|
||||||
|
.iter_mut()
|
||||||
|
.zip(permuted.permuted_input_value[start..].iter())
|
||||||
|
.zip(permuted.permuted_table_value[start..].iter())
|
||||||
|
{
|
||||||
|
*lookup_product *= &(beta + permuted_input_value);
|
||||||
|
*lookup_product *= &(gamma + permuted_table_value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Batch invert to obtain the denominators for the lookup product
|
||||||
|
// polynomials
|
||||||
|
lookup_product.iter_mut().batch_invert();
|
||||||
|
|
||||||
|
// Finish the computation of the entire fraction by computing the numerators
|
||||||
|
// (a_1(X) + \theta a_2(X) + ... + \beta) (s_1(X) + \theta s_2(X) + ... + \gamma)
|
||||||
|
// Compress unpermuted input columns
|
||||||
|
let mut input_term = vec![C::Scalar::zero(); params.n as usize];
|
||||||
|
for unpermuted_input_value in unpermuted_input_values.iter() {
|
||||||
|
parallelize(&mut input_term, |input_term, start| {
|
||||||
|
for (input_term, input_value) in input_term
|
||||||
|
.iter_mut()
|
||||||
|
.zip(unpermuted_input_value[start..].iter())
|
||||||
|
{
|
||||||
|
*input_term *= θ
|
||||||
|
*input_term += input_value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compress unpermuted table columns
|
||||||
|
let mut table_term = vec![C::Scalar::zero(); params.n as usize];
|
||||||
|
for unpermuted_table_value in unpermuted_table_values.iter() {
|
||||||
|
parallelize(&mut table_term, |table_term, start| {
|
||||||
|
for (table_term, fixed_value) in table_term
|
||||||
|
.iter_mut()
|
||||||
|
.zip(unpermuted_table_value[start..].iter())
|
||||||
|
{
|
||||||
|
*table_term *= θ
|
||||||
|
*table_term += fixed_value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add \beta and \gamma offsets
|
||||||
|
parallelize(&mut lookup_product, |product, start| {
|
||||||
|
for ((product, input_term), table_term) in product
|
||||||
|
.iter_mut()
|
||||||
|
.zip(input_term[start..].iter())
|
||||||
|
.zip(table_term[start..].iter())
|
||||||
|
{
|
||||||
|
*product *= &(*input_term + &beta);
|
||||||
|
*product *= &(*table_term + &gamma);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// The product vector is a vector of products of fractions of the form
|
||||||
|
//
|
||||||
|
// (a_1(\omega^i) + \theta a_2(\omega^i) + ... + \beta)(s_1(\omega^i) + \theta s_2(\omega^i) + ... + \gamma)/
|
||||||
|
// (a'(\omega^i) + \beta) (s'(\omega^i) + \gamma)
|
||||||
|
//
|
||||||
|
// where a_j(\omega^i) is the jth input column in this lookup,
|
||||||
|
// a'j(\omega^i) is the permuted input column,
|
||||||
|
// s_j(\omega^i) is the jth table column in this lookup,
|
||||||
|
// s'(\omega^i) is the permuted table column,
|
||||||
|
// and i is the ith row of the column.
|
||||||
|
|
||||||
|
// Compute the evaluations of the lookup product polynomial
|
||||||
|
// over our domain, starting with z[0] = 1
|
||||||
|
let mut z = vec![C::Scalar::one()];
|
||||||
|
for row in 1..(params.n as usize) {
|
||||||
|
let mut tmp = z[row - 1];
|
||||||
|
tmp *= &lookup_product[row];
|
||||||
|
z.push(tmp);
|
||||||
|
}
|
||||||
|
let z = pk.vk.domain.lagrange_from_vec(z);
|
||||||
|
|
||||||
|
#[cfg(feature = "sanity-checks")]
|
||||||
|
// This test works only with intermediate representations in this method.
|
||||||
|
// It can be used for debugging purposes.
|
||||||
|
{
|
||||||
|
// While in Lagrange basis, check that product is correctly constructed
|
||||||
|
let n = params.n as usize;
|
||||||
|
|
||||||
|
// z'(X) (a'(X) + \beta) (s'(X) + \gamma)
|
||||||
|
// - z'(\omega^{-1} X) (a_1(X) + \theta a_2(X) + ... + \beta) (s_1(X) + \theta s_2(X) + ... + \gamma)
|
||||||
|
for i in 0..n {
|
||||||
|
let prev_idx = (n + i - 1) % n;
|
||||||
|
|
||||||
|
let mut left = z[i];
|
||||||
|
let permuted_input_value = &permuted.permuted_input_value[i];
|
||||||
|
|
||||||
|
let permuted_table_value = &permuted.permuted_table_value[i];
|
||||||
|
|
||||||
|
left *= &(*beta + permuted_input_value);
|
||||||
|
left *= &(*gamma + permuted_table_value);
|
||||||
|
|
||||||
|
let mut right = z[prev_idx];
|
||||||
|
let mut input_term = unpermuted_input_values
|
||||||
|
.iter()
|
||||||
|
.fold(C::Scalar::zero(), |acc, input| acc * &theta + &input[i]);
|
||||||
|
|
||||||
|
let mut table_term = unpermuted_table_values
|
||||||
|
.iter()
|
||||||
|
.fold(C::Scalar::zero(), |acc, table| acc * &theta + &table[i]);
|
||||||
|
|
||||||
|
input_term += &(*beta);
|
||||||
|
table_term += &(*gamma);
|
||||||
|
right *= &(input_term * &table_term);
|
||||||
|
|
||||||
|
assert_eq!(left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let product_blind = Blind(C::Scalar::rand());
|
||||||
|
let product_commitment = params.commit_lagrange(&z, product_blind).to_affine();
|
||||||
|
let z = pk.vk.domain.lagrange_to_coeff(z);
|
||||||
|
let product_coset = pk
|
||||||
|
.vk
|
||||||
|
.domain
|
||||||
|
.coeff_to_extended(z.clone(), Rotation::default());
|
||||||
|
let product_inv_coset = pk.vk.domain.coeff_to_extended(z.clone(), Rotation(-1));
|
||||||
|
|
||||||
|
// Hash each product commitment
|
||||||
|
transcript
|
||||||
|
.absorb_point(&product_commitment)
|
||||||
|
.map_err(|_| Error::TranscriptError)?;
|
||||||
|
|
||||||
|
Ok(Product::<C> {
|
||||||
|
product_poly: z,
|
||||||
|
product_coset,
|
||||||
|
product_inv_coset,
|
||||||
|
product_commitment,
|
||||||
|
product_blind,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a column of input values A and a column of table values S,
|
/// Given a column of input values A and a column of table values S,
|
||||||
|
|
Loading…
Reference in New Issue