mirror of https://github.com/zcash/halo2.git
Refactor Transcript API
- remove method to return a challenge in the base field - let ChallengeSpace decide length of raw challenge instead of limiting it to u128 Co-authored-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
cd3cc543cf
commit
85c5f4412d
|
@ -16,7 +16,7 @@ pub fn verify_proof<'a, C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<
|
|||
msm: MSM<'a, C>,
|
||||
instance_commitments: &[&[C]],
|
||||
transcript: &mut T,
|
||||
) -> Result<Guard<'a, C>, Error> {
|
||||
) -> Result<Guard<'a, C, S>, Error> {
|
||||
// Check that instance_commitments matches the expected number of instance columns
|
||||
for instance_commitments in instance_commitments.iter() {
|
||||
if instance_commitments.len() != vk.cs.num_instance_columns {
|
||||
|
|
|
@ -354,7 +354,7 @@ fn test_opening_proof() {
|
|||
commitment_msm.append_term(Field::one(), p);
|
||||
let guard = verify_proof(¶ms, commitment_msm, &mut transcript, *x, v).unwrap();
|
||||
let ch_verifier = transcript.squeeze_challenge();
|
||||
assert_eq!(ch_prover, ch_verifier);
|
||||
assert_eq!(*ch_prover, *ch_verifier);
|
||||
|
||||
// Test guard behavior prior to checking another proof
|
||||
{
|
||||
|
|
|
@ -3,31 +3,31 @@ use group::Curve;
|
|||
|
||||
use super::super::Error;
|
||||
use super::{Params, MSM};
|
||||
use crate::transcript::{Challenge, ChallengeSpace, TranscriptRead};
|
||||
use crate::transcript::{ChallengeSpace, TranscriptRead};
|
||||
|
||||
use crate::arithmetic::{best_multiexp, BatchInvert, CurveAffine};
|
||||
|
||||
/// A guard returned by the verifier
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Guard<'a, C: CurveAffine> {
|
||||
pub struct Guard<'a, C: CurveAffine, S: ChallengeSpace<C>> {
|
||||
msm: MSM<'a, C>,
|
||||
neg_a: C::Scalar,
|
||||
challenges: Vec<C::Scalar>,
|
||||
challenges_packed: Vec<Challenge>,
|
||||
challenges_packed: Vec<S::Challenge>,
|
||||
}
|
||||
|
||||
/// An accumulator instance consisting of an evaluation claim and a proof.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Accumulator<C: CurveAffine> {
|
||||
pub struct Accumulator<C: CurveAffine, S: ChallengeSpace<C>> {
|
||||
/// The claimed output of the linear-time polycommit opening protocol
|
||||
pub g: C,
|
||||
|
||||
/// A vector of 128-bit challenges sampled by the verifier, to be used in
|
||||
/// computing g.
|
||||
pub challenges_packed: Vec<Challenge>,
|
||||
pub challenges_packed: Vec<S::Challenge>,
|
||||
}
|
||||
|
||||
impl<'a, C: CurveAffine> Guard<'a, C> {
|
||||
impl<'a, C: CurveAffine, S: ChallengeSpace<C>> Guard<'a, C, S> {
|
||||
/// Lets caller supply the challenges and obtain an MSM with updated
|
||||
/// scalars and points.
|
||||
pub fn use_challenges(mut self) -> MSM<'a, C> {
|
||||
|
@ -40,7 +40,7 @@ impl<'a, C: CurveAffine> Guard<'a, C> {
|
|||
|
||||
/// Lets caller supply the purported G point and simply appends
|
||||
/// [-a] G to return an updated MSM.
|
||||
pub fn use_g(mut self, g: C) -> (MSM<'a, C>, Accumulator<C>) {
|
||||
pub fn use_g(mut self, g: C) -> (MSM<'a, C>, Accumulator<C, S>) {
|
||||
self.msm.append_term(self.neg_a, g);
|
||||
|
||||
let accumulator = Accumulator {
|
||||
|
@ -70,7 +70,7 @@ pub fn verify_proof<'a, C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<
|
|||
transcript: &mut T,
|
||||
x: C::Scalar,
|
||||
v: C::Scalar,
|
||||
) -> Result<Guard<'a, C>, Error> {
|
||||
) -> Result<Guard<'a, C, S>, Error> {
|
||||
let k = params.k as usize;
|
||||
|
||||
// P - [v] G_0 + S * iota
|
||||
|
@ -90,8 +90,8 @@ pub fn verify_proof<'a, C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<
|
|||
let l = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
let r = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
|
||||
let challenge_packed = transcript.squeeze_challenge_128();
|
||||
let challenge = *transcript.to_challenge_scalar::<()>(challenge_packed);
|
||||
let challenge_packed = transcript.squeeze_challenge();
|
||||
let challenge = *S::to_challenge_scalar::<()>(challenge_packed);
|
||||
|
||||
rounds.push((
|
||||
l,
|
||||
|
@ -108,7 +108,7 @@ pub fn verify_proof<'a, C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<
|
|||
.batch_invert();
|
||||
|
||||
let mut challenges = Vec::with_capacity(k);
|
||||
let mut challenges_packed: Vec<Challenge> = Vec::with_capacity(k);
|
||||
let mut challenges_packed: Vec<S::Challenge> = Vec::with_capacity(k);
|
||||
for (l, r, challenge, challenge_inv, challenge_packed) in rounds {
|
||||
msm.append_term(challenge_inv, l);
|
||||
msm.append_term(challenge, r);
|
||||
|
|
|
@ -23,7 +23,7 @@ pub fn verify_proof<'b, 'a: 'b, I, C: CurveAffine, S: ChallengeSpace<C>, T: Tran
|
|||
transcript: &mut T,
|
||||
queries: I,
|
||||
mut msm: MSM<'a, C>,
|
||||
) -> Result<Guard<'a, C>, Error>
|
||||
) -> Result<Guard<'a, C, S>, Error>
|
||||
where
|
||||
I: IntoIterator<Item = VerifierQuery<'b, C>> + Clone,
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
use blake2b_simd::{Params as Blake2bParams, State as Blake2bState};
|
||||
use ff::Field;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::arithmetic::{Coordinates, CurveAffine, FieldExt};
|
||||
|
||||
|
@ -13,22 +12,13 @@ use std::marker::PhantomData;
|
|||
|
||||
/// Generic transcript view (from either the prover or verifier's perspective)
|
||||
pub trait Transcript<C: CurveAffine, S: ChallengeSpace<C>> {
|
||||
/// Squeeze a challenge (in the base field) from the transcript.
|
||||
fn squeeze_challenge(&mut self) -> C::Base;
|
||||
/// Squeeze a verifier challenge from the transcript. The length of the
|
||||
/// challenge is determined by the `ChallengeSpace`.
|
||||
fn squeeze_challenge(&mut self) -> S::Challenge;
|
||||
|
||||
/// Squeeze a 128-bit verifier challenge from the transcript.
|
||||
fn squeeze_challenge_128(&mut self) -> Challenge {
|
||||
Challenge(self.squeeze_challenge().get_lower_128())
|
||||
}
|
||||
|
||||
/// Get a scalar challenge from a 128-bit challenge.
|
||||
fn to_challenge_scalar<T>(&self, challenge: Challenge) -> ChallengeScalar<C, T> {
|
||||
S::to_challenge_scalar::<T>(challenge)
|
||||
}
|
||||
|
||||
/// Squeeze a scalar challenge from the transcript.
|
||||
/// Squeeze a challenge (in the scalar field) from the transcript.
|
||||
fn squeeze_challenge_scalar<T>(&mut self) -> ChallengeScalar<C, T> {
|
||||
S::to_challenge_scalar::<T>(self.squeeze_challenge_128())
|
||||
S::to_challenge_scalar(self.squeeze_challenge())
|
||||
}
|
||||
|
||||
/// Writing the point to the transcript without writing it to the proof,
|
||||
|
@ -112,6 +102,15 @@ impl<R: Read, C: CurveAffine, S: ChallengeSpace<C>> TranscriptRead<C, S> for Bla
|
|||
}
|
||||
|
||||
impl<R: Read, C: CurveAffine, S: ChallengeSpace<C>> Transcript<C, S> for Blake2bRead<R, C, S> {
|
||||
fn squeeze_challenge(&mut self) -> S::Challenge {
|
||||
let hasher = self.state.clone();
|
||||
let mut result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap();
|
||||
result[S::NUM_BYTES - 1] &= S::BYTE_MASK;
|
||||
// self.state.update(&result[..S::NUM_BYTES]);
|
||||
self.state.update(&result[..]);
|
||||
S::Challenge::new(&result[..S::NUM_BYTES])
|
||||
}
|
||||
|
||||
fn common_point(&mut self, point: C) -> io::Result<()> {
|
||||
let coords: Coordinates<C> = Option::from(point.coordinates()).ok_or_else(|| {
|
||||
io::Error::new(
|
||||
|
@ -130,13 +129,6 @@ impl<R: Read, C: CurveAffine, S: ChallengeSpace<C>> Transcript<C, S> for Blake2b
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn squeeze_challenge(&mut self) -> C::Base {
|
||||
let hasher = self.state.clone();
|
||||
let result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap();
|
||||
self.state.update(&result[..]);
|
||||
C::Base::from_bytes_wide(&result)
|
||||
}
|
||||
}
|
||||
|
||||
/// We will replace BLAKE2b with an algebraic hash function in a later version.
|
||||
|
@ -185,6 +177,15 @@ impl<W: Write, C: CurveAffine, S: ChallengeSpace<C>> TranscriptWrite<C, S>
|
|||
}
|
||||
|
||||
impl<W: Write, C: CurveAffine, S: ChallengeSpace<C>> Transcript<C, S> for Blake2bWrite<W, C, S> {
|
||||
fn squeeze_challenge(&mut self) -> S::Challenge {
|
||||
let hasher = self.state.clone();
|
||||
let mut result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap();
|
||||
result[S::NUM_BYTES - 1] &= S::BYTE_MASK;
|
||||
// self.state.update(&result[..S::NUM_BYTES]);
|
||||
self.state.update(&result[..]);
|
||||
S::Challenge::new(&result[..S::NUM_BYTES])
|
||||
}
|
||||
|
||||
fn common_point(&mut self, point: C) -> io::Result<()> {
|
||||
let coords: Coordinates<C> = Option::from(point.coordinates()).ok_or_else(|| {
|
||||
io::Error::new(
|
||||
|
@ -203,18 +204,49 @@ impl<W: Write, C: CurveAffine, S: ChallengeSpace<C>> Transcript<C, S> for Blake2
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn squeeze_challenge(&mut self) -> C::Base {
|
||||
let hasher = self.state.clone();
|
||||
let result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap();
|
||||
self.state.update(&result[..]);
|
||||
C::Base::from_bytes_wide(&result)
|
||||
/// `Challenge` trait implemented for challenges of different lengths
|
||||
pub trait Challenge: Copy + Clone + std::fmt::Debug {
|
||||
/// Try to create challenge of appropriate length.
|
||||
fn new(challenge: &[u8]) -> Self;
|
||||
}
|
||||
|
||||
/// This is a 16-byte verifier challenge.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Challenge16(pub(crate) [u8; 16]);
|
||||
|
||||
impl Challenge for Challenge16 {
|
||||
fn new(challenge: &[u8]) -> Self {
|
||||
Self(challenge.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a 128-bit verifier challenge.
|
||||
impl std::ops::Deref for Challenge16 {
|
||||
type Target = [u8; 16];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a 64-byte verifier challenge.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Challenge(pub(crate) u128);
|
||||
pub struct Challenge64(pub(crate) [u8; 64]);
|
||||
|
||||
impl Challenge for Challenge64 {
|
||||
fn new(challenge: &[u8]) -> Self {
|
||||
Self(challenge.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Challenge64 {
|
||||
type Target = [u8; 64];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// The scalar representation of a verifier challenge.
|
||||
///
|
||||
|
@ -226,29 +258,50 @@ pub struct ChallengeScalar<C: CurveAffine, T> {
|
|||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// The challenge space used to sample a scalar from a 128-bit challenge.
|
||||
impl<C: CurveAffine, T> std::ops::Deref for ChallengeScalar<C, T> {
|
||||
type Target = C::Scalar;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
/// The challenge space used to sample a scalar from a 512-bit challenge.
|
||||
/// This protocol supports implementations for `ChallengeScalarEndo`, which
|
||||
/// uses an endomorphism, and `ChallengeScalarFull`, which samples the
|
||||
/// full-width field.
|
||||
pub trait ChallengeSpace<C: CurveAffine> {
|
||||
/// Derive a scalar from a 128-bit challenge in a certain challenge space.
|
||||
fn to_challenge_scalar<T>(challenge: Challenge) -> ChallengeScalar<C, T>;
|
||||
pub trait ChallengeSpace<C: CurveAffine>: Copy + Clone + std::fmt::Debug {
|
||||
/// TODO
|
||||
const NUM_BYTES: usize;
|
||||
/// TODO
|
||||
const BYTE_MASK: u8;
|
||||
/// TODO
|
||||
type Challenge: Challenge;
|
||||
|
||||
/// Derive a scalar from a challenge in a certain challenge space.
|
||||
fn to_challenge_scalar<T>(challenge: Self::Challenge) -> ChallengeScalar<C, T>;
|
||||
}
|
||||
|
||||
/// The scalar challenge space that applies the mapping of Algorithm 1 from the
|
||||
/// [Halo](https://eprint.iacr.org/2019/1021) paper.
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ChallengeScalarEndo<C: CurveAffine> {
|
||||
_marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> ChallengeSpace<C> for ChallengeScalarEndo<C> {
|
||||
fn to_challenge_scalar<T>(challenge: Challenge) -> ChallengeScalar<C, T> {
|
||||
const NUM_BYTES: usize = 16;
|
||||
const BYTE_MASK: u8 = 0b11111111;
|
||||
type Challenge = Challenge16;
|
||||
|
||||
fn to_challenge_scalar<T>(challenge: Self::Challenge) -> ChallengeScalar<C, T> {
|
||||
let mut acc = (C::Scalar::ZETA + &C::Scalar::one()).double();
|
||||
|
||||
let challenge: u128 = u128::from_le_bytes(challenge.0);
|
||||
|
||||
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 should_negate = ((challenge >> ((i << 1) + 1)) & 1) == 1;
|
||||
let should_endo = ((challenge >> (i << 1)) & 1) == 1;
|
||||
|
||||
let q = if should_negate {
|
||||
-C::Scalar::one()
|
||||
|
@ -267,30 +320,24 @@ impl<C: CurveAffine> ChallengeSpace<C> for ChallengeScalarEndo<C> {
|
|||
}
|
||||
|
||||
/// The scalar challenge space that samples from the full-width field.
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ChallengeScalarFull<C: CurveAffine> {
|
||||
_marker: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> ChallengeSpace<C> for ChallengeScalarFull<C> {
|
||||
/// This algorithm applies the mapping of Algorithm 1 from the
|
||||
/// [Halo](https://eprint.iacr.org/2019/1021) paper.
|
||||
fn to_challenge_scalar<T>(challenge: Challenge) -> ChallengeScalar<C, T> {
|
||||
const NUM_BYTES: usize = 64;
|
||||
const BYTE_MASK: u8 = 0b111111;
|
||||
type Challenge = Challenge64;
|
||||
|
||||
fn to_challenge_scalar<T>(challenge: Self::Challenge) -> ChallengeScalar<C, T> {
|
||||
ChallengeScalar {
|
||||
inner: C::Scalar::from_u128(challenge.0),
|
||||
inner: C::Scalar::from_bytes_wide(&challenge.0),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CurveAffine, T> Deref for ChallengeScalar<C, T> {
|
||||
type Target = C::Scalar;
|
||||
|
||||
fn deref(&self) -> &C::Scalar {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_n_points<C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<C, S>>(
|
||||
transcript: &mut T,
|
||||
n: usize,
|
||||
|
|
Loading…
Reference in New Issue