Skip to content

Commit

Permalink
Merge pull request zcash#43 from zcash/transcript-merge
Browse files Browse the repository at this point in the history
Make transcript generic over curve point
  • Loading branch information
str4d authored Nov 24, 2020
2 parents 1e8769b + bffab99 commit e8bf35d
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 136 deletions.
18 changes: 2 additions & 16 deletions src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::arithmetic::CurveAffine;
use crate::poly::{
multiopen, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial,
};
use crate::transcript::Hasher;

mod circuit;
mod keygen;
Expand Down Expand Up @@ -78,6 +77,8 @@ pub enum Error {
BoundsFailure,
/// Opening error
OpeningError,
/// Transcript error
TranscriptError,
}

impl<C: CurveAffine> ProvingKey<C> {
Expand All @@ -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]
fn test_proving() {
use crate::arithmetic::{Curve, Field};
Expand Down
37 changes: 18 additions & 19 deletions src/plonk/prover.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
hash_point, Error, Proof, ProvingKey,
Error, Proof, ProvingKey,
};
use crate::arithmetic::{
eval_polynomial, get_challenge_scalar, parallelize, BatchInvert, Challenge, Curve, CurveAffine,
Expand All @@ -11,7 +11,7 @@ use crate::poly::{
multiopen::{self, ProverQuery},
LagrangeCoeff, Polynomial, Rotation,
};
use crate::transcript::Hasher;
use crate::transcript::{Hasher, Transcript};

impl<C: CurveAffine> Proof<C> {
/// This creates a proof for the provided `circuit` when given the public
Expand Down Expand Up @@ -92,7 +92,7 @@ impl<C: CurveAffine> Proof<C> {
let witness = witness;

// 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
let aux_commitments_projective: Vec<_> = aux
Expand All @@ -105,7 +105,9 @@ impl<C: CurveAffine> Proof<C> {
drop(aux_commitments_projective);

for commitment in &aux_commitments {
hash_point(&mut transcript, commitment)?;
transcript
.absorb_point(commitment)
.map_err(|_| Error::TranscriptError)?;
}

let aux_polys: Vec<_> = aux
Expand Down Expand Up @@ -143,7 +145,9 @@ impl<C: CurveAffine> Proof<C> {
drop(advice_commitments_projective);

for commitment in &advice_commitments {
hash_point(&mut transcript, commitment)?;
transcript
.absorb_point(commitment)
.map_err(|_| Error::TranscriptError)?;
}

let advice_polys: Vec<_> = witness
Expand Down Expand Up @@ -277,7 +281,9 @@ impl<C: CurveAffine> Proof<C> {

// Hash each permutation product commitment
for c in &permutation_product_commitments {
hash_point(&mut transcript, c)?;
transcript
.absorb_point(c)
.map_err(|_| Error::TranscriptError)?;
}

// Obtain challenge for keeping all separate gates linearly independent
Expand Down Expand Up @@ -385,7 +391,9 @@ impl<C: CurveAffine> Proof<C> {

// Hash each h(X) piece
for c in h_commitments.iter() {
hash_point(&mut transcript, c)?;
transcript
.absorb_point(c)
.map_err(|_| Error::TranscriptError)?;
}

let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));
Expand Down Expand Up @@ -444,10 +452,6 @@ impl<C: CurveAffine> Proof<C> {
.map(|poly| eval_polynomial(poly, x_3))
.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
for eval in advice_evals
.iter()
Expand All @@ -458,13 +462,9 @@ impl<C: CurveAffine> Proof<C> {
.chain(permutation_product_inv_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();

for (query_index, &(column, at)) in pk.vk.cs.advice_queries.iter().enumerate() {
Expand Down Expand Up @@ -558,9 +558,8 @@ impl<C: CurveAffine> Proof<C> {
}
}

let multiopening =
multiopen::Proof::create(params, &mut transcript, &mut transcript_scalar, instances)
.map_err(|_| Error::OpeningError)?;
let multiopening = multiopen::Proof::create(params, &mut transcript, instances)
.map_err(|_| Error::OpeningError)?;

Ok(Proof {
advice_commitments,
Expand Down
40 changes: 17 additions & 23 deletions src/plonk/verifier.rs
Original file line number Diff line number Diff line change
@@ -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::poly::{
commitment::{Guard, Params, MSM},
multiopen::VerifierQuery,
Rotation,
};
use crate::transcript::Hasher;
use crate::transcript::{Hasher, Transcript};

impl<'a, C: CurveAffine> Proof<C> {
/// Returns a boolean indicating whether or not the proof is valid
Expand All @@ -27,16 +27,20 @@ impl<'a, C: CurveAffine> Proof<C> {
}

// 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
for commitment in aux_commitments {
hash_point(&mut transcript, commitment)?;
transcript
.absorb_point(commitment)
.map_err(|_| Error::TranscriptError)?;
}

// Hash the prover's advice commitments into the transcript
for commitment in &self.advice_commitments {
hash_point(&mut transcript, commitment)?;
transcript
.absorb_point(commitment)
.map_err(|_| Error::TranscriptError)?;
}

// Sample x_0 challenge
Expand All @@ -47,15 +51,19 @@ impl<'a, C: CurveAffine> Proof<C> {

// Hash each permutation product commitment
for c in &self.permutation_product_commitments {
hash_point(&mut transcript, c)?;
transcript
.absorb_point(c)
.map_err(|_| Error::TranscriptError)?;
}

// Sample x_2 challenge, which keeps the gates linearly independent.
let x_2: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128()));

// Obtain a commitment to h(X) in the form of multiple pieces of degree n - 1
for c in &self.h_commitments {
hash_point(&mut transcript, c)?;
transcript
.absorb_point(c)
.map_err(|_| Error::TranscriptError)?;
}

// Sample x_3 challenge, which is used to ensure the circuit is
Expand All @@ -66,10 +74,6 @@ impl<'a, C: CurveAffine> Proof<C> {
// 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
// transcript on the scalar field.
let mut transcript_scalar = HScalar::init(C::Scalar::one());

for eval in self
.advice_evals
.iter()
Expand All @@ -80,13 +84,9 @@ impl<'a, C: CurveAffine> Proof<C> {
.chain(self.permutation_product_inv_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();

for (query_index, &(column, at)) in vk.cs.advice_queries.iter().enumerate() {
Expand Down Expand Up @@ -180,13 +180,7 @@ impl<'a, C: CurveAffine> Proof<C> {
// We are now convinced the circuit is satisfied so long as the
// polynomial commitments open to the correct values.
self.multiopening
.verify(
params,
&mut transcript,
&mut transcript_scalar,
queries,
msm,
)
.verify(params, &mut transcript, queries, msm)
.map_err(|_| Error::OpeningError)
}

Expand Down
21 changes: 12 additions & 9 deletions src/poly/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,10 @@ fn test_opening_proof() {
commitment::{Blind, Params},
EvaluationDomain,
};
use crate::arithmetic::{eval_polynomial, get_challenge_scalar, Challenge, Curve, Field};
use crate::transcript::{DummyHash, Hasher};
use crate::arithmetic::{
eval_polynomial, get_challenge_scalar, Challenge, Curve, CurveAffine, Field,
};
use crate::transcript::{DummyHash, Hasher, Transcript};
use crate::tweedle::{EpAffine, Fp, Fq};

let params = Params::<EpAffine>::new::<DummyHash<Fp>>(K);
Expand All @@ -265,25 +267,26 @@ fn test_opening_proof() {

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();
transcript.absorb(p_x);
transcript.absorb(p_y);
let x_packed = transcript.squeeze().get_lower_128();
hasher.absorb(p_x);
hasher.absorb(p_y);
let x_packed = hasher.squeeze().get_lower_128();
let x: Fq = get_challenge_scalar(Challenge(x_packed));

// Evaluate the polynomial
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 {
let transcript_dup = transcript.clone();

let opening_proof = Proof::create(&params, &mut transcript, &px, blind, x);
if opening_proof.is_err() {
transcript = transcript_dup;
transcript.absorb(Field::one());
transcript.absorb_base(Field::one());
} else {
let opening_proof = opening_proof.unwrap();
// Verify the opening proof
Expand Down
46 changes: 24 additions & 22 deletions src/poly/commitment/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::arithmetic::{
best_multiexp, compute_inner_product, get_challenge_scalar, parallelize, small_multiexp,
Challenge, Curve, CurveAffine, Field,
};
use crate::transcript::Hasher;
use crate::transcript::{Hasher, Transcript};

impl<C: CurveAffine> Proof<C> {
/// Create a polynomial commitment opening proof for the polynomial defined
Expand All @@ -20,13 +20,17 @@ impl<C: CurveAffine> Proof<C> {
/// 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
/// be rigorous.
pub fn create<H: Hasher<C::Base>>(
pub fn create<HBase, HScalar>(
params: &Params<C>,
transcript: &mut H,
transcript: &mut Transcript<C, HBase, HScalar>,
px: &Polynomial<C::Scalar, Coeff>,
blind: Blind<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;

// We're limited to polynomials of degree n - 1.
Expand Down Expand Up @@ -90,15 +94,14 @@ impl<C: CurveAffine> Proof<C> {
// until the challenge is a square.
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.
let (l_x, l_y) = l.get_xy().unwrap();
let (r_x, r_y) = r.get_xy().unwrap();

// Feed L and R into the cloned transcript...
transcript.absorb(l_x);
transcript.absorb(l_y);
transcript.absorb(r_x);
transcript.absorb(r_y);
transcript
.absorb_point(&l)
.map_err(|_| Error::SamplingError)?;
transcript
.absorb_point(&r)
.map_err(|_| Error::SamplingError)?;

// ... and get the squared challenge.
let challenge_sq_packed = transcript.squeeze().get_lower_128();
Expand All @@ -122,12 +125,12 @@ impl<C: CurveAffine> Proof<C> {
let challenge_sq = challenge.square();

// Feed L and R into the real transcript
let (l_x, l_y) = l.get_xy().unwrap();
let (r_x, r_y) = r.get_xy().unwrap();
transcript.absorb(l_x);
transcript.absorb(l_y);
transcript.absorb(r_x);
transcript.absorb(r_y);
transcript
.absorb_point(&l)
.map_err(|_| Error::SamplingError)?;
transcript
.absorb_point(&r)
.map_err(|_| Error::SamplingError)?;

// And obtain the challenge, even though we already have it, since
// squeezing affects the transcript.
Expand Down Expand Up @@ -172,11 +175,10 @@ impl<C: CurveAffine> Proof<C> {

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
transcript.absorb(delta_x);
transcript.absorb(delta_y);
transcript
.absorb_point(&delta)
.map_err(|_| Error::SamplingError)?;

// Obtain the challenge c.
let c_packed = transcript.squeeze().get_lower_128();
Expand Down
Loading

0 comments on commit e8bf35d

Please sign in to comment.