mirror of https://github.com/zcash/halo2.git
Make Transcript generic over curve points
Co-authored-by: Jack Grigg <jack@electriccoin.co>
This commit is contained in:
parent
1e8769b738
commit
43337dea1b
18
src/plonk.rs
18
src/plonk.rs
|
@ -9,7 +9,6 @@ use crate::arithmetic::CurveAffine;
|
||||||
use crate::poly::{
|
use crate::poly::{
|
||||||
multiopen, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial,
|
multiopen, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial,
|
||||||
};
|
};
|
||||||
use crate::transcript::Hasher;
|
|
||||||
|
|
||||||
mod circuit;
|
mod circuit;
|
||||||
mod keygen;
|
mod keygen;
|
||||||
|
@ -78,6 +77,8 @@ pub enum Error {
|
||||||
BoundsFailure,
|
BoundsFailure,
|
||||||
/// Opening error
|
/// Opening error
|
||||||
OpeningError,
|
OpeningError,
|
||||||
|
/// Transcript error
|
||||||
|
TranscriptError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveAffine> ProvingKey<C> {
|
impl<C: CurveAffine> ProvingKey<C> {
|
||||||
|
@ -94,21 +95,6 @@ impl<C: CurveAffine> VerifyingKey<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hash a point into transcript
|
|
||||||
pub fn hash_point<C: CurveAffine, H: Hasher<C::Base>>(
|
|
||||||
transcript: &mut H,
|
|
||||||
point: &C,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let tmp = point.get_xy();
|
|
||||||
if bool::from(tmp.is_none()) {
|
|
||||||
return Err(Error::SynthesisError);
|
|
||||||
};
|
|
||||||
let tmp = tmp.unwrap();
|
|
||||||
transcript.absorb(tmp.0);
|
|
||||||
transcript.absorb(tmp.1);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_proving() {
|
fn test_proving() {
|
||||||
use crate::arithmetic::{Curve, Field};
|
use crate::arithmetic::{Curve, Field};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{
|
use super::{
|
||||||
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
|
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
|
||||||
hash_point, Error, Proof, ProvingKey,
|
Error, Proof, ProvingKey,
|
||||||
};
|
};
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{
|
||||||
eval_polynomial, get_challenge_scalar, parallelize, BatchInvert, Challenge, Curve, CurveAffine,
|
eval_polynomial, get_challenge_scalar, parallelize, BatchInvert, Challenge, Curve, CurveAffine,
|
||||||
|
@ -11,7 +11,7 @@ use crate::poly::{
|
||||||
multiopen::{self, ProverQuery},
|
multiopen::{self, ProverQuery},
|
||||||
LagrangeCoeff, Polynomial, Rotation,
|
LagrangeCoeff, Polynomial, Rotation,
|
||||||
};
|
};
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::{Hasher, Transcript};
|
||||||
|
|
||||||
impl<C: CurveAffine> Proof<C> {
|
impl<C: CurveAffine> Proof<C> {
|
||||||
/// This creates a proof for the provided `circuit` when given the public
|
/// This creates a proof for the provided `circuit` when given the public
|
||||||
|
@ -92,7 +92,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let witness = witness;
|
let witness = witness;
|
||||||
|
|
||||||
// Create a transcript for obtaining Fiat-Shamir challenges.
|
// Create a transcript for obtaining Fiat-Shamir challenges.
|
||||||
let mut transcript = HBase::init(C::Base::one());
|
let mut transcript = Transcript::<C, HBase, HScalar>::new();
|
||||||
|
|
||||||
// Compute commitments to aux column polynomials
|
// Compute commitments to aux column polynomials
|
||||||
let aux_commitments_projective: Vec<_> = aux
|
let aux_commitments_projective: Vec<_> = aux
|
||||||
|
@ -105,7 +105,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
drop(aux_commitments_projective);
|
drop(aux_commitments_projective);
|
||||||
|
|
||||||
for commitment in &aux_commitments {
|
for commitment in &aux_commitments {
|
||||||
hash_point(&mut transcript, commitment)?;
|
transcript.absorb_point(commitment).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let aux_polys: Vec<_> = aux
|
let aux_polys: Vec<_> = aux
|
||||||
|
@ -143,7 +143,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
drop(advice_commitments_projective);
|
drop(advice_commitments_projective);
|
||||||
|
|
||||||
for commitment in &advice_commitments {
|
for commitment in &advice_commitments {
|
||||||
hash_point(&mut transcript, commitment)?;
|
transcript.absorb_point(commitment).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let advice_polys: Vec<_> = witness
|
let advice_polys: Vec<_> = witness
|
||||||
|
@ -277,7 +277,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
// Hash each permutation product commitment
|
// Hash each permutation product commitment
|
||||||
for c in &permutation_product_commitments {
|
for c in &permutation_product_commitments {
|
||||||
hash_point(&mut transcript, c)?;
|
transcript.absorb_point(c).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain challenge for keeping all separate gates linearly independent
|
// Obtain challenge for keeping all separate gates linearly independent
|
||||||
|
@ -385,7 +385,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
// Hash each h(X) piece
|
// Hash each h(X) piece
|
||||||
for c in h_commitments.iter() {
|
for c in h_commitments.iter() {
|
||||||
hash_point(&mut transcript, c)?;
|
transcript.absorb_point(c).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
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()));
|
||||||
|
@ -444,10 +444,6 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
.map(|poly| eval_polynomial(poly, x_3))
|
.map(|poly| eval_polynomial(poly, x_3))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// We set up a second transcript on the scalar field to hash in openings of
|
|
||||||
// our polynomial commitments.
|
|
||||||
let mut transcript_scalar = HScalar::init(C::Scalar::one());
|
|
||||||
|
|
||||||
// Hash each advice evaluation
|
// Hash each advice evaluation
|
||||||
for eval in advice_evals
|
for eval in advice_evals
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -458,13 +454,9 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
.chain(permutation_product_inv_evals.iter())
|
.chain(permutation_product_inv_evals.iter())
|
||||||
.chain(permutation_evals.iter().flat_map(|evals| evals.iter()))
|
.chain(permutation_evals.iter().flat_map(|evals| evals.iter()))
|
||||||
{
|
{
|
||||||
transcript_scalar.absorb(*eval);
|
transcript.absorb_scalar(*eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transcript_scalar_point =
|
|
||||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
|
||||||
transcript.absorb(transcript_scalar_point);
|
|
||||||
|
|
||||||
let mut instances: Vec<ProverQuery<C>> = Vec::new();
|
let mut instances: Vec<ProverQuery<C>> = Vec::new();
|
||||||
|
|
||||||
for (query_index, &(column, at)) in pk.vk.cs.advice_queries.iter().enumerate() {
|
for (query_index, &(column, at)) in pk.vk.cs.advice_queries.iter().enumerate() {
|
||||||
|
@ -558,9 +550,8 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let multiopening =
|
let multiopening = multiopen::Proof::create(params, &mut transcript, instances)
|
||||||
multiopen::Proof::create(params, &mut transcript, &mut transcript_scalar, instances)
|
.map_err(|_| Error::OpeningError)?;
|
||||||
.map_err(|_| Error::OpeningError)?;
|
|
||||||
|
|
||||||
Ok(Proof {
|
Ok(Proof {
|
||||||
advice_commitments,
|
advice_commitments,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use super::{hash_point, Error, Proof, VerifyingKey};
|
use super::{Error, Proof, VerifyingKey};
|
||||||
use crate::arithmetic::{get_challenge_scalar, Challenge, CurveAffine, Field};
|
use crate::arithmetic::{get_challenge_scalar, Challenge, CurveAffine, Field};
|
||||||
use crate::poly::{
|
use crate::poly::{
|
||||||
commitment::{Guard, Params, MSM},
|
commitment::{Guard, Params, MSM},
|
||||||
multiopen::VerifierQuery,
|
multiopen::VerifierQuery,
|
||||||
Rotation,
|
Rotation,
|
||||||
};
|
};
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::{Hasher, Transcript};
|
||||||
|
|
||||||
impl<'a, C: CurveAffine> Proof<C> {
|
impl<'a, C: CurveAffine> Proof<C> {
|
||||||
/// Returns a boolean indicating whether or not the proof is valid
|
/// Returns a boolean indicating whether or not the proof is valid
|
||||||
|
@ -27,16 +27,16 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a transcript for obtaining Fiat-Shamir challenges.
|
// Create a transcript for obtaining Fiat-Shamir challenges.
|
||||||
let mut transcript = HBase::init(C::Base::one());
|
let mut transcript = Transcript::<C, HBase, HScalar>::new();
|
||||||
|
|
||||||
// Hash the aux (external) commitments into the transcript
|
// Hash the aux (external) commitments into the transcript
|
||||||
for commitment in aux_commitments {
|
for commitment in aux_commitments {
|
||||||
hash_point(&mut transcript, commitment)?;
|
transcript.absorb_point(commitment).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the prover's advice commitments into the transcript
|
// Hash the prover's advice commitments into the transcript
|
||||||
for commitment in &self.advice_commitments {
|
for commitment in &self.advice_commitments {
|
||||||
hash_point(&mut transcript, commitment)?;
|
transcript.absorb_point(commitment).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample x_0 challenge
|
// Sample x_0 challenge
|
||||||
|
@ -47,7 +47,7 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
// Hash each permutation product commitment
|
// Hash each permutation product commitment
|
||||||
for c in &self.permutation_product_commitments {
|
for c in &self.permutation_product_commitments {
|
||||||
hash_point(&mut transcript, c)?;
|
transcript.absorb_point(c).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample x_2 challenge, which keeps the gates linearly independent.
|
// Sample x_2 challenge, which keeps the gates linearly independent.
|
||||||
|
@ -55,7 +55,7 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
// 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 {
|
||||||
hash_point(&mut transcript, c)?;
|
transcript.absorb_point(c).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample x_3 challenge, which is used to ensure the circuit is
|
// Sample x_3 challenge, which is used to ensure the circuit is
|
||||||
|
@ -66,10 +66,6 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
// 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, x_0, x_1, x_2, x_3)?;
|
||||||
|
|
||||||
// Hash together all the openings provided by the prover into a new
|
|
||||||
// transcript on the scalar field.
|
|
||||||
let mut transcript_scalar = HScalar::init(C::Scalar::one());
|
|
||||||
|
|
||||||
for eval in self
|
for eval in self
|
||||||
.advice_evals
|
.advice_evals
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -80,13 +76,9 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
.chain(self.permutation_product_inv_evals.iter())
|
.chain(self.permutation_product_inv_evals.iter())
|
||||||
.chain(self.permutation_evals.iter().flat_map(|evals| evals.iter()))
|
.chain(self.permutation_evals.iter().flat_map(|evals| evals.iter()))
|
||||||
{
|
{
|
||||||
transcript_scalar.absorb(*eval);
|
transcript.absorb_scalar(*eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transcript_scalar_point =
|
|
||||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
|
||||||
transcript.absorb(transcript_scalar_point);
|
|
||||||
|
|
||||||
let mut queries: Vec<VerifierQuery<'a, C>> = Vec::new();
|
let mut queries: Vec<VerifierQuery<'a, C>> = Vec::new();
|
||||||
|
|
||||||
for (query_index, &(column, at)) in vk.cs.advice_queries.iter().enumerate() {
|
for (query_index, &(column, at)) in vk.cs.advice_queries.iter().enumerate() {
|
||||||
|
@ -180,13 +172,7 @@ impl<'a, C: CurveAffine> Proof<C> {
|
||||||
// We are now convinced the circuit is satisfied so long as the
|
// We are now convinced the circuit is satisfied so long as the
|
||||||
// polynomial commitments open to the correct values.
|
// polynomial commitments open to the correct values.
|
||||||
self.multiopening
|
self.multiopening
|
||||||
.verify(
|
.verify(params, &mut transcript, queries, msm)
|
||||||
params,
|
|
||||||
&mut transcript,
|
|
||||||
&mut transcript_scalar,
|
|
||||||
queries,
|
|
||||||
msm,
|
|
||||||
)
|
|
||||||
.map_err(|_| Error::OpeningError)
|
.map_err(|_| Error::OpeningError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -248,8 +248,10 @@ fn test_opening_proof() {
|
||||||
commitment::{Blind, Params},
|
commitment::{Blind, Params},
|
||||||
EvaluationDomain,
|
EvaluationDomain,
|
||||||
};
|
};
|
||||||
use crate::arithmetic::{eval_polynomial, get_challenge_scalar, Challenge, Curve, Field};
|
use crate::arithmetic::{
|
||||||
use crate::transcript::{DummyHash, Hasher};
|
eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, Field,
|
||||||
|
};
|
||||||
|
use crate::transcript::{DummyHash, Hasher, Transcript};
|
||||||
use crate::tweedle::{EpAffine, Fp, Fq};
|
use crate::tweedle::{EpAffine, Fp, Fq};
|
||||||
|
|
||||||
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
|
||||||
|
@ -265,17 +267,18 @@ fn test_opening_proof() {
|
||||||
|
|
||||||
let p = params.commit(&px, blind).to_affine();
|
let p = params.commit(&px, blind).to_affine();
|
||||||
|
|
||||||
let mut transcript = DummyHash::init(Field::one());
|
let mut hasher = DummyHash::init(Field::one());
|
||||||
let (p_x, p_y) = p.get_xy().unwrap();
|
let (p_x, p_y) = p.get_xy().unwrap();
|
||||||
transcript.absorb(p_x);
|
hasher.absorb(p_x);
|
||||||
transcript.absorb(p_y);
|
hasher.absorb(p_y);
|
||||||
let x_packed = transcript.squeeze().get_lower_128();
|
let x_packed = hasher.squeeze().get_lower_128();
|
||||||
let x: Fq = get_challenge_scalar(Challenge(x_packed));
|
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(Fp::from_bytes(&v.to_bytes()).unwrap()); // unlikely to fail since p ~ q
|
hasher.absorb(Fp::from_bytes(&v.to_bytes()).unwrap()); // unlikely to fail since p ~ q
|
||||||
|
let scalar_hasher = DummyHash::init(Fq::one());
|
||||||
|
let mut transcript = Transcript::init_with_hashers(&hasher, &scalar_hasher);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let transcript_dup = transcript.clone();
|
let transcript_dup = transcript.clone();
|
||||||
|
@ -283,7 +286,7 @@ fn test_opening_proof() {
|
||||||
let opening_proof = Proof::create(¶ms, &mut transcript, &px, blind, x);
|
let opening_proof = Proof::create(¶ms, &mut transcript, &px, blind, x);
|
||||||
if opening_proof.is_err() {
|
if opening_proof.is_err() {
|
||||||
transcript = transcript_dup;
|
transcript = transcript_dup;
|
||||||
transcript.absorb(Field::one());
|
transcript.absorb_base(Field::one());
|
||||||
} else {
|
} else {
|
||||||
let opening_proof = opening_proof.unwrap();
|
let opening_proof = opening_proof.unwrap();
|
||||||
// Verify the opening proof
|
// Verify the opening proof
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::arithmetic::{
|
||||||
best_multiexp, compute_inner_product, get_challenge_scalar, parallelize, small_multiexp,
|
best_multiexp, compute_inner_product, get_challenge_scalar, parallelize, small_multiexp,
|
||||||
Challenge, Curve, CurveAffine, Field,
|
Challenge, Curve, CurveAffine, Field,
|
||||||
};
|
};
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::{Hasher, Transcript};
|
||||||
|
|
||||||
impl<C: CurveAffine> Proof<C> {
|
impl<C: CurveAffine> Proof<C> {
|
||||||
/// Create a polynomial commitment opening proof for the polynomial defined
|
/// Create a polynomial commitment opening proof for the polynomial defined
|
||||||
|
@ -20,13 +20,17 @@ 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<H: Hasher<C::Base>>(
|
pub fn create<HBase, HScalar>(
|
||||||
params: &Params<C>,
|
params: &Params<C>,
|
||||||
transcript: &mut H,
|
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: C::Scalar,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
HBase: Hasher<C::Base>,
|
||||||
|
HScalar: Hasher<C::Scalar>,
|
||||||
|
{
|
||||||
let mut blind = blind.0;
|
let mut blind = blind.0;
|
||||||
|
|
||||||
// We're limited to polynomials of degree n - 1.
|
// We're limited to polynomials of degree n - 1.
|
||||||
|
@ -90,15 +94,10 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
// until the challenge is a square.
|
// until the challenge is a square.
|
||||||
let mut transcript = transcript.clone();
|
let mut transcript = transcript.clone();
|
||||||
|
|
||||||
|
// Feed L and R into the cloned transcript.
|
||||||
// We expect these to not be points at infinity due to the randomness.
|
// We expect these to not be points at infinity due to the randomness.
|
||||||
let (l_x, l_y) = l.get_xy().unwrap();
|
transcript.absorb_point(&l).ok();
|
||||||
let (r_x, r_y) = r.get_xy().unwrap();
|
transcript.absorb_point(&r).ok();
|
||||||
|
|
||||||
// Feed L and R into the cloned transcript...
|
|
||||||
transcript.absorb(l_x);
|
|
||||||
transcript.absorb(l_y);
|
|
||||||
transcript.absorb(r_x);
|
|
||||||
transcript.absorb(r_y);
|
|
||||||
|
|
||||||
// ... and get the squared challenge.
|
// ... and get the squared challenge.
|
||||||
let challenge_sq_packed = transcript.squeeze().get_lower_128();
|
let challenge_sq_packed = transcript.squeeze().get_lower_128();
|
||||||
|
@ -122,12 +121,8 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let challenge_sq = challenge.square();
|
let challenge_sq = challenge.square();
|
||||||
|
|
||||||
// Feed L and R into the real transcript
|
// Feed L and R into the real transcript
|
||||||
let (l_x, l_y) = l.get_xy().unwrap();
|
transcript.absorb_point(&l).ok();
|
||||||
let (r_x, r_y) = r.get_xy().unwrap();
|
transcript.absorb_point(&r).ok();
|
||||||
transcript.absorb(l_x);
|
|
||||||
transcript.absorb(l_y);
|
|
||||||
transcript.absorb(r_x);
|
|
||||||
transcript.absorb(r_y);
|
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -172,11 +167,8 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
let delta = best_multiexp(&[d, d * &b, s], &[g, u, params.h]).to_affine();
|
let delta = best_multiexp(&[d, d * &b, s], &[g, u, params.h]).to_affine();
|
||||||
|
|
||||||
let (delta_x, delta_y) = delta.get_xy().unwrap();
|
|
||||||
|
|
||||||
// Feed delta into the transcript
|
// Feed delta into the transcript
|
||||||
transcript.absorb(delta_x);
|
transcript.absorb_point(&delta).ok();
|
||||||
transcript.absorb(delta_y);
|
|
||||||
|
|
||||||
// Obtain the challenge c.
|
// Obtain the challenge c.
|
||||||
let c_packed = transcript.squeeze().get_lower_128();
|
let c_packed = transcript.squeeze().get_lower_128();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::super::Error;
|
use super::super::Error;
|
||||||
use super::{Params, Proof, MSM};
|
use super::{Params, Proof, MSM};
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::{Hasher, Transcript};
|
||||||
|
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{
|
||||||
best_multiexp, get_challenge_scalar, Challenge, Curve, CurveAffine, Field,
|
best_multiexp, get_challenge_scalar, Challenge, Curve, CurveAffine, Field,
|
||||||
|
@ -65,15 +65,19 @@ 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, H: Hasher<C::Base>>(
|
pub 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 H,
|
transcript: &mut Transcript<C, HBase, HScalar>,
|
||||||
x: C::Scalar,
|
x: 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>
|
||||||
|
where
|
||||||
|
HBase: Hasher<C::Base>,
|
||||||
|
HScalar: Hasher<C::Scalar>,
|
||||||
|
{
|
||||||
// Check for well-formedness
|
// Check for well-formedness
|
||||||
if self.rounds.len() != params.k as usize {
|
if self.rounds.len() != params.k as usize {
|
||||||
return Err(Error::OpeningError);
|
return Err(Error::OpeningError);
|
||||||
|
@ -105,17 +109,13 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
for round in &self.rounds {
|
for round in &self.rounds {
|
||||||
// Feed L and R into the transcript.
|
// Feed L and R into the transcript.
|
||||||
let l = round.0.get_xy();
|
let l = round.0;
|
||||||
let r = round.1.get_xy();
|
let r = round.1;
|
||||||
if bool::from(l.is_none() | r.is_none()) {
|
if bool::from(l.get_xy().is_none() | r.get_xy().is_none()) {
|
||||||
return Err(Error::OpeningError);
|
return Err(Error::OpeningError);
|
||||||
}
|
}
|
||||||
let l = l.unwrap();
|
transcript.absorb_point(&l).ok();
|
||||||
let r = r.unwrap();
|
transcript.absorb_point(&r).ok();
|
||||||
transcript.absorb(l.0);
|
|
||||||
transcript.absorb(l.1);
|
|
||||||
transcript.absorb(r.0);
|
|
||||||
transcript.absorb(r.1);
|
|
||||||
let challenge_sq_packed = transcript.squeeze().get_lower_128();
|
let challenge_sq_packed = transcript.squeeze().get_lower_128();
|
||||||
let challenge_sq: C::Scalar = get_challenge_scalar(Challenge(challenge_sq_packed));
|
let challenge_sq: C::Scalar = get_challenge_scalar(Challenge(challenge_sq_packed));
|
||||||
|
|
||||||
|
@ -148,15 +148,13 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
challenges_sq_packed.push(Challenge(challenge_sq_packed));
|
challenges_sq_packed.push(Challenge(challenge_sq_packed));
|
||||||
}
|
}
|
||||||
|
|
||||||
let delta = self.delta.get_xy();
|
let delta = self.delta;
|
||||||
if bool::from(delta.is_none()) {
|
if bool::from(delta.get_xy().is_none()) {
|
||||||
return Err(Error::OpeningError);
|
return Err(Error::OpeningError);
|
||||||
}
|
}
|
||||||
let delta = delta.unwrap();
|
|
||||||
|
|
||||||
// Feed delta into the transcript
|
// Feed delta into the transcript
|
||||||
transcript.absorb(delta.0);
|
transcript.absorb_point(&delta).ok();
|
||||||
transcript.absorb(delta.1);
|
|
||||||
|
|
||||||
// Get the challenge `c`
|
// Get the challenge `c`
|
||||||
let c_packed = transcript.squeeze().get_lower_128();
|
let c_packed = transcript.squeeze().get_lower_128();
|
||||||
|
|
|
@ -8,8 +8,7 @@ use crate::arithmetic::{
|
||||||
eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve,
|
eval_polynomial, get_challenge_scalar, kate_division, lagrange_interpolate, Challenge, Curve,
|
||||||
CurveAffine, Field,
|
CurveAffine, Field,
|
||||||
};
|
};
|
||||||
use crate::plonk::hash_point;
|
use crate::transcript::{Hasher, Transcript};
|
||||||
use crate::transcript::Hasher;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -24,8 +23,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
/// Create a multi-opening proof
|
/// Create a multi-opening proof
|
||||||
pub fn create<'a, I, HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
|
pub fn create<'a, I, HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
|
||||||
params: &Params<C>,
|
params: &Params<C>,
|
||||||
transcript: &mut HBase,
|
transcript: &mut Transcript<C, HBase, HScalar>,
|
||||||
transcript_scalar: &mut HScalar,
|
|
||||||
queries: I,
|
queries: I,
|
||||||
) -> Result<Self, Error>
|
) -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
|
@ -110,8 +108,9 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
let (opening, q_evals) = loop {
|
let (opening, q_evals) = loop {
|
||||||
let mut transcript = transcript.clone();
|
let mut transcript = transcript.clone();
|
||||||
let mut transcript_scalar = transcript_scalar.clone();
|
transcript
|
||||||
hash_point(&mut transcript, &f_commitment).unwrap();
|
.absorb_point(&f_commitment)
|
||||||
|
.map_err(|_| Error::SamplingError)?;
|
||||||
|
|
||||||
let x_6: C::Scalar =
|
let x_6: C::Scalar =
|
||||||
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
@ -122,13 +121,9 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for eval in q_evals.iter() {
|
for eval in q_evals.iter() {
|
||||||
transcript_scalar.absorb(*eval);
|
transcript.absorb_scalar(*eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transcript_scalar_point =
|
|
||||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
|
||||||
transcript.absorb(transcript_scalar_point);
|
|
||||||
|
|
||||||
let x_7: C::Scalar =
|
let x_7: C::Scalar =
|
||||||
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ use super::{construct_intermediate_sets, Proof, Query, VerifierQuery};
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{
|
||||||
eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, Field,
|
eval_polynomial, get_challenge_scalar, lagrange_interpolate, Challenge, CurveAffine, Field,
|
||||||
};
|
};
|
||||||
use crate::plonk::hash_point;
|
use crate::transcript::{Hasher, Transcript};
|
||||||
use crate::transcript::Hasher;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct CommitmentData<C: CurveAffine> {
|
struct CommitmentData<C: CurveAffine> {
|
||||||
|
@ -21,8 +20,7 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
pub fn verify<'a, I, HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
|
pub fn verify<'a, I, HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
|
||||||
&self,
|
&self,
|
||||||
params: &'a Params<C>,
|
params: &'a Params<C>,
|
||||||
transcript: &mut HBase,
|
transcript: &mut Transcript<C, HBase, HScalar>,
|
||||||
transcript_scalar: &mut HScalar,
|
|
||||||
queries: I,
|
queries: I,
|
||||||
mut msm: MSM<'a, C>,
|
mut msm: MSM<'a, C>,
|
||||||
) -> Result<Guard<'a, C>, Error>
|
) -> Result<Guard<'a, C>, Error>
|
||||||
|
@ -75,20 +73,18 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain the commitment to the multi-point quotient polynomial f(X).
|
// Obtain the commitment to the multi-point quotient polynomial f(X).
|
||||||
hash_point(transcript, &self.f_commitment).unwrap();
|
transcript
|
||||||
|
.absorb_point(&self.f_commitment)
|
||||||
|
.map_err(|_| Error::SamplingError)?;
|
||||||
|
|
||||||
// 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: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
|
||||||
|
|
||||||
for eval in self.q_evals.iter() {
|
for eval in self.q_evals.iter() {
|
||||||
transcript_scalar.absorb(*eval);
|
transcript.absorb_scalar(*eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
let transcript_scalar_point =
|
|
||||||
C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap();
|
|
||||||
transcript.absorb(transcript_scalar_point);
|
|
||||||
|
|
||||||
// We can compute the expected msm_eval at x_6 using the q_evals provided
|
// We can compute the expected msm_eval at x_6 using the q_evals provided
|
||||||
// by the prover and from x_5
|
// by the prover and from x_5
|
||||||
let msm_eval = point_sets
|
let msm_eval = point_sets
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
//! This module contains utilities and traits for dealing with Fiat-Shamir
|
//! This module contains utilities and traits for dealing with Fiat-Shamir
|
||||||
//! transcripts.
|
//! transcripts.
|
||||||
|
|
||||||
use crate::arithmetic::Field;
|
use crate::arithmetic::{CurveAffine, Field};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// This is a generic interface for a sponge function that can be used for
|
/// This is a generic interface for a sponge function that can be used for
|
||||||
/// Fiat-Shamir transformations.
|
/// Fiat-Shamir transformations.
|
||||||
|
@ -23,9 +24,9 @@ pub struct DummyHash<F: Field> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field> Hasher<F> for DummyHash<F> {
|
impl<F: Field> Hasher<F> for DummyHash<F> {
|
||||||
fn init(value: F) -> Self {
|
fn init(key: F) -> Self {
|
||||||
DummyHash {
|
DummyHash {
|
||||||
power: F::ZETA + F::one() + value,
|
power: F::ZETA + F::one() + key,
|
||||||
state: F::ZETA,
|
state: F::ZETA,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,3 +44,85 @@ impl<F: Field> Hasher<F> for DummyHash<F> {
|
||||||
tmp
|
tmp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A transcript that can absorb points from both the base field and scalar
|
||||||
|
/// field of a curve
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Transcript<C: CurveAffine, HBase, HScalar>
|
||||||
|
where
|
||||||
|
HBase: Hasher<C::Base>,
|
||||||
|
HScalar: Hasher<C::Scalar>,
|
||||||
|
{
|
||||||
|
// Hasher over the base field
|
||||||
|
base_hasher: HBase,
|
||||||
|
// Hasher over the scalar field
|
||||||
|
scalar_hasher: HScalar,
|
||||||
|
// Indicates if scalar(s) has been hashed but not squeezed
|
||||||
|
scalar_needs_squeezing: bool,
|
||||||
|
// PhantomData
|
||||||
|
_marker: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveAffine, HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>
|
||||||
|
Transcript<C, HBase, HScalar>
|
||||||
|
{
|
||||||
|
/// Initialise a new transcript with Field::one() as keys
|
||||||
|
/// in both the base_hasher and scalar_hasher
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let base_hasher = HBase::init(C::Base::one());
|
||||||
|
let scalar_hasher = HScalar::init(C::Scalar::one());
|
||||||
|
Transcript {
|
||||||
|
base_hasher,
|
||||||
|
scalar_hasher,
|
||||||
|
scalar_needs_squeezing: false,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialise a new transcript with some given base_hasher and
|
||||||
|
/// scalar_hasher
|
||||||
|
pub fn init_with_hashers(base_hasher: &HBase, scalar_hasher: &HScalar) -> Self {
|
||||||
|
Transcript {
|
||||||
|
base_hasher: base_hasher.clone(),
|
||||||
|
scalar_hasher: scalar_hasher.clone(),
|
||||||
|
scalar_needs_squeezing: false,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Absorb a curve point into the transcript by absorbing
|
||||||
|
/// its x and y coordinates
|
||||||
|
pub fn absorb_point(&mut self, point: &C) -> Result<(), ()> {
|
||||||
|
let tmp = point.get_xy();
|
||||||
|
if bool::from(tmp.is_none()) {
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
let tmp = tmp.unwrap();
|
||||||
|
self.base_hasher.absorb(tmp.0);
|
||||||
|
self.base_hasher.absorb(tmp.1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Absorb a base into the base_hasher
|
||||||
|
pub fn absorb_base(&mut self, base: C::Base) {
|
||||||
|
self.base_hasher.absorb(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Absorb a scalar into the scalar_hasher
|
||||||
|
pub fn absorb_scalar(&mut self, scalar: C::Scalar) {
|
||||||
|
self.scalar_hasher.absorb(scalar);
|
||||||
|
self.scalar_needs_squeezing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Squeeze the transcript to obtain a C::Base value.
|
||||||
|
pub fn squeeze(&mut self) -> C::Base {
|
||||||
|
if self.scalar_needs_squeezing {
|
||||||
|
let transcript_scalar_point =
|
||||||
|
C::Base::from_bytes(&(self.scalar_hasher.squeeze()).to_bytes()).unwrap();
|
||||||
|
self.base_hasher.absorb(transcript_scalar_point);
|
||||||
|
self.scalar_needs_squeezing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.base_hasher.squeeze()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue