Remove the Read/Write type parameters from Transcript{Read,Write}.

This commit is contained in:
Sean Bowe 2020-12-23 16:20:27 -07:00
parent dff5a3a692
commit c5e0364962
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
16 changed files with 49 additions and 78 deletions

View File

@ -6,7 +6,7 @@ use halo2::arithmetic::FieldExt;
use halo2::pasta::{EqAffine, Fp, Fq}; use halo2::pasta::{EqAffine, Fp, Fq};
use halo2::plonk::*; use halo2::plonk::*;
use halo2::poly::commitment::Params; use halo2::poly::commitment::Params;
use halo2::transcript::{DummyHashRead, DummyHashWrite, TranscriptRead, TranscriptWrite}; use halo2::transcript::{DummyHashRead, DummyHashWrite};
use std::marker::PhantomData; use std::marker::PhantomData;

View File

@ -4,7 +4,7 @@ use halo2::{
pasta::{EqAffine, Fp, Fq}, pasta::{EqAffine, Fp, Fq},
plonk::*, plonk::*,
poly::commitment::{Blind, Params}, poly::commitment::{Blind, Params},
transcript::{DummyHashRead, DummyHashWrite, TranscriptRead, TranscriptWrite}, transcript::{DummyHashRead, DummyHashWrite},
}; };
use std::marker::PhantomData; use std::marker::PhantomData;

View File

@ -105,7 +105,7 @@ fn test_proving() {
use crate::arithmetic::{Curve, FieldExt}; use crate::arithmetic::{Curve, FieldExt};
use crate::pasta::{EqAffine, Fp, Fq}; use crate::pasta::{EqAffine, Fp, Fq};
use crate::poly::commitment::{Blind, Params}; use crate::poly::commitment::{Blind, Params};
use crate::transcript::{DummyHashRead, DummyHashWrite, TranscriptRead, TranscriptWrite}; use crate::transcript::{DummyHashRead, DummyHashWrite};
use circuit::{Advice, Column, Fixed}; use circuit::{Advice, Column, Fixed};
use std::marker::PhantomData; use std::marker::PhantomData;
const K: u32 = 5; const K: u32 = 5;

View File

@ -13,7 +13,6 @@ use crate::{
transcript::TranscriptWrite, transcript::TranscriptWrite,
}; };
use ff::Field; use ff::Field;
use std::io::Write;
use std::{collections::BTreeMap, iter}; use std::{collections::BTreeMap, iter};
#[derive(Debug)] #[derive(Debug)]
@ -73,12 +72,7 @@ impl Argument {
/// - constructs Permuted<C> struct using permuted_input_value = A', and /// - constructs Permuted<C> struct using permuted_input_value = A', and
/// permuted_table_column = S'. /// permuted_table_column = S'.
/// The Permuted<C> struct is used to update the Lookup, and is then returned. /// The Permuted<C> struct is used to update the Lookup, and is then returned.
pub(in crate::plonk) fn commit_permuted< pub(in crate::plonk) fn commit_permuted<'a, C: CurveAffine, T: TranscriptWrite<C>>(
'a,
C: CurveAffine,
W: Write,
T: TranscriptWrite<W, C>,
>(
&self, &self,
pk: &ProvingKey<C>, pk: &ProvingKey<C>,
params: &Params<C>, params: &Params<C>,
@ -195,7 +189,7 @@ impl<'a, C: CurveAffine> Permuted<'a, C> {
/// grand product polynomial over the lookup. The grand product polynomial /// grand product polynomial over the lookup. The grand product polynomial
/// is used to populate the Product<C> struct. The Product<C> struct is /// is used to populate the Product<C> struct. The Product<C> struct is
/// added to the Lookup and finally returned by the method. /// added to the Lookup and finally returned by the method.
pub(in crate::plonk) fn commit_product<W: Write, T: TranscriptWrite<W, C>>( pub(in crate::plonk) fn commit_product<T: TranscriptWrite<C>>(
self, self,
pk: &ProvingKey<C>, pk: &ProvingKey<C>,
params: &Params<C>, params: &Params<C>,
@ -443,7 +437,7 @@ impl<'a, C: CurveAffine> Committed<'a, C> {
} }
impl<C: CurveAffine> Constructed<C> { impl<C: CurveAffine> Constructed<C> {
pub(in crate::plonk) fn evaluate<W: Write, T: TranscriptWrite<W, C>>( pub(in crate::plonk) fn evaluate<T: TranscriptWrite<C>>(
self, self,
pk: &ProvingKey<C>, pk: &ProvingKey<C>,
x: ChallengeX<C>, x: ChallengeX<C>,

View File

@ -9,7 +9,6 @@ use crate::{
transcript::TranscriptRead, transcript::TranscriptRead,
}; };
use ff::Field; use ff::Field;
use std::io::Read;
pub struct PermutationCommitments<C: CurveAffine> { pub struct PermutationCommitments<C: CurveAffine> {
permuted_input_commitment: C, permuted_input_commitment: C,
@ -32,11 +31,7 @@ pub struct Evaluated<C: CurveAffine> {
} }
impl Argument { impl Argument {
pub(in crate::plonk) fn absorb_permuted_commitments< pub(in crate::plonk) fn absorb_permuted_commitments<C: CurveAffine, T: TranscriptRead<C>>(
C: CurveAffine,
R: Read,
T: TranscriptRead<R, C>,
>(
&self, &self,
transcript: &mut T, transcript: &mut T,
) -> Result<PermutationCommitments<C>, Error> { ) -> Result<PermutationCommitments<C>, Error> {
@ -55,7 +50,7 @@ impl Argument {
} }
impl<C: CurveAffine> PermutationCommitments<C> { impl<C: CurveAffine> PermutationCommitments<C> {
pub(in crate::plonk) fn absorb_product_commitment<R: Read, T: TranscriptRead<R, C>>( pub(in crate::plonk) fn absorb_product_commitment<T: TranscriptRead<C>>(
self, self,
transcript: &mut T, transcript: &mut T,
) -> Result<Committed<C>, Error> { ) -> Result<Committed<C>, Error> {
@ -72,7 +67,7 @@ impl<C: CurveAffine> PermutationCommitments<C> {
} }
impl<C: CurveAffine> Committed<C> { impl<C: CurveAffine> Committed<C> {
pub(crate) fn evaluate<R: Read, T: TranscriptRead<R, C>>( pub(crate) fn evaluate<T: TranscriptRead<C>>(
self, self,
transcript: &mut T, transcript: &mut T,
) -> Result<Evaluated<C>, Error> { ) -> Result<Evaluated<C>, Error> {

View File

@ -1,5 +1,4 @@
use ff::Field; use ff::Field;
use std::io::Write;
use std::iter; use std::iter;
use super::{Argument, ProvingKey}; use super::{Argument, ProvingKey};
@ -34,7 +33,7 @@ pub(crate) struct Evaluated<C: CurveAffine> {
} }
impl Argument { impl Argument {
pub(in crate::plonk) fn commit<C: CurveAffine, W: Write, T: TranscriptWrite<W, C>>( pub(in crate::plonk) fn commit<C: CurveAffine, T: TranscriptWrite<C>>(
&self, &self,
params: &Params<C>, params: &Params<C>,
pk: &plonk::ProvingKey<C>, pk: &plonk::ProvingKey<C>,
@ -237,7 +236,7 @@ impl<C: CurveAffine> super::ProvingKey<C> {
} }
impl<C: CurveAffine> Constructed<C> { impl<C: CurveAffine> Constructed<C> {
pub(in crate::plonk) fn evaluate<W: Write, T: TranscriptWrite<W, C>>( pub(in crate::plonk) fn evaluate<T: TranscriptWrite<C>>(
self, self,
pk: &plonk::ProvingKey<C>, pk: &plonk::ProvingKey<C>,
pkey: &ProvingKey<C>, pkey: &ProvingKey<C>,

View File

@ -1,5 +1,4 @@
use ff::Field; use ff::Field;
use std::io::Read;
use std::iter; use std::iter;
use super::{Argument, VerifyingKey}; use super::{Argument, VerifyingKey};
@ -22,7 +21,7 @@ pub struct Evaluated<C: CurveAffine> {
} }
impl Argument { impl Argument {
pub(crate) fn absorb_product_commitment<C: CurveAffine, R: Read, T: TranscriptRead<R, C>>( pub(crate) fn absorb_product_commitment<C: CurveAffine, T: TranscriptRead<C>>(
&self, &self,
transcript: &mut T, transcript: &mut T,
) -> Result<Committed<C>, Error> { ) -> Result<Committed<C>, Error> {
@ -37,7 +36,7 @@ impl Argument {
} }
impl<C: CurveAffine> Committed<C> { impl<C: CurveAffine> Committed<C> {
pub(crate) fn evaluate<R: Read, T: TranscriptRead<R, C>>( pub(crate) fn evaluate<T: TranscriptRead<C>>(
self, self,
vkey: &VerifyingKey<C>, vkey: &VerifyingKey<C>,
transcript: &mut T, transcript: &mut T,

View File

@ -1,5 +1,4 @@
use ff::Field; use ff::Field;
use std::io::Write;
use std::iter; use std::iter;
use super::{ use super::{
@ -18,12 +17,7 @@ use crate::transcript::TranscriptWrite;
/// This creates a proof for the provided `circuit` when given the public /// This creates a proof for the provided `circuit` when given the public
/// parameters `params` and the proving key [`ProvingKey`] that was /// parameters `params` and the proving key [`ProvingKey`] that was
/// generated previously for the same circuit. /// generated previously for the same circuit.
pub fn create_proof< pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circuit<C::Scalar>>(
C: CurveAffine,
W: Write,
T: TranscriptWrite<W, C>,
ConcreteCircuit: Circuit<C::Scalar>,
>(
params: &Params<C>, params: &Params<C>,
pk: &ProvingKey<C>, pk: &ProvingKey<C>,
circuit: &ConcreteCircuit, circuit: &ConcreteCircuit,

View File

@ -1,5 +1,3 @@
use std::io::Write;
use super::Argument; use super::Argument;
use crate::{ use crate::{
arithmetic::{eval_polynomial, Curve, CurveAffine, FieldExt}, arithmetic::{eval_polynomial, Curve, CurveAffine, FieldExt},
@ -23,7 +21,7 @@ pub(in crate::plonk) struct Evaluated<C: CurveAffine> {
} }
impl<C: CurveAffine> Argument<C> { impl<C: CurveAffine> Argument<C> {
pub(in crate::plonk) fn construct<W: Write, T: TranscriptWrite<W, C>>( pub(in crate::plonk) fn construct<T: TranscriptWrite<C>>(
params: &Params<C>, params: &Params<C>,
domain: &EvaluationDomain<C::Scalar>, domain: &EvaluationDomain<C::Scalar>,
expressions: impl Iterator<Item = Polynomial<C::Scalar, ExtendedLagrangeCoeff>>, expressions: impl Iterator<Item = Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
@ -69,7 +67,7 @@ impl<C: CurveAffine> Argument<C> {
} }
impl<C: CurveAffine> Constructed<C> { impl<C: CurveAffine> Constructed<C> {
pub(in crate::plonk) fn evaluate<W: Write, T: TranscriptWrite<W, C>>( pub(in crate::plonk) fn evaluate<T: TranscriptWrite<C>>(
self, self,
x: ChallengeX<C>, x: ChallengeX<C>,
transcript: &mut T, transcript: &mut T,

View File

@ -1,5 +1,4 @@
use ff::Field; use ff::Field;
use std::io::Read;
use crate::{ use crate::{
arithmetic::CurveAffine, arithmetic::CurveAffine,
@ -20,7 +19,7 @@ pub struct Evaluated<C: CurveAffine> {
} }
impl<C: CurveAffine> Argument<C> { impl<C: CurveAffine> Argument<C> {
pub(in crate::plonk) fn absorb_commitments<R: Read, T: TranscriptRead<R, C>>( pub(in crate::plonk) fn absorb_commitments<T: TranscriptRead<C>>(
vk: &VerifyingKey<C>, vk: &VerifyingKey<C>,
transcript: &mut T, transcript: &mut T,
) -> Result<Committed<C>, Error> { ) -> Result<Committed<C>, Error> {
@ -33,7 +32,7 @@ impl<C: CurveAffine> Argument<C> {
} }
impl<C: CurveAffine> Committed<C> { impl<C: CurveAffine> Committed<C> {
pub(in crate::plonk) fn evaluate<R: Read, T: TranscriptRead<R, C>>( pub(in crate::plonk) fn evaluate<T: TranscriptRead<C>>(
self, self,
transcript: &mut T, transcript: &mut T,
) -> Result<Evaluated<C>, Error> { ) -> Result<Evaluated<C>, Error> {

View File

@ -1,5 +1,4 @@
use ff::Field; use ff::Field;
use std::io::Read;
use std::iter; use std::iter;
use super::{ use super::{
@ -14,7 +13,7 @@ use crate::poly::{
use crate::transcript::{read_n_points, read_n_scalars, TranscriptRead}; use crate::transcript::{read_n_points, read_n_scalars, TranscriptRead};
/// Returns a boolean indicating whether or not the proof is valid /// Returns a boolean indicating whether or not the proof is valid
pub fn verify_proof<'a, C: CurveAffine, R: Read, T: TranscriptRead<R, C>>( pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
params: &'a Params<C>, params: &'a Params<C>,
vk: &VerifyingKey<C>, vk: &VerifyingKey<C>,
msm: MSM<'a, C>, msm: MSM<'a, C>,

View File

@ -7,7 +7,7 @@ use crate::arithmetic::{
CurveAffine, FieldExt, CurveAffine, FieldExt,
}; };
use crate::transcript::{Challenge, ChallengeScalar, TranscriptWrite}; use crate::transcript::{Challenge, ChallengeScalar, TranscriptWrite};
use std::io::{self, Write}; use std::io;
/// Create a polynomial commitment opening proof for the polynomial defined /// Create a polynomial commitment opening proof for the polynomial defined
/// by the coefficients `px`, the blinding factor `blind` used for the /// by the coefficients `px`, the blinding factor `blind` used for the
@ -22,7 +22,7 @@ use std::io::{self, Write};
/// 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_proof<C: CurveAffine, W: Write, T: TranscriptWrite<W, C>>( pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>>(
params: &Params<C>, params: &Params<C>,
transcript: &mut T, transcript: &mut T,
px: &Polynomial<C::Scalar, Coeff>, px: &Polynomial<C::Scalar, Coeff>,

View File

@ -6,8 +6,6 @@ use crate::transcript::{Challenge, ChallengeScalar, TranscriptRead};
use crate::arithmetic::{best_multiexp, Curve, CurveAffine, FieldExt}; use crate::arithmetic::{best_multiexp, Curve, CurveAffine, FieldExt};
use std::io::Read;
/// A guard returned by the verifier /// A guard returned by the verifier
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Guard<'a, C: CurveAffine> { pub struct Guard<'a, C: CurveAffine> {
@ -67,7 +65,7 @@ impl<'a, C: CurveAffine> Guard<'a, C> {
/// Checks to see if an [`Proof`] is valid given the current `transcript`, and a /// Checks to see if an [`Proof`] is valid given the current `transcript`, and a
/// point `x` that the polynomial commitment `P` opens purportedly to the value /// point `x` that the polynomial commitment `P` opens purportedly to the value
/// `v`. The provided `msm` should evaluate to the commitment `P` being opened. /// `v`. The provided `msm` should evaluate to the commitment `P` being opened.
pub fn verify_proof<'a, C: CurveAffine, R: Read, T: TranscriptRead<R, C>>( pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
params: &'a Params<C>, params: &'a Params<C>,
mut msm: MSM<'a, C>, mut msm: MSM<'a, C>,
transcript: &mut T, transcript: &mut T,

View File

@ -13,7 +13,7 @@ use crate::arithmetic::{
use crate::transcript::TranscriptWrite; use crate::transcript::TranscriptWrite;
use ff::Field; use ff::Field;
use std::io::{self, Write}; use std::io;
use std::marker::PhantomData; use std::marker::PhantomData;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -25,7 +25,7 @@ struct CommitmentData<C: CurveAffine> {
} }
/// Create a multi-opening proof /// Create a multi-opening proof
pub fn create_proof<'a, I, C: CurveAffine, W: Write, T: TranscriptWrite<W, C>>( pub fn create_proof<'a, I, C: CurveAffine, T: TranscriptWrite<C>>(
params: &Params<C>, params: &Params<C>,
transcript: &mut T, transcript: &mut T,
queries: I, queries: I,

View File

@ -10,9 +10,6 @@ use super::{
}; };
use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt}; use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt};
use crate::transcript::TranscriptRead; use crate::transcript::TranscriptRead;
use std::io::Read;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct CommitmentData<C: CurveAffine> { struct CommitmentData<C: CurveAffine> {
set_index: usize, set_index: usize,
@ -21,7 +18,7 @@ struct CommitmentData<C: CurveAffine> {
} }
/// Verify a multi-opening proof /// Verify a multi-opening proof
pub fn verify_proof<'b, 'a: 'b, I, C: CurveAffine, R: Read, T: TranscriptRead<R, C>>( pub fn verify_proof<'b, 'a: 'b, I, C: CurveAffine, T: TranscriptRead<C>>(
params: &'a Params<C>, params: &'a Params<C>,
transcript: &mut T, transcript: &mut T,
queries: I, queries: I,

View File

@ -21,10 +21,7 @@ pub trait Transcript<C: CurveAffine> {
/// Transcript view from the perspective of a verifier that has access to an /// Transcript view from the perspective of a verifier that has access to an
/// input stream of data from the prover to the verifier. /// input stream of data from the prover to the verifier.
pub trait TranscriptRead<R: Read, C: CurveAffine>: Transcript<C> { pub trait TranscriptRead<C: CurveAffine>: Transcript<C> {
/// Initialize the transcript with a key and an input stream.
fn init(reader: R, key: C::Base) -> Self;
/// Read a curve point from the prover. /// Read a curve point from the prover.
fn read_point(&mut self) -> io::Result<C>; fn read_point(&mut self) -> io::Result<C>;
@ -34,12 +31,9 @@ pub trait TranscriptRead<R: Read, C: CurveAffine>: Transcript<C> {
/// Transcript view from the perspective of a prover that has access to an /// Transcript view from the perspective of a prover that has access to an
/// output stream of messages from the prover to the verifier. /// output stream of messages from the prover to the verifier.
pub trait TranscriptWrite<W: Write, C: CurveAffine>: Transcript<C> { pub trait TranscriptWrite<C: CurveAffine>: Transcript<C> {
/// Forked transcript that does not write to the proof structure. /// Forked transcript that does not write to the proof structure.
type ForkedTranscript: TranscriptWrite<io::Sink, C>; type ForkedTranscript: TranscriptWrite<C>;
/// Initialize the transcript with a key and an output stream.
fn init(writer: W, key: C::Base) -> Self;
/// Write a curve point to the proof and the transcript. /// Write a curve point to the proof and the transcript.
fn write_point(&mut self, point: C) -> io::Result<()>; fn write_point(&mut self, point: C) -> io::Result<()>;
@ -50,10 +44,6 @@ pub trait TranscriptWrite<W: Write, C: CurveAffine>: Transcript<C> {
/// Fork the transcript, creating a variant of this `TranscriptWrite` which /// Fork the transcript, creating a variant of this `TranscriptWrite` which
/// does not output anything to the writer. /// does not output anything to the writer.
fn fork(&self) -> Self::ForkedTranscript; fn fork(&self) -> Self::ForkedTranscript;
/// Return the writer to conclude the interaction and take possession of the
/// proof.
fn finalize(self) -> W;
} }
/// This is just a simple (and completely broken) transcript reader /// This is just a simple (and completely broken) transcript reader
@ -67,8 +57,9 @@ pub struct DummyHashRead<R: Read, C: CurveAffine> {
reader: R, reader: R,
} }
impl<R: Read, C: CurveAffine> TranscriptRead<R, C> for DummyHashRead<R, C> { impl<R: Read, C: CurveAffine> DummyHashRead<R, C> {
fn init(reader: R, key: C::Base) -> Self { /// Initialize a transcript given an input buffer and a key.
pub fn init(reader: R, key: C::Base) -> Self {
DummyHashRead { DummyHashRead {
base_state: key + &C::Base::from_u64(1013), base_state: key + &C::Base::from_u64(1013),
scalar_state: C::Scalar::from_u64(1013), scalar_state: C::Scalar::from_u64(1013),
@ -76,7 +67,9 @@ impl<R: Read, C: CurveAffine> TranscriptRead<R, C> for DummyHashRead<R, C> {
reader, reader,
} }
} }
}
impl<R: Read, C: CurveAffine> TranscriptRead<C> for DummyHashRead<R, C> {
fn read_point(&mut self) -> io::Result<C> { fn read_point(&mut self) -> io::Result<C> {
let mut compressed = [0u8; 32]; let mut compressed = [0u8; 32];
self.reader.read_exact(&mut compressed[..])?; self.reader.read_exact(&mut compressed[..])?;
@ -149,10 +142,9 @@ pub struct DummyHashWrite<W: Write, C: CurveAffine> {
writer: W, writer: W,
} }
impl<W: Write, C: CurveAffine> TranscriptWrite<W, C> for DummyHashWrite<W, C> { impl<W: Write, C: CurveAffine> DummyHashWrite<W, C> {
type ForkedTranscript = DummyHashWrite<io::Sink, C>; /// Initialize a transcript given an output buffer and a key.
pub fn init(writer: W, key: C::Base) -> Self {
fn init(writer: W, key: C::Base) -> Self {
DummyHashWrite { DummyHashWrite {
base_state: key + &C::Base::from_u64(1013), base_state: key + &C::Base::from_u64(1013),
scalar_state: C::Scalar::from_u64(1013), scalar_state: C::Scalar::from_u64(1013),
@ -160,6 +152,17 @@ impl<W: Write, C: CurveAffine> TranscriptWrite<W, C> for DummyHashWrite<W, C> {
writer, writer,
} }
} }
/// Conclude the interaction and return the output buffer (writer).
pub fn finalize(self) -> W {
// TODO: handle outstanding scalars?
self.writer
}
}
impl<W: Write, C: CurveAffine> TranscriptWrite<C> for DummyHashWrite<W, C> {
type ForkedTranscript = DummyHashWrite<io::Sink, C>;
fn write_point(&mut self, point: C) -> io::Result<()> { fn write_point(&mut self, point: C) -> io::Result<()> {
self.common_point(point)?; self.common_point(point)?;
let compressed = point.to_bytes(); let compressed = point.to_bytes();
@ -180,10 +183,6 @@ impl<W: Write, C: CurveAffine> TranscriptWrite<W, C> for DummyHashWrite<W, C> {
writer: io::sink(), writer: io::sink(),
} }
} }
fn finalize(self) -> W {
// TODO: handle outstanding scalars?
self.writer
}
} }
impl<W: Write, C: CurveAffine> Transcript<C> for DummyHashWrite<W, C> { impl<W: Write, C: CurveAffine> Transcript<C> for DummyHashWrite<W, C> {
@ -285,7 +284,7 @@ impl<C: CurveAffine, Type> Deref for ChallengeScalar<C, Type> {
} }
} }
pub(crate) fn read_n_points<C: CurveAffine, R: Read, T: TranscriptRead<R, C>>( pub(crate) fn read_n_points<C: CurveAffine, T: TranscriptRead<C>>(
transcript: &mut T, transcript: &mut T,
n: usize, n: usize,
) -> io::Result<Vec<C>> { ) -> io::Result<Vec<C>> {
@ -296,7 +295,7 @@ pub(crate) fn read_n_points<C: CurveAffine, R: Read, T: TranscriptRead<R, C>>(
Ok(v) Ok(v)
} }
pub(crate) fn read_n_scalars<C: CurveAffine, R: Read, T: TranscriptRead<R, C>>( pub(crate) fn read_n_scalars<C: CurveAffine, T: TranscriptRead<C>>(
transcript: &mut T, transcript: &mut T,
n: usize, n: usize,
) -> io::Result<Vec<C::Scalar>> { ) -> io::Result<Vec<C::Scalar>> {