Introduce typed challenge scalars

This also centralises the challenge generation logic in Challenge::get,
ensuring it is consistent across the codebase.
This commit is contained in:
Jack Grigg 2020-11-25 19:26:31 +00:00
parent 63e3bc1e15
commit f63f3ff2af
11 changed files with 241 additions and 196 deletions

View file

@ -68,27 +68,6 @@ where
} }
} }
/// This is a 128-bit verifier challenge.
#[derive(Copy, Clone, Debug)]
pub struct Challenge(pub(crate) u128);
/// This algorithm applies the mapping of Algorithm 1 from the
/// [Halo](https://eprint.iacr.org/2019/1021) paper.
pub fn get_challenge_scalar<F: FieldExt>(challenge: Challenge) -> F {
let mut acc = (F::ZETA + F::one()).double();
for i in (0..64).rev() {
let should_negate = ((challenge.0 >> ((i << 1) + 1)) & 1) == 1;
let should_endo = ((challenge.0 >> (i << 1)) & 1) == 1;
let q = if should_negate { -F::one() } else { F::one() };
let q = if should_endo { q * F::ZETA } else { q };
acc = acc + q + acc;
}
acc
}
fn multiexp_serial<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C], acc: &mut C::Projective) { fn multiexp_serial<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C], acc: &mut C::Projective) {
let coeffs: Vec<[u8; 32]> = coeffs.iter().map(|a| a.to_bytes()).collect(); let coeffs: Vec<[u8; 32]> = coeffs.iter().map(|a| a.to_bytes()).collect();

View file

@ -7,7 +7,8 @@
use crate::arithmetic::CurveAffine; use crate::arithmetic::CurveAffine;
use crate::poly::{ use crate::poly::{
multiopen, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, commitment::ChallengeScalar, multiopen, Coeff, EvaluationDomain, ExtendedLagrangeCoeff,
LagrangeCoeff, Polynomial,
}; };
mod circuit; mod circuit;
@ -93,6 +94,22 @@ impl<C: CurveAffine> VerifyingKey<C> {
} }
} }
#[derive(Clone, Copy, Debug)]
pub(crate) struct Beta;
pub(crate) type ChallengeBeta<F> = ChallengeScalar<F, Beta>;
#[derive(Clone, Copy, Debug)]
pub(crate) struct Gamma;
pub(crate) type ChallengeGamma<F> = ChallengeScalar<F, Gamma>;
#[derive(Clone, Copy, Debug)]
pub(crate) struct Y;
pub(crate) type ChallengeY<F> = ChallengeScalar<F, Y>;
#[derive(Clone, Copy, Debug)]
pub(crate) struct X;
pub(crate) type ChallengeX<F> = ChallengeScalar<F, X>;
#[test] #[test]
fn test_proving() { fn test_proving() {
use crate::arithmetic::{Curve, FieldExt}; use crate::arithmetic::{Curve, FieldExt};

View file

@ -4,7 +4,7 @@ use std::iter;
use super::Proof; use super::Proof;
use crate::{ use crate::{
arithmetic::{eval_polynomial, parallelize, BatchInvert, Curve, CurveAffine, FieldExt}, arithmetic::{eval_polynomial, parallelize, BatchInvert, Curve, CurveAffine, FieldExt},
plonk::{Error, ProvingKey}, plonk::{ChallengeBeta, ChallengeGamma, ChallengeX, Error, ProvingKey},
poly::{ poly::{
commitment::{Blind, Params}, commitment::{Blind, Params},
multiopen::ProverQuery, multiopen::ProverQuery,
@ -40,8 +40,8 @@ impl<C: CurveAffine> Proof<C> {
params: &Params<C>, params: &Params<C>,
pk: &ProvingKey<C>, pk: &ProvingKey<C>,
advice: &[Polynomial<C::Scalar, LagrangeCoeff>], advice: &[Polynomial<C::Scalar, LagrangeCoeff>],
x_0: C::Scalar, beta: ChallengeBeta<C::Scalar>,
x_1: C::Scalar, gamma: ChallengeGamma<C::Scalar>,
transcript: &mut Transcript<C, HBase, HScalar>, transcript: &mut Transcript<C, HBase, HScalar>,
) -> Result<Committed<C>, Error> { ) -> Result<Committed<C>, Error> {
let domain = &pk.vk.domain; let domain = &pk.vk.domain;
@ -81,7 +81,7 @@ impl<C: CurveAffine> Proof<C> {
.zip(permuted_column_values[start..].iter()) .zip(permuted_column_values[start..].iter())
{ {
*modified_advice *= *modified_advice *=
&(x_0 * permuted_advice_value + &x_1 + advice_value); &(*beta * permuted_advice_value + &gamma + advice_value);
} }
}); });
} }
@ -116,7 +116,7 @@ impl<C: CurveAffine> Proof<C> {
.zip(advice[column.index()][start..].iter()) .zip(advice[column.index()][start..].iter())
{ {
// Multiply by p_j(\omega^i) + \delta^j \omega^i \beta // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta
*modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); *modified_advice *= &(deltaomega * &beta + &gamma + advice_value);
deltaomega *= &omega; deltaomega *= &omega;
} }
}); });
@ -184,8 +184,8 @@ impl<C: CurveAffine> Committed<C> {
self, self,
pk: &'a ProvingKey<C>, pk: &'a ProvingKey<C>,
advice_cosets: &'a [Polynomial<C::Scalar, ExtendedLagrangeCoeff>], advice_cosets: &'a [Polynomial<C::Scalar, ExtendedLagrangeCoeff>],
x_0: C::Scalar, beta: ChallengeBeta<C::Scalar>,
x_1: C::Scalar, gamma: ChallengeGamma<C::Scalar>,
) -> Result< ) -> Result<
( (
Constructed<C>, Constructed<C>,
@ -220,13 +220,13 @@ impl<C: CurveAffine> Committed<C> {
.zip(advice[start..].iter()) .zip(advice[start..].iter())
.zip(permutation[start..].iter()) .zip(permutation[start..].iter())
{ {
*left *= &(*advice + &(x_0 * permutation) + &x_1); *left *= &(*advice + &(*beta * permutation) + &gamma);
} }
}); });
} }
let mut right = permutation_product_cosets_inv[permutation_index].clone(); let mut right = permutation_product_cosets_inv[permutation_index].clone();
let mut current_delta = x_0 * &C::Scalar::ZETA; let mut current_delta = *beta * &C::Scalar::ZETA;
let step = domain.get_extended_omega(); let step = domain.get_extended_omega();
for advice in columns for advice in columns
.iter() .iter()
@ -236,7 +236,7 @@ impl<C: CurveAffine> Committed<C> {
let mut beta_term = let mut beta_term =
current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]); current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]);
for (right, advice) in right.iter_mut().zip(advice[start..].iter()) { for (right, advice) in right.iter_mut().zip(advice[start..].iter()) {
*right *= &(*advice + &beta_term + &x_1); *right *= &(*advice + &beta_term + &gamma);
beta_term *= &step; beta_term *= &step;
} }
}); });
@ -262,7 +262,7 @@ impl<C: CurveAffine> Constructed<C> {
pub(crate) fn evaluate<HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>( pub(crate) fn evaluate<HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
self, self,
pk: &ProvingKey<C>, pk: &ProvingKey<C>,
x_3: C::Scalar, x: ChallengeX<C::Scalar>,
transcript: &mut Transcript<C, HBase, HScalar>, transcript: &mut Transcript<C, HBase, HScalar>,
) -> Evaluated<C> { ) -> Evaluated<C> {
let domain = &pk.vk.domain; let domain = &pk.vk.domain;
@ -270,24 +270,19 @@ impl<C: CurveAffine> Constructed<C> {
let permutation_product_evals: Vec<C::Scalar> = self let permutation_product_evals: Vec<C::Scalar> = self
.permutation_product_polys .permutation_product_polys
.iter() .iter()
.map(|poly| eval_polynomial(poly, x_3)) .map(|poly| eval_polynomial(poly, *x))
.collect(); .collect();
let permutation_product_inv_evals: Vec<C::Scalar> = self let permutation_product_inv_evals: Vec<C::Scalar> = self
.permutation_product_polys .permutation_product_polys
.iter() .iter()
.map(|poly| eval_polynomial(poly, domain.rotate_omega(x_3, Rotation(-1)))) .map(|poly| eval_polynomial(poly, domain.rotate_omega(*x, Rotation(-1))))
.collect(); .collect();
let permutation_evals: Vec<Vec<C::Scalar>> = pk let permutation_evals: Vec<Vec<C::Scalar>> = pk
.permutation_polys .permutation_polys
.iter() .iter()
.map(|polys| { .map(|polys| polys.iter().map(|poly| eval_polynomial(poly, *x)).collect())
polys
.iter()
.map(|poly| eval_polynomial(poly, x_3))
.collect()
})
.collect(); .collect();
// Hash each advice evaluation // Hash each advice evaluation
@ -312,12 +307,12 @@ impl<C: CurveAffine> Evaluated<C> {
pub fn open<'a>( pub fn open<'a>(
&'a self, &'a self,
pk: &'a ProvingKey<C>, pk: &'a ProvingKey<C>,
x_3: C::Scalar, x: ChallengeX<C::Scalar>,
) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone { ) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
let x_3_inv = pk.vk.domain.rotate_omega(x_3, Rotation(-1)); let x_inv = pk.vk.domain.rotate_omega(*x, Rotation(-1));
iter::empty() iter::empty()
// Open permutation product commitments at x_3 // Open permutation product commitments at x
.chain( .chain(
self.constructed self.constructed
.permutation_product_polys .permutation_product_polys
@ -325,26 +320,26 @@ impl<C: CurveAffine> Evaluated<C> {
.zip(self.constructed.permutation_product_blinds.iter()) .zip(self.constructed.permutation_product_blinds.iter())
.zip(self.permutation_product_evals.iter()) .zip(self.permutation_product_evals.iter())
.map(move |((poly, blind), eval)| ProverQuery { .map(move |((poly, blind), eval)| ProverQuery {
point: x_3, point: *x,
poly, poly,
blind: *blind, blind: *blind,
eval: *eval, eval: *eval,
}), }),
) )
// Open permutation polynomial commitments at x_3 // Open permutation polynomial commitments at x
.chain( .chain(
pk.permutation_polys pk.permutation_polys
.iter() .iter()
.zip(self.permutation_evals.iter()) .zip(self.permutation_evals.iter())
.flat_map(|(polys, evals)| polys.iter().zip(evals.iter())) .flat_map(|(polys, evals)| polys.iter().zip(evals.iter()))
.map(move |(poly, eval)| ProverQuery { .map(move |(poly, eval)| ProverQuery {
point: x_3, point: *x,
poly, poly,
blind: Blind::default(), blind: Blind::default(),
eval: *eval, eval: *eval,
}), }),
) )
// Open permutation product commitments at \omega^{-1} x_3 // Open permutation product commitments at \omega^{-1} x
.chain( .chain(
self.constructed self.constructed
.permutation_product_polys .permutation_product_polys
@ -352,7 +347,7 @@ impl<C: CurveAffine> Evaluated<C> {
.zip(self.constructed.permutation_product_blinds.iter()) .zip(self.constructed.permutation_product_blinds.iter())
.zip(self.permutation_product_inv_evals.iter()) .zip(self.permutation_product_inv_evals.iter())
.map(move |((poly, blind), eval)| ProverQuery { .map(move |((poly, blind), eval)| ProverQuery {
point: x_3_inv, point: x_inv,
poly, poly,
blind: *blind, blind: *blind,
eval: *eval, eval: *eval,

View file

@ -4,7 +4,7 @@ use std::iter;
use super::Proof; use super::Proof;
use crate::{ use crate::{
arithmetic::{CurveAffine, FieldExt}, arithmetic::{CurveAffine, FieldExt},
plonk::{Error, VerifyingKey}, plonk::{ChallengeBeta, ChallengeGamma, ChallengeX, Error, VerifyingKey},
poly::{multiopen::VerifierQuery, Rotation}, poly::{multiopen::VerifierQuery, Rotation},
transcript::{Hasher, Transcript}, transcript::{Hasher, Transcript},
}; };
@ -55,9 +55,9 @@ impl<C: CurveAffine> Proof<C> {
vk: &'a VerifyingKey<C>, vk: &'a VerifyingKey<C>,
advice_evals: &'a [C::Scalar], advice_evals: &'a [C::Scalar],
l_0: C::Scalar, l_0: C::Scalar,
x_0: C::Scalar, beta: ChallengeBeta<C::Scalar>,
x_1: C::Scalar, gamma: ChallengeGamma<C::Scalar>,
x_3: C::Scalar, x: ChallengeX<C::Scalar>,
) -> impl Iterator<Item = C::Scalar> + 'a { ) -> impl Iterator<Item = C::Scalar> + 'a {
iter::empty() iter::empty()
// l_0(X) * (1 - z(X)) = 0 // l_0(X) * (1 - z(X)) = 0
@ -85,15 +85,15 @@ impl<C: CurveAffine> Proof<C> {
}) })
.zip(permutation_evals.iter()) .zip(permutation_evals.iter())
{ {
left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1); left *= &(advice_eval + &(*beta * permutation_eval) + &gamma);
} }
let mut right = *product_inv_eval; let mut right = *product_inv_eval;
let mut current_delta = x_0 * &x_3; let mut current_delta = *beta * &x;
for advice_eval in columns.iter().map(|&column| { for advice_eval in columns.iter().map(|&column| {
advice_evals[vk.cs.get_advice_query_index(column, 0)] advice_evals[vk.cs.get_advice_query_index(column, 0)]
}) { }) {
right *= &(advice_eval + &current_delta + &x_1); right *= &(advice_eval + &current_delta + &gamma);
current_delta *= &C::Scalar::DELTA; current_delta *= &C::Scalar::DELTA;
} }
@ -113,44 +113,44 @@ impl<C: CurveAffine> Proof<C> {
pub(crate) fn queries<'a>( pub(crate) fn queries<'a>(
&'a self, &'a self,
vk: &'a VerifyingKey<C>, vk: &'a VerifyingKey<C>,
x_3: C::Scalar, x: ChallengeX<C::Scalar>,
) -> impl Iterator<Item = VerifierQuery<'a, C>> + Clone { ) -> impl Iterator<Item = VerifierQuery<'a, C>> + Clone {
let x_3_inv = vk.domain.rotate_omega(x_3, Rotation(-1)); let x_inv = vk.domain.rotate_omega(*x, Rotation(-1));
iter::empty() iter::empty()
// Open permutation product commitments at x_3 // Open permutation product commitments at x
.chain( .chain(
self.permutation_product_commitments self.permutation_product_commitments
.iter() .iter()
.enumerate() .enumerate()
.zip(self.permutation_product_evals.iter()) .zip(self.permutation_product_evals.iter())
.map(move |((idx, _), &eval)| VerifierQuery { .map(move |((idx, _), &eval)| VerifierQuery {
point: x_3, point: *x,
commitment: &self.permutation_product_commitments[idx], commitment: &self.permutation_product_commitments[idx],
eval, eval,
}), }),
) )
// Open permutation commitments for each permutation argument at x_3 // Open permutation commitments for each permutation argument at x
.chain( .chain(
(0..vk.permutation_commitments.len()) (0..vk.permutation_commitments.len())
.map(move |outer_idx| { .map(move |outer_idx| {
let inner_len = vk.permutation_commitments[outer_idx].len(); let inner_len = vk.permutation_commitments[outer_idx].len();
(0..inner_len).map(move |inner_idx| VerifierQuery { (0..inner_len).map(move |inner_idx| VerifierQuery {
point: x_3, point: *x,
commitment: &vk.permutation_commitments[outer_idx][inner_idx], commitment: &vk.permutation_commitments[outer_idx][inner_idx],
eval: self.permutation_evals[outer_idx][inner_idx], eval: self.permutation_evals[outer_idx][inner_idx],
}) })
}) })
.flatten(), .flatten(),
) )
// Open permutation product commitments at \omega^{-1} x_3 // Open permutation product commitments at \omega^{-1} x
.chain( .chain(
self.permutation_product_commitments self.permutation_product_commitments
.iter() .iter()
.enumerate() .enumerate()
.zip(self.permutation_product_inv_evals.iter()) .zip(self.permutation_product_inv_evals.iter())
.map(move |((idx, _), &eval)| VerifierQuery { .map(move |((idx, _), &eval)| VerifierQuery {
point: x_3_inv, point: x_inv,
commitment: &self.permutation_product_commitments[idx], commitment: &self.permutation_product_commitments[idx],
eval, eval,
}), }),

View file

@ -3,11 +3,9 @@ use std::iter;
use super::{ use super::{
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed}, circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
permutation, Error, Proof, ProvingKey, permutation, ChallengeBeta, ChallengeGamma, ChallengeX, ChallengeY, Error, Proof, ProvingKey,
};
use crate::arithmetic::{
eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, FieldExt,
}; };
use crate::arithmetic::{eval_polynomial, Curve, CurveAffine, FieldExt};
use crate::poly::{ use crate::poly::{
commitment::{Blind, Params}, commitment::{Blind, Params},
multiopen::{self, ProverQuery}, multiopen::{self, ProverQuery},
@ -170,11 +168,11 @@ impl<C: CurveAffine> Proof<C> {
}) })
.collect(); .collect();
// Sample x_0 challenge // Sample beta challenge
let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let beta = ChallengeBeta::get(&mut transcript);
// Sample x_1 challenge // Sample gamma challenge
let x_1: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let gamma = ChallengeGamma::get(&mut transcript);
// Commit to permutations, if any. // Commit to permutations, if any.
let permutations = if !pk.vk.cs.permutations.is_empty() { let permutations = if !pk.vk.cs.permutations.is_empty() {
@ -182,8 +180,8 @@ impl<C: CurveAffine> Proof<C> {
params, params,
pk, pk,
&witness.advice, &witness.advice,
x_0, beta,
x_1, gamma,
&mut transcript, &mut transcript,
)?) )?)
} else { } else {
@ -191,11 +189,11 @@ impl<C: CurveAffine> Proof<C> {
}; };
// Obtain challenge for keeping all separate gates linearly independent // Obtain challenge for keeping all separate gates linearly independent
let x_2: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let y = ChallengeY::<C::Scalar>::get(&mut transcript);
// Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any. // Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any.
let (permutations, permutation_expressions) = permutations let (permutations, permutation_expressions) = permutations
.map(|p| p.construct(pk, &advice_cosets, x_0, x_1)) .map(|p| p.construct(pk, &advice_cosets, beta, gamma))
.transpose()? .transpose()?
.map(|(p, expressions)| (Some(p), Some(expressions))) .map(|(p, expressions)| (Some(p), Some(expressions)))
.unwrap_or_default(); .unwrap_or_default();
@ -215,7 +213,7 @@ impl<C: CurveAffine> Proof<C> {
})) }))
// Permutation constraints, if any. // Permutation constraints, if any.
.chain(permutation_expressions.into_iter().flatten()) .chain(permutation_expressions.into_iter().flatten())
.fold(domain.empty_extended(), |h_poly, v| h_poly * x_2 + &v); .fold(domain.empty_extended(), |h_poly, v| h_poly * *y + &v);
// Divide by t(X) = X^{params.n} - 1. // Divide by t(X) = X^{params.n} - 1.
let h_poly = domain.divide_by_vanishing_poly(h_poly); let h_poly = domain.divide_by_vanishing_poly(h_poly);
@ -249,14 +247,14 @@ impl<C: CurveAffine> Proof<C> {
.map_err(|_| Error::TranscriptError)?; .map_err(|_| Error::TranscriptError)?;
} }
let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x = ChallengeX::get(&mut transcript);
// Evaluate polynomials at omega^i x_3 // Evaluate polynomials at omega^i x
let advice_evals: Vec<_> = meta let advice_evals: Vec<_> = meta
.advice_queries .advice_queries
.iter() .iter()
.map(|&(column, at)| { .map(|&(column, at)| {
eval_polynomial(&advice_polys[column.index()], domain.rotate_omega(x_3, at)) eval_polynomial(&advice_polys[column.index()], domain.rotate_omega(*x, at))
}) })
.collect(); .collect();
@ -264,7 +262,7 @@ impl<C: CurveAffine> Proof<C> {
.aux_queries .aux_queries
.iter() .iter()
.map(|&(column, at)| { .map(|&(column, at)| {
eval_polynomial(&aux_polys[column.index()], domain.rotate_omega(x_3, at)) eval_polynomial(&aux_polys[column.index()], domain.rotate_omega(*x, at))
}) })
.collect(); .collect();
@ -272,16 +270,13 @@ impl<C: CurveAffine> Proof<C> {
.fixed_queries .fixed_queries
.iter() .iter()
.map(|&(column, at)| { .map(|&(column, at)| {
eval_polynomial( eval_polynomial(&pk.fixed_polys[column.index()], domain.rotate_omega(*x, at))
&pk.fixed_polys[column.index()],
domain.rotate_omega(x_3, at),
)
}) })
.collect(); .collect();
let h_evals: Vec<_> = h_pieces let h_evals: Vec<_> = h_pieces
.iter() .iter()
.map(|poly| eval_polynomial(poly, x_3)) .map(|poly| eval_polynomial(poly, *x))
.collect(); .collect();
// Hash each advice evaluation // Hash each advice evaluation
@ -294,14 +289,14 @@ impl<C: CurveAffine> Proof<C> {
transcript.absorb_scalar(*eval); transcript.absorb_scalar(*eval);
} }
// Evaluate the permutations, if any, at omega^i x_3. // Evaluate the permutations, if any, at omega^i x.
let permutations = permutations.map(|p| p.evaluate(pk, x_3, &mut transcript)); let permutations = permutations.map(|p| p.evaluate(pk, x, &mut transcript));
let instances = let instances =
iter::empty() iter::empty()
.chain(pk.vk.cs.advice_queries.iter().enumerate().map( .chain(pk.vk.cs.advice_queries.iter().enumerate().map(
|(query_index, &(column, at))| ProverQuery { |(query_index, &(column, at))| ProverQuery {
point: domain.rotate_omega(x_3, at), point: domain.rotate_omega(*x, at),
poly: &advice_polys[column.index()], poly: &advice_polys[column.index()],
blind: advice_blinds[column.index()], blind: advice_blinds[column.index()],
eval: advice_evals[query_index], eval: advice_evals[query_index],
@ -309,7 +304,7 @@ impl<C: CurveAffine> Proof<C> {
)) ))
.chain(pk.vk.cs.aux_queries.iter().enumerate().map( .chain(pk.vk.cs.aux_queries.iter().enumerate().map(
|(query_index, &(column, at))| ProverQuery { |(query_index, &(column, at))| ProverQuery {
point: domain.rotate_omega(x_3, at), point: domain.rotate_omega(*x, at),
poly: &aux_polys[column.index()], poly: &aux_polys[column.index()],
blind: Blind::default(), blind: Blind::default(),
eval: aux_evals[query_index], eval: aux_evals[query_index],
@ -317,20 +312,20 @@ impl<C: CurveAffine> Proof<C> {
)) ))
.chain(pk.vk.cs.fixed_queries.iter().enumerate().map( .chain(pk.vk.cs.fixed_queries.iter().enumerate().map(
|(query_index, &(column, at))| ProverQuery { |(query_index, &(column, at))| ProverQuery {
point: domain.rotate_omega(x_3, at), point: domain.rotate_omega(*x, at),
poly: &pk.fixed_polys[column.index()], poly: &pk.fixed_polys[column.index()],
blind: Blind::default(), blind: Blind::default(),
eval: fixed_evals[query_index], eval: fixed_evals[query_index],
}, },
)) ))
// We query the h(X) polynomial at x_3 // We query the h(X) polynomial at x
.chain( .chain(
h_pieces h_pieces
.iter() .iter()
.zip(h_blinds.iter()) .zip(h_blinds.iter())
.zip(h_evals.iter()) .zip(h_evals.iter())
.map(|((h_poly, h_blind), h_eval)| ProverQuery { .map(|((h_poly, h_blind), h_eval)| ProverQuery {
point: x_3, point: *x,
poly: h_poly, poly: h_poly,
blind: *h_blind, blind: *h_blind,
eval: *h_eval, eval: *h_eval,
@ -343,7 +338,7 @@ impl<C: CurveAffine> Proof<C> {
instances.chain( instances.chain(
permutations permutations
.as_ref() .as_ref()
.map(|p| p.open(pk, x_3)) .map(|p| p.open(pk, x))
.into_iter() .into_iter()
.flatten(), .flatten(),
), ),

View file

@ -1,8 +1,8 @@
use ff::Field; use ff::Field;
use std::iter; use std::iter;
use super::{Error, Proof, VerifyingKey}; use super::{ChallengeBeta, ChallengeGamma, ChallengeX, ChallengeY, Error, Proof, VerifyingKey};
use crate::arithmetic::{get_challenge_scalar, Challenge, CurveAffine, FieldExt}; use crate::arithmetic::{CurveAffine, FieldExt};
use crate::poly::{ use crate::poly::{
commitment::{Guard, Params, MSM}, commitment::{Guard, Params, MSM},
multiopen::VerifierQuery, multiopen::VerifierQuery,
@ -45,19 +45,19 @@ impl<'a, C: CurveAffine> Proof<C> {
.map_err(|_| Error::TranscriptError)?; .map_err(|_| Error::TranscriptError)?;
} }
// Sample x_0 challenge // Sample beta challenge
let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let beta = ChallengeBeta::get(&mut transcript);
// Sample x_1 challenge // Sample gamma challenge
let x_1: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let gamma = ChallengeGamma::get(&mut transcript);
// Hash each permutation product commitment // Hash each permutation product commitment
if let Some(p) = &self.permutations { if let Some(p) = &self.permutations {
p.absorb_commitments(&mut transcript)?; p.absorb_commitments(&mut transcript)?;
} }
// Sample x_2 challenge, which keeps the gates linearly independent. // Sample y challenge, which keeps the gates linearly independent.
let x_2: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let y = ChallengeY::get(&mut transcript);
// Obtain a commitment to h(X) in the form of multiple pieces of degree n - 1 // Obtain a commitment to h(X) in the form of multiple pieces of degree n - 1
for c in &self.h_commitments { for c in &self.h_commitments {
@ -66,13 +66,13 @@ impl<'a, C: CurveAffine> Proof<C> {
.map_err(|_| Error::TranscriptError)?; .map_err(|_| Error::TranscriptError)?;
} }
// Sample x_3 challenge, which is used to ensure the circuit is // Sample x 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 = ChallengeX::get(&mut transcript);
// This check ensures the circuit is satisfied so long as the polynomial // This check ensures the circuit is satisfied so long as the polynomial
// commitments open to the correct values. // commitments open to the correct values.
self.check_hx(params, vk, x_0, x_1, x_2, x_3)?; self.check_hx(params, vk, beta, gamma, y, x)?;
for eval in self for eval in self
.advice_evals .advice_evals
@ -95,7 +95,7 @@ impl<'a, C: CurveAffine> Proof<C> {
iter::empty() iter::empty()
.chain(vk.cs.advice_queries.iter().enumerate().map( .chain(vk.cs.advice_queries.iter().enumerate().map(
|(query_index, &(column, at))| VerifierQuery { |(query_index, &(column, at))| VerifierQuery {
point: vk.domain.rotate_omega(x_3, at), point: vk.domain.rotate_omega(*x, at),
commitment: &self.advice_commitments[column.index()], commitment: &self.advice_commitments[column.index()],
eval: self.advice_evals[query_index], eval: self.advice_evals[query_index],
}, },
@ -106,14 +106,14 @@ impl<'a, C: CurveAffine> Proof<C> {
.iter() .iter()
.enumerate() .enumerate()
.map(|(query_index, &(column, at))| VerifierQuery { .map(|(query_index, &(column, at))| VerifierQuery {
point: vk.domain.rotate_omega(x_3, at), point: vk.domain.rotate_omega(*x, at),
commitment: &aux_commitments[column.index()], commitment: &aux_commitments[column.index()],
eval: self.aux_evals[query_index], eval: self.aux_evals[query_index],
}), }),
) )
.chain(vk.cs.fixed_queries.iter().enumerate().map( .chain(vk.cs.fixed_queries.iter().enumerate().map(
|(query_index, &(column, at))| VerifierQuery { |(query_index, &(column, at))| VerifierQuery {
point: vk.domain.rotate_omega(x_3, at), point: vk.domain.rotate_omega(*x, at),
commitment: &vk.fixed_commitments[column.index()], commitment: &vk.fixed_commitments[column.index()],
eval: self.fixed_evals[query_index], eval: self.fixed_evals[query_index],
}, },
@ -124,7 +124,7 @@ impl<'a, C: CurveAffine> Proof<C> {
.enumerate() .enumerate()
.zip(self.h_evals.iter()) .zip(self.h_evals.iter())
.map(|((idx, _), &eval)| VerifierQuery { .map(|((idx, _), &eval)| VerifierQuery {
point: x_3, point: *x,
commitment: &self.h_commitments[idx], commitment: &self.h_commitments[idx],
eval, eval,
}), }),
@ -139,7 +139,7 @@ impl<'a, C: CurveAffine> Proof<C> {
queries.chain( queries.chain(
self.permutations self.permutations
.as_ref() .as_ref()
.map(|p| p.queries(vk, x_3)) .map(|p| p.queries(vk, x))
.into_iter() .into_iter()
.flatten(), .flatten(),
), ),
@ -189,21 +189,21 @@ impl<'a, C: CurveAffine> Proof<C> {
&self, &self,
params: &'a Params<C>, params: &'a Params<C>,
vk: &VerifyingKey<C>, vk: &VerifyingKey<C>,
x_0: C::Scalar, beta: ChallengeBeta<C::Scalar>,
x_1: C::Scalar, gamma: ChallengeGamma<C::Scalar>,
x_2: C::Scalar, y: ChallengeY<C::Scalar>,
x_3: C::Scalar, x: ChallengeX<C::Scalar>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// x_3^n // x^n
let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]); let xn = x.pow(&[params.n as u64, 0, 0, 0]);
// TODO: bubble this error up // TODO: bubble this error up
// l_0(x_3) // l_0(x)
let l_0 = (x_3 - &C::Scalar::one()).invert().unwrap() // 1 / (x_3 - 1) let l_0 = (*x - &C::Scalar::one()).invert().unwrap() // 1 / (x - 1)
* &(x_3n - &C::Scalar::one()) // (x_3^n - 1) / (x_3 - 1) * &(xn - &C::Scalar::one()) // (x^n - 1) / (x - 1)
* &vk.domain.get_barycentric_weight(); // l_0(x_3) * &vk.domain.get_barycentric_weight(); // l_0(x)
// Compute the expected value of h(x_3) // Compute the expected value of h(x)
let expected_h_eval = std::iter::empty() let expected_h_eval = std::iter::empty()
// Evaluate the circuit using the custom gates provided // Evaluate the circuit using the custom gates provided
.chain(vk.cs.gates.iter().map(|poly| { .chain(vk.cs.gates.iter().map(|poly| {
@ -219,21 +219,21 @@ impl<'a, C: CurveAffine> Proof<C> {
.chain( .chain(
self.permutations self.permutations
.as_ref() .as_ref()
.map(|p| p.expressions(vk, &self.advice_evals, l_0, x_0, x_1, x_3)) .map(|p| p.expressions(vk, &self.advice_evals, l_0, beta, gamma, x))
.into_iter() .into_iter()
.flatten(), .flatten(),
) )
.fold(C::Scalar::zero(), |h_eval, v| h_eval * &x_2 + &v); .fold(C::Scalar::zero(), |h_eval, v| h_eval * &y + &v);
// Compute h(x_3) from the prover // Compute h(x) from the prover
let h_eval = self let h_eval = self
.h_evals .h_evals
.iter() .iter()
.rev() .rev()
.fold(C::Scalar::zero(), |acc, eval| acc * &x_3n + eval); .fold(C::Scalar::zero(), |acc, eval| acc * &xn + eval);
// Did the prover commit to the correct polynomial? // Did the prover commit to the correct polynomial?
if expected_h_eval != (h_eval * &(x_3n - &C::Scalar::one())) { if expected_h_eval != (h_eval * &(xn - &C::Scalar::one())) {
return Err(Error::ConstraintSystemFailure); return Err(Error::ConstraintSystemFailure);
} }

View file

@ -5,10 +5,11 @@
use super::{Coeff, LagrangeCoeff, Polynomial}; use super::{Coeff, LagrangeCoeff, Polynomial};
use crate::arithmetic::{best_fft, best_multiexp, parallelize, Curve, CurveAffine, FieldExt}; use crate::arithmetic::{best_fft, best_multiexp, parallelize, Curve, CurveAffine, FieldExt};
use crate::transcript::Hasher; use crate::transcript::{Hasher, Transcript};
use ff::{Field, PrimeField}; use ff::{Field, PrimeField};
use std::ops::{Add, AddAssign, Mul, MulAssign}; use std::marker::PhantomData;
use std::ops::{Add, AddAssign, Deref, Mul, MulAssign};
mod msm; mod msm;
mod prover; mod prover;
@ -17,6 +18,78 @@ mod verifier;
pub use msm::MSM; pub use msm::MSM;
pub use verifier::{Accumulator, Guard}; pub use verifier::{Accumulator, Guard};
/// This is a 128-bit verifier challenge.
#[derive(Copy, Clone, Debug)]
pub struct Challenge(pub(crate) u128);
impl Challenge {
/// Obtains a new challenge from the transcript.
pub fn get<C, HBase, HScalar>(transcript: &mut Transcript<C, HBase, HScalar>) -> Challenge
where
C: CurveAffine,
HBase: Hasher<C::Base>,
HScalar: Hasher<C::Scalar>,
{
Challenge(transcript.squeeze().get_lower_128())
}
}
/// The scalar representation of a verifier challenge.
///
/// The `T` type can be used to scope the challenge to a specific context, or set to `()`
/// if no context is required.
#[derive(Copy, Clone, Debug)]
pub struct ChallengeScalar<F: FieldExt, T> {
inner: F,
_marker: PhantomData<T>,
}
impl<F: FieldExt, T> From<Challenge> for ChallengeScalar<F, T> {
/// This algorithm applies the mapping of Algorithm 1 from the
/// [Halo](https://eprint.iacr.org/2019/1021) paper.
fn from(challenge: Challenge) -> Self {
let mut acc = (F::ZETA + F::one()).double();
for i in (0..64).rev() {
let should_negate = ((challenge.0 >> ((i << 1) + 1)) & 1) == 1;
let should_endo = ((challenge.0 >> (i << 1)) & 1) == 1;
let q = if should_negate { -F::one() } else { F::one() };
let q = if should_endo { q * F::ZETA } else { q };
acc = acc + q + acc;
}
ChallengeScalar {
inner: acc,
_marker: PhantomData::default(),
}
}
}
impl<F: FieldExt, T> ChallengeScalar<F, T> {
/// Obtains a new challenge from the transcript.
pub fn get<C, HBase, HScalar>(transcript: &mut Transcript<C, HBase, HScalar>) -> Self
where
C: CurveAffine,
HBase: Hasher<C::Base>,
HScalar: Hasher<C::Scalar>,
{
Challenge::get(transcript).into()
}
}
impl<F: FieldExt, T> Deref for ChallengeScalar<F, T> {
type Target = F;
fn deref(&self) -> &F {
&self.inner
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct X6 {}
pub(crate) type ChallengeX6<F> = ChallengeScalar<F, X6>;
/// These are the public parameters for the polynomial commitment scheme. /// These are the public parameters for the polynomial commitment scheme.
#[derive(Debug)] #[derive(Debug)]
pub struct Params<C: CurveAffine> { pub struct Params<C: CurveAffine> {
@ -176,13 +249,13 @@ impl<C: CurveAffine> Params<C> {
#[derive(Copy, Clone, Eq, PartialEq, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct Blind<F>(pub F); pub struct Blind<F>(pub F);
impl<F: Field> Default for Blind<F> { impl<F: FieldExt> Default for Blind<F> {
fn default() -> Self { fn default() -> Self {
Blind(F::one()) Blind(F::one())
} }
} }
impl<F: Field> Add for Blind<F> { impl<F: FieldExt> Add for Blind<F> {
type Output = Self; type Output = Self;
fn add(self, rhs: Blind<F>) -> Self { fn add(self, rhs: Blind<F>) -> Self {
@ -190,7 +263,7 @@ impl<F: Field> Add for Blind<F> {
} }
} }
impl<F: Field> Mul for Blind<F> { impl<F: FieldExt> Mul for Blind<F> {
type Output = Self; type Output = Self;
fn mul(self, rhs: Blind<F>) -> Self { fn mul(self, rhs: Blind<F>) -> Self {
@ -198,25 +271,25 @@ impl<F: Field> Mul for Blind<F> {
} }
} }
impl<F: Field> AddAssign for Blind<F> { impl<F: FieldExt> AddAssign for Blind<F> {
fn add_assign(&mut self, rhs: Blind<F>) { fn add_assign(&mut self, rhs: Blind<F>) {
self.0 += rhs.0; self.0 += rhs.0;
} }
} }
impl<F: Field> MulAssign for Blind<F> { impl<F: FieldExt> MulAssign for Blind<F> {
fn mul_assign(&mut self, rhs: Blind<F>) { fn mul_assign(&mut self, rhs: Blind<F>) {
self.0 *= rhs.0; self.0 *= rhs.0;
} }
} }
impl<F: Field> AddAssign<F> for Blind<F> { impl<F: FieldExt> AddAssign<F> for Blind<F> {
fn add_assign(&mut self, rhs: F) { fn add_assign(&mut self, rhs: F) {
self.0 += rhs; self.0 += rhs;
} }
} }
impl<F: Field> MulAssign<F> for Blind<F> { impl<F: FieldExt> MulAssign<F> for Blind<F> {
fn mul_assign(&mut self, rhs: F) { fn mul_assign(&mut self, rhs: F) {
self.0 *= rhs; self.0 *= rhs;
} }
@ -254,9 +327,7 @@ fn test_opening_proof() {
commitment::{Blind, Params}, commitment::{Blind, Params},
EvaluationDomain, EvaluationDomain,
}; };
use crate::arithmetic::{ use crate::arithmetic::{eval_polynomial, Curve, FieldExt};
eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, FieldExt,
};
use crate::transcript::{DummyHash, Transcript}; use crate::transcript::{DummyHash, Transcript};
use crate::tweedle::{EpAffine, Fp, Fq}; use crate::tweedle::{EpAffine, Fp, Fq};
@ -275,10 +346,9 @@ fn test_opening_proof() {
let mut transcript = Transcript::<_, DummyHash<_>, DummyHash<_>>::new(); let mut transcript = Transcript::<_, DummyHash<_>, DummyHash<_>>::new();
transcript.absorb_point(&p).unwrap(); transcript.absorb_point(&p).unwrap();
let x_packed = transcript.squeeze().get_lower_128(); let x = ChallengeX6::get(&mut transcript);
let x: Fq = get_challenge_scalar(Challenge(x_packed));
// Evaluate the polynomial // Evaluate the polynomial
let v = eval_polynomial(&px, x); let v = eval_polynomial(&px, *x);
transcript.absorb_base(Fp::from_bytes(&v.to_bytes()).unwrap()); // unlikely to fail since p ~ q transcript.absorb_base(Fp::from_bytes(&v.to_bytes()).unwrap()); // unlikely to fail since p ~ q

View file

@ -1,10 +1,9 @@
use ff::Field; use ff::Field;
use super::super::{Coeff, Error, Polynomial}; use super::super::{Coeff, Error, Polynomial};
use super::{Blind, Params, Proof}; use super::{Blind, Challenge, ChallengeScalar, ChallengeX6, Params, Proof};
use crate::arithmetic::{ use crate::arithmetic::{
best_multiexp, compute_inner_product, get_challenge_scalar, parallelize, small_multiexp, best_multiexp, compute_inner_product, parallelize, small_multiexp, Curve, CurveAffine, FieldExt,
Challenge, Curve, CurveAffine, FieldExt,
}; };
use crate::transcript::{Hasher, Transcript}; use crate::transcript::{Hasher, Transcript};
@ -22,12 +21,12 @@ impl<C: CurveAffine> Proof<C> {
/// opening v, and the point x. It's probably also nice for the transcript /// opening v, and the point x. It's probably also nice for the transcript
/// to have seen the elliptic curve description and the SRS, if you want to /// to have seen the elliptic curve description and the SRS, if you want to
/// be rigorous. /// be rigorous.
pub fn create<HBase, HScalar>( pub(crate) fn create<HBase, HScalar>(
params: &Params<C>, params: &Params<C>,
transcript: &mut Transcript<C, HBase, HScalar>, transcript: &mut Transcript<C, HBase, HScalar>,
px: &Polynomial<C::Scalar, Coeff>, px: &Polynomial<C::Scalar, Coeff>,
blind: Blind<C::Scalar>, blind: Blind<C::Scalar>,
x: C::Scalar, x: ChallengeX6<C::Scalar>,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
HBase: Hasher<C::Base>, HBase: Hasher<C::Base>,
@ -108,8 +107,8 @@ impl<C: CurveAffine> Proof<C> {
.map_err(|_| Error::SamplingError)?; .map_err(|_| Error::SamplingError)?;
// ... and get the squared challenge. // ... and get the squared challenge.
let challenge_sq_packed = transcript.squeeze().get_lower_128(); let challenge_sq_packed = Challenge::get(&mut transcript);
let challenge_sq: C::Scalar = get_challenge_scalar(Challenge(challenge_sq_packed)); let challenge_sq: C::Scalar = *ChallengeScalar::<_, ()>::from(challenge_sq_packed);
// There might be no square root, in which case we'll fork the // There might be no square root, in which case we'll fork the
// transcript. // transcript.
@ -139,9 +138,8 @@ impl<C: CurveAffine> Proof<C> {
// And obtain the challenge, even though we already have it, since // And obtain the challenge, even though we already have it, since
// squeezing affects the transcript. // squeezing affects the transcript.
{ {
let challenge_sq_packed = transcript.squeeze().get_lower_128(); let challenge_sq_expected = ChallengeScalar::<_, ()>::get(transcript);
let challenge_sq_expected = get_challenge_scalar(Challenge(challenge_sq_packed)); assert_eq!(challenge_sq, *challenge_sq_expected);
assert_eq!(challenge_sq, challenge_sq_expected);
} }
// Done with this round. // Done with this round.
@ -186,12 +184,11 @@ impl<C: CurveAffine> Proof<C> {
.map_err(|_| Error::SamplingError)?; .map_err(|_| Error::SamplingError)?;
// Obtain the challenge c. // Obtain the challenge c.
let c_packed = transcript.squeeze().get_lower_128(); let c = ChallengeScalar::<_, ()>::get(transcript);
let c: C::Scalar = get_challenge_scalar(Challenge(c_packed));
// Compute z1 and z2 as described in the Halo paper. // Compute z1 and z2 as described in the Halo paper.
let z1 = a * &c + &d; let z1 = a * &c + &d;
let z2 = c * &blind + &s; let z2 = *c * &blind + &s;
Ok(Proof { Ok(Proof {
rounds, rounds,

View file

@ -1,12 +1,10 @@
use ff::Field; use ff::Field;
use super::super::Error; use super::super::Error;
use super::{Params, Proof, MSM}; use super::{Challenge, ChallengeScalar, ChallengeX6, Params, Proof, MSM};
use crate::transcript::{Hasher, Transcript}; use crate::transcript::{Hasher, Transcript};
use crate::arithmetic::{ use crate::arithmetic::{best_multiexp, Curve, CurveAffine, FieldExt};
best_multiexp, get_challenge_scalar, Challenge, Curve, CurveAffine, FieldExt,
};
/// A guard returned by the verifier /// A guard returned by the verifier
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -68,12 +66,12 @@ impl<C: CurveAffine> Proof<C> {
/// Checks to see if an [`Proof`] is valid given the current `transcript`, /// Checks to see if an [`Proof`] is valid given the current `transcript`,
/// and a point `x` that the polynomial commitment `p` opens purportedly to /// and a point `x` that the polynomial commitment `p` opens purportedly to
/// the value `v`. /// the value `v`.
pub fn verify<'a, HBase, HScalar>( pub(crate) fn verify<'a, HBase, HScalar>(
&self, &self,
params: &'a Params<C>, params: &'a Params<C>,
mut msm: MSM<'a, C>, mut msm: MSM<'a, C>,
transcript: &mut Transcript<C, HBase, HScalar>, transcript: &mut Transcript<C, HBase, HScalar>,
x: C::Scalar, x: ChallengeX6<C::Scalar>,
mut commitment_msm: MSM<'a, C>, mut commitment_msm: MSM<'a, C>,
v: C::Scalar, v: C::Scalar,
) -> Result<Guard<'a, C>, Error> ) -> Result<Guard<'a, C>, Error>
@ -120,8 +118,8 @@ impl<C: CurveAffine> Proof<C> {
transcript transcript
.absorb_point(&r) .absorb_point(&r)
.map_err(|_| Error::OpeningError)?; .map_err(|_| Error::OpeningError)?;
let challenge_sq_packed = transcript.squeeze().get_lower_128(); let challenge_sq_packed = Challenge::get(transcript);
let challenge_sq: C::Scalar = get_challenge_scalar(Challenge(challenge_sq_packed)); let challenge_sq: C::Scalar = *ChallengeScalar::<_, ()>::from(challenge_sq_packed);
let challenge = challenge_sq.deterministic_sqrt(); let challenge = challenge_sq.deterministic_sqrt();
if challenge.is_none() { if challenge.is_none() {
@ -149,7 +147,7 @@ impl<C: CurveAffine> Proof<C> {
challenges.push(challenge); challenges.push(challenge);
challenges_inv.push(challenge_inv); challenges_inv.push(challenge_inv);
challenges_sq.push(challenge_sq); challenges_sq.push(challenge_sq);
challenges_sq_packed.push(Challenge(challenge_sq_packed)); challenges_sq_packed.push(challenge_sq_packed);
} }
// Feed delta into the transcript // Feed delta into the transcript
@ -158,8 +156,7 @@ impl<C: CurveAffine> Proof<C> {
.map_err(|_| Error::OpeningError)?; .map_err(|_| Error::OpeningError)?;
// Get the challenge `c` // Get the challenge `c`
let c_packed = transcript.squeeze().get_lower_128(); let c = ChallengeScalar::<_, ()>::get(transcript);
let c: C::Scalar = get_challenge_scalar(Challenge(c_packed));
// Construct // Construct
// [c] P + [c * v] U + [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2) + delta - [z1 * b] U + [z1 - z2] H // [c] P + [c * v] U + [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2) + delta - [z1 * b] U + [z1 - z2] H
@ -167,17 +164,17 @@ impl<C: CurveAffine> Proof<C> {
// The computation of [z1] (G + H) happens in either Guard::use_challenges() // The computation of [z1] (G + H) happens in either Guard::use_challenges()
// or Guard::use_g(). // or Guard::use_g().
let b = compute_b(x, &challenges, &challenges_inv); let b = compute_b(*x, &challenges, &challenges_inv);
let neg_z1 = -self.z1; let neg_z1 = -self.z1;
// [c] P // [c] P
commitment_msm.scale(c); commitment_msm.scale(*c);
msm.add_msm(&commitment_msm); msm.add_msm(&commitment_msm);
// [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2) // [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2)
for scalar in &mut extra_scalars { for scalar in &mut extra_scalars {
*scalar *= &c; *scalar *= &(*c);
} }
for (scalar, base) in extra_scalars.iter().zip(extra_bases.iter()) { for (scalar, base) in extra_scalars.iter().zip(extra_bases.iter()) {
@ -185,7 +182,7 @@ impl<C: CurveAffine> Proof<C> {
} }
// [c * v] U - [z1 * b] U // [c * v] U - [z1 * b] U
msm.append_term((c * &v) + &(neg_z1 * &b), u); msm.append_term((*c * &v) + &(neg_z1 * &b), u);
// delta // delta
msm.append_term(Field::one(), self.delta); msm.append_term(Field::one(), self.delta);

View file

@ -1,12 +1,11 @@
use super::super::{ use super::super::{
commitment::{self, Blind, Params}, commitment::{self, Blind, ChallengeScalar, ChallengeX6, Params},
Coeff, Error, Polynomial, Coeff, Error, Polynomial,
}; };
use super::{construct_intermediate_sets, Proof, ProverQuery, Query}; use super::{construct_intermediate_sets, Proof, ProverQuery, Query};
use crate::arithmetic::{ use crate::arithmetic::{
eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve, eval_polynomial, kate_division, lagrange_interpolate, Curve, CurveAffine, FieldExt,
CurveAffine, FieldExt,
}; };
use crate::transcript::{Hasher, Transcript}; use crate::transcript::{Hasher, Transcript};
@ -31,8 +30,8 @@ impl<C: CurveAffine> Proof<C> {
where where
I: IntoIterator<Item = ProverQuery<'a, C>> + Clone, I: IntoIterator<Item = ProverQuery<'a, C>> + Clone,
{ {
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x_4 = ChallengeScalar::<_, ()>::get(transcript);
let x_5: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x_5 = ChallengeScalar::<_, ()>::get(transcript);
let (poly_map, point_sets) = construct_intermediate_sets(queries); let (poly_map, point_sets) = construct_intermediate_sets(queries);
@ -54,11 +53,11 @@ impl<C: CurveAffine> Proof<C> {
blind: Blind<C::Scalar>, blind: Blind<C::Scalar>,
evals: Vec<C::Scalar>| { evals: Vec<C::Scalar>| {
if let Some(poly) = &q_polys[set_idx] { if let Some(poly) = &q_polys[set_idx] {
q_polys[set_idx] = Some(poly.clone() * x_4 + new_poly); q_polys[set_idx] = Some(poly.clone() * *x_4 + new_poly);
} else { } else {
q_polys[set_idx] = Some(new_poly.clone()); q_polys[set_idx] = Some(new_poly.clone());
} }
q_blinds[set_idx] *= x_4; q_blinds[set_idx] *= *x_4;
q_blinds[set_idx] += blind; q_blinds[set_idx] += blind;
// Each polynomial is evaluated at a set of points. For each set, // Each polynomial is evaluated at a set of points. For each set,
// we collapse each polynomial's evals pointwise. // we collapse each polynomial's evals pointwise.
@ -100,7 +99,7 @@ impl<C: CurveAffine> Proof<C> {
if f_poly.is_none() { if f_poly.is_none() {
Some(poly) Some(poly)
} else { } else {
f_poly.map(|f_poly| f_poly * x_5 + &poly) f_poly.map(|f_poly| f_poly * *x_5 + &poly)
} }
}) })
.unwrap(); .unwrap();
@ -114,26 +113,24 @@ impl<C: CurveAffine> Proof<C> {
.absorb_point(&f_commitment) .absorb_point(&f_commitment)
.map_err(|_| Error::SamplingError)?; .map_err(|_| Error::SamplingError)?;
let x_6: C::Scalar = let x_6 = ChallengeX6::get(&mut transcript);
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
let q_evals: Vec<C::Scalar> = q_polys let q_evals: Vec<C::Scalar> = q_polys
.iter() .iter()
.map(|poly| eval_polynomial(poly.as_ref().unwrap(), x_6)) .map(|poly| eval_polynomial(poly.as_ref().unwrap(), *x_6))
.collect(); .collect();
for eval in q_evals.iter() { for eval in q_evals.iter() {
transcript.absorb_scalar(*eval); transcript.absorb_scalar(*eval);
} }
let x_7: C::Scalar = let x_7 = ChallengeScalar::<_, ()>::get(&mut transcript);
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
let (f_poly, f_blind_try) = q_polys.iter().zip(q_blinds.iter()).fold( let (f_poly, f_blind_try) = q_polys.iter().zip(q_blinds.iter()).fold(
(f_poly.clone(), f_blind), (f_poly.clone(), f_blind),
|(f_poly, f_blind), (poly, blind)| { |(f_poly, f_blind), (poly, blind)| {
( (
f_poly * x_7 + poly.as_ref().unwrap(), f_poly * *x_7 + poly.as_ref().unwrap(),
Blind((f_blind.0 * &x_7) + &blind.0), Blind((f_blind.0 * &x_7) + &blind.0),
) )
}, },

View file

@ -1,13 +1,11 @@
use ff::Field; use ff::Field;
use super::super::{ use super::super::{
commitment::{Guard, Params, MSM}, commitment::{ChallengeScalar, ChallengeX6, Guard, Params, MSM},
Error, Error,
}; };
use super::{construct_intermediate_sets, Proof, Query, VerifierQuery}; use super::{construct_intermediate_sets, Proof, Query, VerifierQuery};
use crate::arithmetic::{ use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt};
eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, FieldExt,
};
use crate::transcript::{Hasher, Transcript}; use crate::transcript::{Hasher, Transcript};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -35,15 +33,15 @@ impl<C: CurveAffine> Proof<C> {
msm.scale(C::Scalar::rand()); msm.scale(C::Scalar::rand());
// Sample x_4 for compressing openings at the same point sets together // Sample x_4 for compressing openings at the same point sets together
let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x_4 = ChallengeScalar::<_, ()>::get(transcript);
// Sample a challenge x_5 for keeping the multi-point quotient // Sample a challenge x_5 for keeping the multi-point quotient
// polynomial terms linearly independent. // polynomial terms linearly independent.
let x_5: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x_5 = ChallengeScalar::<_, ()>::get(transcript);
let (commitment_map, point_sets) = construct_intermediate_sets(queries); let (commitment_map, point_sets) = construct_intermediate_sets(queries);
// Compress the commitments and expected evaluations at x_3 together. // Compress the commitments and expected evaluations at x together.
// using the challenge x_4 // using the challenge x_4
let mut q_commitments: Vec<_> = vec![params.empty_msm(); point_sets.len()]; let mut q_commitments: Vec<_> = vec![params.empty_msm(); point_sets.len()];
@ -55,7 +53,7 @@ impl<C: CurveAffine> Proof<C> {
} }
{ {
let mut accumulate = |set_idx: usize, new_commitment, evals: Vec<C::Scalar>| { let mut accumulate = |set_idx: usize, new_commitment, evals: Vec<C::Scalar>| {
q_commitments[set_idx].scale(x_4); q_commitments[set_idx].scale(*x_4);
q_commitments[set_idx].append_term(C::Scalar::one(), new_commitment); q_commitments[set_idx].append_term(C::Scalar::one(), new_commitment);
for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) { for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) {
*set_eval *= &x_4; *set_eval *= &x_4;
@ -81,7 +79,7 @@ impl<C: CurveAffine> Proof<C> {
// Sample a challenge x_6 for checking that f(X) was committed to // Sample a challenge x_6 for checking that f(X) was committed to
// correctly. // correctly.
let x_6: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x_6 = ChallengeX6::get(transcript);
for eval in self.q_evals.iter() { for eval in self.q_evals.iter() {
transcript.absorb_scalar(*eval); transcript.absorb_scalar(*eval);
@ -97,9 +95,9 @@ impl<C: CurveAffine> Proof<C> {
C::Scalar::zero(), C::Scalar::zero(),
|msm_eval, ((points, evals), proof_eval)| { |msm_eval, ((points, evals), proof_eval)| {
let r_poly = lagrange_interpolate(points, evals); let r_poly = lagrange_interpolate(points, evals);
let r_eval = eval_polynomial(&r_poly, x_6); let r_eval = eval_polynomial(&r_poly, *x_6);
let eval = points.iter().fold(*proof_eval - &r_eval, |eval, point| { let eval = points.iter().fold(*proof_eval - &r_eval, |eval, point| {
eval * &(x_6 - point).invert().unwrap() eval * &(*x_6 - point).invert().unwrap()
}); });
msm_eval * &x_5 + &eval msm_eval * &x_5 + &eval
}, },
@ -107,7 +105,7 @@ impl<C: CurveAffine> Proof<C> {
// Sample a challenge x_7 that we will use to collapse the openings of // Sample a challenge x_7 that we will use to collapse the openings of
// the various remaining polynomials at x_6 together. // the various remaining polynomials at x_6 together.
let x_7: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); let x_7 = ChallengeScalar::<_, ()>::get(transcript);
// Compute the final commitment that has to be opened // Compute the final commitment that has to be opened
let mut commitment_msm = params.empty_msm(); let mut commitment_msm = params.empty_msm();
@ -115,7 +113,7 @@ impl<C: CurveAffine> Proof<C> {
let (commitment_msm, msm_eval) = q_commitments.into_iter().zip(self.q_evals.iter()).fold( let (commitment_msm, msm_eval) = q_commitments.into_iter().zip(self.q_evals.iter()).fold(
(commitment_msm, msm_eval), (commitment_msm, msm_eval),
|(mut commitment_msm, msm_eval), (q_commitment, q_eval)| { |(mut commitment_msm, msm_eval), (q_commitment, q_eval)| {
commitment_msm.scale(x_7); commitment_msm.scale(*x_7);
commitment_msm.add_msm(&q_commitment); commitment_msm.add_msm(&q_commitment);
(commitment_msm, msm_eval * &x_7 + q_eval) (commitment_msm, msm_eval * &x_7 + q_eval)
}, },