mirror of https://github.com/zcash/halo2.git
Refactor h_eval computation into separate, more functional code.
Co-authored-by: str4d <thestr4d@gmail.com>
This commit is contained in:
parent
e275d78c7d
commit
7d8daa5d05
|
@ -63,7 +63,10 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
// Sample x_3 challenge, which is used to ensure the circuit is
|
// Sample x_3 challenge, which is used to ensure the circuit is
|
||||||
// satisfied with high probability.
|
// satisfied with high probability.
|
||||||
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
|
||||||
|
// This check ensures the circuit is satisfied so long as the polynomial
|
||||||
|
// commitments open to the correct values.
|
||||||
|
self.check_hx(params, vk, x_0, x_1, x_2, x_3)?;
|
||||||
|
|
||||||
// Hash together all the openings provided by the prover into a new
|
// Hash together all the openings provided by the prover into a new
|
||||||
// transcript on the scalar field.
|
// transcript on the scalar field.
|
||||||
|
@ -86,83 +89,6 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
||||||
transcript.absorb(transcript_scalar_point);
|
transcript.absorb(transcript_scalar_point);
|
||||||
|
|
||||||
// Evaluate the circuit using the custom gates provided
|
|
||||||
let mut h_eval = C::Scalar::zero();
|
|
||||||
for poly in vk.cs.gates.iter() {
|
|
||||||
h_eval *= &x_2;
|
|
||||||
|
|
||||||
let evaluation: C::Scalar = poly.evaluate(
|
|
||||||
&|index| self.fixed_evals[index],
|
|
||||||
&|index| self.advice_evals[index],
|
|
||||||
&|index| self.aux_evals[index],
|
|
||||||
&|a, b| a + &b,
|
|
||||||
&|a, b| a * &b,
|
|
||||||
&|a, scalar| a * &scalar,
|
|
||||||
);
|
|
||||||
|
|
||||||
h_eval += &evaluation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First element in each permutation product should be 1
|
|
||||||
// l_0(X) * (1 - z(X)) = 0
|
|
||||||
{
|
|
||||||
// TODO: bubble this error up
|
|
||||||
let denominator = (x_3 - &C::Scalar::one()).invert().unwrap();
|
|
||||||
|
|
||||||
for eval in self.permutation_product_evals.iter() {
|
|
||||||
h_eval *= &x_2;
|
|
||||||
|
|
||||||
let mut tmp = denominator; // 1 / (x_3 - 1)
|
|
||||||
tmp *= &(x_3n - &C::Scalar::one()); // (x_3^n - 1) / (x_3 - 1)
|
|
||||||
tmp *= &vk.domain.get_barycentric_weight(); // l_0(x_3)
|
|
||||||
tmp *= &(C::Scalar::one() - &eval); // l_0(X) * (1 - z(X))
|
|
||||||
|
|
||||||
h_eval += &tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
|
|
||||||
for (permutation_index, wires) in vk.cs.permutations.iter().enumerate() {
|
|
||||||
h_eval *= &x_2;
|
|
||||||
|
|
||||||
let mut left = self.permutation_product_evals[permutation_index];
|
|
||||||
for (advice_eval, permutation_eval) in wires
|
|
||||||
.iter()
|
|
||||||
.map(|&wire| self.advice_evals[vk.cs.get_advice_query_index(wire, 0)])
|
|
||||||
.zip(self.permutation_evals[permutation_index].iter())
|
|
||||||
{
|
|
||||||
left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut right = self.permutation_product_inv_evals[permutation_index];
|
|
||||||
let mut current_delta = x_0 * &x_3;
|
|
||||||
for advice_eval in wires
|
|
||||||
.iter()
|
|
||||||
.map(|&wire| self.advice_evals[vk.cs.get_advice_query_index(wire, 0)])
|
|
||||||
{
|
|
||||||
right *= &(advice_eval + ¤t_delta + &x_1);
|
|
||||||
current_delta *= &C::Scalar::DELTA;
|
|
||||||
}
|
|
||||||
|
|
||||||
h_eval += &left;
|
|
||||||
h_eval -= &right;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the expected h(x) value
|
|
||||||
let mut expected_h_eval = C::Scalar::zero();
|
|
||||||
let mut cur = C::Scalar::one();
|
|
||||||
for eval in &self.h_evals {
|
|
||||||
expected_h_eval += &(cur * eval);
|
|
||||||
cur *= &x_3n;
|
|
||||||
}
|
|
||||||
|
|
||||||
if h_eval != (expected_h_eval * &(x_3n - &C::Scalar::one())) {
|
|
||||||
return Err(Error::ConstraintSystemFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are now convinced the circuit is satisfied so long as the
|
|
||||||
// polynomial commitments open to the correct values.
|
|
||||||
|
|
||||||
// Sample x_4 for compressing openings at the same points together
|
// Sample x_4 for compressing openings at the same points together
|
||||||
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
|
||||||
|
@ -293,4 +219,95 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
.verify(params, msm, &mut transcript, x_6, commitment_msm, msm_eval)
|
.verify(params, msm, &mut transcript, x_6, commitment_msm, msm_eval)
|
||||||
.map_err(|_| Error::OpeningError)
|
.map_err(|_| Error::OpeningError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks that this proof's h_evals are correct, and thus that all of the
|
||||||
|
/// rules are satisfied.
|
||||||
|
fn check_hx(
|
||||||
|
&self,
|
||||||
|
params: &'a Params<C>,
|
||||||
|
vk: &VerifyingKey<C>,
|
||||||
|
x_0: C::Scalar,
|
||||||
|
x_1: C::Scalar,
|
||||||
|
x_2: C::Scalar,
|
||||||
|
x_3: C::Scalar,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
// x_3^n
|
||||||
|
let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]);
|
||||||
|
|
||||||
|
// TODO: bubble this error up
|
||||||
|
// l_0(x_3)
|
||||||
|
let l_0 = (x_3 - &C::Scalar::one()).invert().unwrap() // 1 / (x_3 - 1)
|
||||||
|
* &(x_3n - &C::Scalar::one()) // (x_3^n - 1) / (x_3 - 1)
|
||||||
|
* &vk.domain.get_barycentric_weight(); // l_0(x_3)
|
||||||
|
|
||||||
|
// Compute the expected value of h(x_3)
|
||||||
|
let h_eval = std::iter::empty()
|
||||||
|
// Evaluate the circuit using the custom gates provided
|
||||||
|
.chain(vk.cs.gates.iter().map(|poly| {
|
||||||
|
poly.evaluate(
|
||||||
|
&|index| self.fixed_evals[index],
|
||||||
|
&|index| self.advice_evals[index],
|
||||||
|
&|index| self.aux_evals[index],
|
||||||
|
&|a, b| a + &b,
|
||||||
|
&|a, b| a * &b,
|
||||||
|
&|a, scalar| a * &scalar,
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
// l_0(X) * (1 - z(X)) = 0
|
||||||
|
.chain(
|
||||||
|
self.permutation_product_evals
|
||||||
|
.iter()
|
||||||
|
.map(|product_eval| l_0 * &(C::Scalar::one() - &product_eval)),
|
||||||
|
)
|
||||||
|
// z(X) \prod (p(X) + \beta s_i(X) + \gamma)
|
||||||
|
// - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
|
||||||
|
.chain(
|
||||||
|
vk.cs
|
||||||
|
.permutations
|
||||||
|
.iter()
|
||||||
|
.zip(self.permutation_evals.iter())
|
||||||
|
.zip(self.permutation_product_evals.iter())
|
||||||
|
.zip(self.permutation_product_inv_evals.iter())
|
||||||
|
.map(
|
||||||
|
|(((wires, permutation_evals), product_eval), product_inv_eval)| {
|
||||||
|
let mut left = *product_eval;
|
||||||
|
for (advice_eval, permutation_eval) in wires
|
||||||
|
.iter()
|
||||||
|
.map(|&wire| {
|
||||||
|
self.advice_evals[vk.cs.get_advice_query_index(wire, 0)]
|
||||||
|
})
|
||||||
|
.zip(permutation_evals.iter())
|
||||||
|
{
|
||||||
|
left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut right = *product_inv_eval;
|
||||||
|
let mut current_delta = x_0 * &x_3;
|
||||||
|
for advice_eval in wires.iter().map(|&wire| {
|
||||||
|
self.advice_evals[vk.cs.get_advice_query_index(wire, 0)]
|
||||||
|
}) {
|
||||||
|
right *= &(advice_eval + ¤t_delta + &x_1);
|
||||||
|
current_delta *= &C::Scalar::DELTA;
|
||||||
|
}
|
||||||
|
|
||||||
|
left - &right
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.fold(C::Scalar::zero(), |h_eval, v| h_eval * &x_2 + &v);
|
||||||
|
|
||||||
|
// Compute the expected h(x_3) value
|
||||||
|
let mut expected_h_eval = C::Scalar::zero();
|
||||||
|
let mut cur = C::Scalar::one();
|
||||||
|
for eval in &self.h_evals {
|
||||||
|
expected_h_eval += &(cur * eval);
|
||||||
|
cur *= &x_3n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if h_eval != (expected_h_eval * &(x_3n - &C::Scalar::one())) {
|
||||||
|
return Err(Error::ConstraintSystemFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue