Introduce ChallengeSpace trait with to_challenge_scalar() method.

This is implemented for the ChallengeScalarEndo and ChallengeScalarFull types.

Co-authored-by: Kris Nuttycombe <kris@electriccoin.co>
This commit is contained in:
therealyingtong 2021-04-13 14:43:51 +08:00
parent 24d7100bd4
commit 1a9baab55b
1 changed files with 70 additions and 35 deletions

View File

@ -12,10 +12,25 @@ use std::io::{self, Read, Write};
use std::marker::PhantomData;
/// Generic transcript view (from either the prover or verifier's perspective)
pub trait Transcript<C: CurveAffine> {
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 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.
fn squeeze_challenge_scalar<T>(&mut self) -> ChallengeScalar<C, T> {
S::to_challenge_scalar::<T>(self.squeeze_challenge_128())
}
/// Writing the point to the transcript without writing it to the proof,
/// treating it as a common input.
fn common_point(&mut self, point: C) -> io::Result<()>;
@ -27,7 +42,7 @@ pub trait Transcript<C: CurveAffine> {
/// Transcript view from the perspective of a verifier that has access to an
/// input stream of data from the prover to the verifier.
pub trait TranscriptRead<C: CurveAffine>: Transcript<C> {
pub trait TranscriptRead<C: CurveAffine, S: ChallengeSpace<C>>: Transcript<C, S> {
/// Read a curve point from the prover.
fn read_point(&mut self) -> io::Result<C>;
@ -37,7 +52,7 @@ pub trait TranscriptRead<C: CurveAffine>: Transcript<C> {
/// Transcript view from the perspective of a prover that has access to an
/// output stream of messages from the prover to the verifier.
pub trait TranscriptWrite<C: CurveAffine>: Transcript<C> {
pub trait TranscriptWrite<C: CurveAffine, S: ChallengeSpace<C>>: Transcript<C, S> {
/// Write a curve point to the proof and the transcript.
fn write_point(&mut self, point: C) -> io::Result<()>;
@ -47,13 +62,14 @@ pub trait TranscriptWrite<C: CurveAffine>: Transcript<C> {
/// We will replace BLAKE2b with an algebraic hash function in a later version.
#[derive(Debug, Clone)]
pub struct Blake2bRead<R: Read, C: CurveAffine> {
pub struct Blake2bRead<R: Read, C: CurveAffine, S: ChallengeSpace<C>> {
state: Blake2bState,
reader: R,
_marker: PhantomData<C>,
_marker_s: PhantomData<S>,
}
impl<R: Read, C: CurveAffine> Blake2bRead<R, C> {
impl<R: Read, C: CurveAffine, S: ChallengeSpace<C>> Blake2bRead<R, C, S> {
/// Initialize a transcript given an input buffer and a key.
pub fn init(reader: R) -> Self {
Blake2bRead {
@ -63,11 +79,12 @@ impl<R: Read, C: CurveAffine> Blake2bRead<R, C> {
.to_state(),
reader,
_marker: PhantomData,
_marker_s: PhantomData,
}
}
}
impl<R: Read, C: CurveAffine> TranscriptRead<C> for Blake2bRead<R, C> {
impl<R: Read, C: CurveAffine, S: ChallengeSpace<C>> TranscriptRead<C, S> for Blake2bRead<R, C, S> {
fn read_point(&mut self) -> io::Result<C> {
let mut compressed = C::Repr::default();
self.reader.read_exact(compressed.as_mut())?;
@ -94,7 +111,7 @@ impl<R: Read, C: CurveAffine> TranscriptRead<C> for Blake2bRead<R, C> {
}
}
impl<R: Read, C: CurveAffine> Transcript<C> for Blake2bRead<R, C> {
impl<R: Read, C: CurveAffine, S: ChallengeSpace<C>> Transcript<C, S> for Blake2bRead<R, C, S> {
fn common_point(&mut self, point: C) -> io::Result<()> {
let coords: Coordinates<C> = Option::from(point.coordinates()).ok_or_else(|| {
io::Error::new(
@ -124,13 +141,14 @@ impl<R: Read, C: CurveAffine> Transcript<C> for Blake2bRead<R, C> {
/// We will replace BLAKE2b with an algebraic hash function in a later version.
#[derive(Debug, Clone)]
pub struct Blake2bWrite<W: Write, C: CurveAffine> {
pub struct Blake2bWrite<W: Write, C: CurveAffine, S: ChallengeSpace<C>> {
state: Blake2bState,
writer: W,
_marker: PhantomData<C>,
_marker_s: PhantomData<S>,
}
impl<W: Write, C: CurveAffine> Blake2bWrite<W, C> {
impl<W: Write, C: CurveAffine, S: ChallengeSpace<C>> Blake2bWrite<W, C, S> {
/// Initialize a transcript given an output buffer and a key.
pub fn init(writer: W) -> Self {
Blake2bWrite {
@ -140,6 +158,7 @@ impl<W: Write, C: CurveAffine> Blake2bWrite<W, C> {
.to_state(),
writer,
_marker: PhantomData,
_marker_s: PhantomData,
}
}
@ -150,7 +169,9 @@ impl<W: Write, C: CurveAffine> Blake2bWrite<W, C> {
}
}
impl<W: Write, C: CurveAffine> TranscriptWrite<C> for Blake2bWrite<W, C> {
impl<W: Write, C: CurveAffine, S: ChallengeSpace<C>> TranscriptWrite<C, S>
for Blake2bWrite<W, C, S>
{
fn write_point(&mut self, point: C) -> io::Result<()> {
self.common_point(point)?;
let compressed = point.to_bytes();
@ -163,7 +184,7 @@ impl<W: Write, C: CurveAffine> TranscriptWrite<C> for Blake2bWrite<W, C> {
}
}
impl<W: Write, C: CurveAffine> Transcript<C> for Blake2bWrite<W, C> {
impl<W: Write, C: CurveAffine, S: ChallengeSpace<C>> Transcript<C, S> for Blake2bWrite<W, C, S> {
fn common_point(&mut self, point: C) -> io::Result<()> {
let coords: Coordinates<C> = Option::from(point.coordinates()).ok_or_else(|| {
io::Error::new(
@ -195,27 +216,34 @@ impl<W: Write, C: CurveAffine> Transcript<C> for Blake2bWrite<W, C> {
#[derive(Copy, Clone, Debug)]
pub struct Challenge(pub(crate) u128);
impl Challenge {
/// Obtains a new challenge from the transcript.
pub fn get<C: CurveAffine, T: Transcript<C>>(transcript: &mut T) -> Challenge {
Challenge(transcript.squeeze_challenge().get_lower_128())
}
}
/// The scalar representation of a verifier challenge.
///
/// The `Type` type can be used to scope the challenge to a specific context, or
/// set to `()` if no context is required.
/// set to `Default` if no context is required.
#[derive(Copy, Clone, Debug)]
pub struct ChallengeScalar<C: CurveAffine, Type> {
pub struct ChallengeScalar<C: CurveAffine, T> {
inner: C::Scalar,
_marker: PhantomData<Type>,
_marker: PhantomData<T>,
}
impl<C: CurveAffine, Type> From<Challenge> for ChallengeScalar<C, Type> {
/// This algorithm applies the mapping of Algorithm 1 from the
/// [Halo](https://eprint.iacr.org/2019/1021) paper.
fn from(challenge: Challenge) -> Self {
/// The challenge space used to sample a scalar from a 128-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>;
}
/// The scalar challenge space that applies the mapping of Algorithm 1 from the
/// [Halo](https://eprint.iacr.org/2019/1021) paper.
#[derive(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> {
let mut acc = (C::Scalar::ZETA + &C::Scalar::one()).double();
for i in (0..64).rev() {
@ -238,17 +266,24 @@ impl<C: CurveAffine, Type> From<Challenge> for ChallengeScalar<C, Type> {
}
}
impl<C: CurveAffine, Type> ChallengeScalar<C, Type> {
/// Obtains a new challenge from the transcript.
pub fn get<T: Transcript<C>>(transcript: &mut T) -> Self
where
C: CurveAffine,
{
Challenge::get(transcript).into()
/// The scalar challenge space that samples from the full-width field.
#[derive(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> {
ChallengeScalar {
inner: C::Scalar::from_u128(challenge.0),
_marker: PhantomData,
}
}
}
impl<C: CurveAffine, Type> Deref for ChallengeScalar<C, Type> {
impl<C: CurveAffine, T> Deref for ChallengeScalar<C, T> {
type Target = C::Scalar;
fn deref(&self) -> &C::Scalar {
@ -256,14 +291,14 @@ impl<C: CurveAffine, Type> Deref for ChallengeScalar<C, Type> {
}
}
pub(crate) fn read_n_points<C: CurveAffine, T: TranscriptRead<C>>(
pub(crate) fn read_n_points<C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<C, S>>(
transcript: &mut T,
n: usize,
) -> io::Result<Vec<C>> {
(0..n).map(|_| transcript.read_point()).collect()
}
pub(crate) fn read_n_scalars<C: CurveAffine, T: TranscriptRead<C>>(
pub(crate) fn read_n_scalars<C: CurveAffine, S: ChallengeSpace<C>, T: TranscriptRead<C, S>>(
transcript: &mut T,
n: usize,
) -> io::Result<Vec<C::Scalar>> {