From 85c5f4412d12cf225d111f37b2f250dd3a75d283 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 23 Apr 2021 13:14:42 +0800 Subject: [PATCH] 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 --- src/plonk/verifier.rs | 2 +- src/poly/commitment.rs | 2 +- src/poly/commitment/verifier.rs | 22 ++--- src/poly/multiopen/verifier.rs | 2 +- src/transcript.rs | 147 +++++++++++++++++++++----------- 5 files changed, 111 insertions(+), 64 deletions(-) diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 592f01b9..eead6f5f 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -16,7 +16,7 @@ pub fn verify_proof<'a, C: CurveAffine, S: ChallengeSpace, T: TranscriptRead< msm: MSM<'a, C>, instance_commitments: &[&[C]], transcript: &mut T, -) -> Result, Error> { +) -> Result, 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 { diff --git a/src/poly/commitment.rs b/src/poly/commitment.rs index 6432e505..dd03da90 100644 --- a/src/poly/commitment.rs +++ b/src/poly/commitment.rs @@ -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 { diff --git a/src/poly/commitment/verifier.rs b/src/poly/commitment/verifier.rs index 2cccee7d..63e37b74 100644 --- a/src/poly/commitment/verifier.rs +++ b/src/poly/commitment/verifier.rs @@ -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> { msm: MSM<'a, C>, neg_a: C::Scalar, challenges: Vec, - challenges_packed: Vec, + challenges_packed: Vec, } /// An accumulator instance consisting of an evaluation claim and a proof. #[derive(Debug, Clone)] -pub struct Accumulator { +pub struct Accumulator> { /// 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, + pub challenges_packed: Vec, } -impl<'a, C: CurveAffine> Guard<'a, C> { +impl<'a, C: CurveAffine, S: ChallengeSpace> 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) { + pub fn use_g(mut self, g: C) -> (MSM<'a, C>, Accumulator) { self.msm.append_term(self.neg_a, g); let accumulator = Accumulator { @@ -70,7 +70,7 @@ pub fn verify_proof<'a, C: CurveAffine, S: ChallengeSpace, T: TranscriptRead< transcript: &mut T, x: C::Scalar, v: C::Scalar, -) -> Result, Error> { +) -> Result, 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, 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, T: TranscriptRead< .batch_invert(); let mut challenges = Vec::with_capacity(k); - let mut challenges_packed: Vec = Vec::with_capacity(k); + let mut challenges_packed: Vec = 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); diff --git a/src/poly/multiopen/verifier.rs b/src/poly/multiopen/verifier.rs index 222b7f14..f33c99ec 100644 --- a/src/poly/multiopen/verifier.rs +++ b/src/poly/multiopen/verifier.rs @@ -23,7 +23,7 @@ pub fn verify_proof<'b, 'a: 'b, I, C: CurveAffine, S: ChallengeSpace, T: Tran transcript: &mut T, queries: I, mut msm: MSM<'a, C>, -) -> Result, Error> +) -> Result, Error> where I: IntoIterator> + Clone, { diff --git a/src/transcript.rs b/src/transcript.rs index 0d98a2e1..41365c16 100644 --- a/src/transcript.rs +++ b/src/transcript.rs @@ -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> { - /// 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(&self, challenge: Challenge) -> ChallengeScalar { - S::to_challenge_scalar::(challenge) - } - - /// Squeeze a scalar challenge from the transcript. + /// Squeeze a challenge (in the scalar field) from the transcript. fn squeeze_challenge_scalar(&mut self) -> ChallengeScalar { - S::to_challenge_scalar::(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> TranscriptRead for Bla } impl> Transcript for Blake2bRead { + 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 = Option::from(point.coordinates()).ok_or_else(|| { io::Error::new( @@ -130,13 +129,6 @@ impl> Transcript 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> TranscriptWrite } impl> Transcript for Blake2bWrite { + 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 = Option::from(point.coordinates()).ok_or_else(|| { io::Error::new( @@ -203,18 +204,49 @@ impl> Transcript 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 { _marker: PhantomData, } -/// The challenge space used to sample a scalar from a 128-bit challenge. +impl std::ops::Deref for ChallengeScalar { + 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 { - /// Derive a scalar from a 128-bit challenge in a certain challenge space. - fn to_challenge_scalar(challenge: Challenge) -> ChallengeScalar; +pub trait ChallengeSpace: 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(challenge: Self::Challenge) -> ChallengeScalar; } /// 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 { _marker: PhantomData, } impl ChallengeSpace for ChallengeScalarEndo { - fn to_challenge_scalar(challenge: Challenge) -> ChallengeScalar { + const NUM_BYTES: usize = 16; + const BYTE_MASK: u8 = 0b11111111; + type Challenge = Challenge16; + + fn to_challenge_scalar(challenge: Self::Challenge) -> ChallengeScalar { 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 ChallengeSpace for ChallengeScalarEndo { } /// The scalar challenge space that samples from the full-width field. -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub struct ChallengeScalarFull { _marker: PhantomData, } impl ChallengeSpace for ChallengeScalarFull { - /// This algorithm applies the mapping of Algorithm 1 from the - /// [Halo](https://eprint.iacr.org/2019/1021) paper. - fn to_challenge_scalar(challenge: Challenge) -> ChallengeScalar { + const NUM_BYTES: usize = 64; + const BYTE_MASK: u8 = 0b111111; + type Challenge = Challenge64; + + fn to_challenge_scalar(challenge: Self::Challenge) -> ChallengeScalar { ChallengeScalar { - inner: C::Scalar::from_u128(challenge.0), + inner: C::Scalar::from_bytes_wide(&challenge.0), _marker: PhantomData, } } } -impl Deref for ChallengeScalar { - type Target = C::Scalar; - - fn deref(&self) -> &C::Scalar { - &self.inner - } -} - pub(crate) fn read_n_points, T: TranscriptRead>( transcript: &mut T, n: usize,