move transcript to trait (#46)
jump to
@@ -2,5 +2,6 @@ [workspace]
members = [ "hyperplonk", "pcs", - "poly-iop" + "poly-iop", + "transcript", ]
@@ -17,8 +17,7 @@ ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "curve" ] }
displaydoc = { version = "0.2.3", default-features = false } -poly-iop = { path = "../poly-iop" } - +transcript = { path = "../transcript" } # Benchmarks [[bench]]@@ -34,9 +33,7 @@ "ark-std/parallel",
"ark-ff/parallel", "ark-poly/parallel", "ark-ec/parallel", - "poly-iop/parallel" ] print-trace = [ "ark-std/print-trace", - "poly-iop/print-trace" ]
@@ -3,7 +3,7 @@
use ark_serialize::SerializationError; use ark_std::string::String; use displaydoc::Display; -use poly_iop::PolyIOPErrors; +use transcript::TranscriptErrors; /// A `enum` specifying the possible failure modes of the PCS. #[derive(Display, Debug)]@@ -18,8 +18,8 @@ /// Invalid parameters: {0}
InvalidParameters(String), /// An error during (de)serialization: {0} SerializationError(SerializationError), - /// PolyIOP error {0} - PolyIOPErrors(PolyIOPErrors), + /// Transcript error {0} + TranscriptError(TranscriptErrors), } impl From<SerializationError> for PCSErrors {@@ -28,8 +28,8 @@ Self::SerializationError(e)
} } -impl From<PolyIOPErrors> for PCSErrors { - fn from(e: PolyIOPErrors) -> Self { - Self::PolyIOPErrors(e) +impl From<TranscriptErrors> for PCSErrors { + fn from(e: TranscriptErrors) -> Self { + Self::TranscriptError(e) } }
@@ -13,7 +13,7 @@ };
use ark_ec::PairingEngine; use ark_poly::{DenseMultilinearExtension, EvaluationDomain, MultilinearExtension, Polynomial}; use ark_std::{end_timer, start_timer, vec::Vec}; -use poly_iop::IOPTranscript; +use transcript::IOPTranscript; /// Input /// - the prover parameters for univariate KZG,@@ -237,12 +237,12 @@ let r = transcript.get_and_append_challenge(b"r")?;
// 3. check `q(r) == batch_proof.q_x_value.last` and `q(omega^i) = // batch_proof.q_x_value[i]` - for i in 0..points_len { + for (i, value) in values.iter().enumerate().take(points_len) { if !KZGUnivariatePCS::verify( uni_verifier_param, &batch_proof.q_x_commit, &domain.element(i), - &values[i], + &value, &batch_proof.q_x_opens[i], )? { #[cfg(debug_assertion)]
@@ -7,8 +7,19 @@ univariate::DensePolynomial, DenseMultilinearExtension, EvaluationDomain, Evaluations,
MultilinearExtension, Polynomial, Radix2EvaluationDomain, }; use ark_std::{end_timer, log2, start_timer}; -use poly_iop::bit_decompose; use std::cmp::max; + +/// Decompose an integer into a binary vector in little endian. +#[allow(dead_code)] +pub(crate) fn bit_decompose(input: u64, num_var: usize) -> Vec<bool> { + let mut res = Vec::with_capacity(num_var); + let mut i = input; + for _ in 0..num_var { + res.push(i & 1 == 1); + i >>= 1; + } + res +} /// For an MLE w with `mle_num_vars` variables, and `point_len` number of /// points, compute the degree of the univariate polynomial `q(x):= w(l(x))`
@@ -14,10 +14,11 @@ ark-serialize = { version = "^0.3.0", default-features = false }
ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "curve" ] } rand_chacha = { version = "0.3.0", default-features = false } -merlin = { version = "3.0.0", default-features = false } displaydoc = { version = "0.2.3", default-features = false } rayon = { version = "1.5.2", default-features = false, optional = true } + +transcript = { path = "../transcript" } # Benchmarks [[bench]]
@@ -2,6 +2,7 @@ //! Error module.
use ark_std::string::String; use displaydoc::Display; +use transcript::TranscriptErrors; /// A `enum` specifying the possible failure modes of the PolyIOP. #[derive(Display, Debug)]@@ -14,12 +15,14 @@ /// Invalid Proof: {0}
InvalidProof(String), /// Invalid parameters: {0} InvalidParameters(String), - /// Invalid Transcript: {0} - InvalidTranscript(String), + /// Invalid challenge: {0} + InvalidChallenge(String), /// Should not arrive to this point ShouldNotArrive, /// An error during (de)serialization: {0} SerializationError(ark_serialize::SerializationError), + /// Transcript Error: {0} + TranscriptError(TranscriptErrors), } impl From<ark_serialize::SerializationError> for PolyIOPErrors {@@ -27,3 +30,9 @@ fn from(e: ark_serialize::SerializationError) -> Self {
Self::SerializationError(e) } } + +impl From<TranscriptErrors> for PolyIOPErrors { + fn from(e: TranscriptErrors) -> Self { + Self::TranscriptError(e) + } +}
@@ -1,12 +1,10 @@
//! Main module for the HyperPlonk PolyIOP. -use crate::{ - errors::PolyIOPErrors, perm_check::PermutationCheck, transcript::IOPTranscript, - zero_check::ZeroCheck, -}; +use crate::{errors::PolyIOPErrors, perm_check::PermutationCheck, zero_check::ZeroCheck}; use ark_ff::PrimeField; use ark_poly::DenseMultilinearExtension; use std::rc::Rc; +use transcript::IOPTranscript; /// A trait for HyperPlonk Poly-IOPs pub trait HyperPlonkPIOP<F: PrimeField> {
@@ -7,7 +7,6 @@ mod perm_check;
mod prod_check; mod structs; mod sum_check; -mod transcript; mod utils; mod virtual_poly; mod zero_check;@@ -20,7 +19,6 @@ PermutationCheck,
}; pub use prod_check::ProductCheck; pub use sum_check::SumCheck; -pub use transcript::IOPTranscript; pub use utils::*; pub use virtual_poly::{VPAuxInfo, VirtualPolynomial}; pub use zero_check::ZeroCheck;
@@ -1,13 +1,14 @@
//! Main module for the Permutation Check protocol use crate::{ - errors::PolyIOPErrors, perm_check::util::compute_prod_0, structs::IOPProof, - transcript::IOPTranscript, utils::get_index, PolyIOP, VirtualPolynomial, ZeroCheck, + errors::PolyIOPErrors, perm_check::util::compute_prod_0, structs::IOPProof, utils::get_index, + PolyIOP, VirtualPolynomial, ZeroCheck, }; use ark_ff::PrimeField; use ark_poly::DenseMultilinearExtension; use ark_std::{end_timer, start_timer}; use std::rc::Rc; +use transcript::IOPTranscript; pub mod util;@@ -221,7 +222,7 @@ transcript: &mut Self::Transcript,
prod_x_binding: &F, ) -> Result<(), PolyIOPErrors> { if challenge.alpha.is_some() { - return Err(PolyIOPErrors::InvalidTranscript( + return Err(PolyIOPErrors::InvalidChallenge( "alpha should not be sampled at the current stage".to_string(), )); }@@ -268,7 +269,7 @@ ) -> Result<[DenseMultilinearExtension<F>; 7], PolyIOPErrors> {
let start = start_timer!(|| "compute all prod polynomial"); if challenge.alpha.is_some() { - return Err(PolyIOPErrors::InvalidTranscript( + return Err(PolyIOPErrors::InvalidChallenge( "alpha is already sampled".to_string(), )); }@@ -372,7 +373,7 @@ ) -> Result<Self::Proof, PolyIOPErrors> {
let alpha = match challenge.alpha { Some(p) => p, None => { - return Err(PolyIOPErrors::InvalidTranscript( + return Err(PolyIOPErrors::InvalidChallenge( "alpha is not sampled yet".to_string(), )) },
@@ -1,8 +1,9 @@
//! Main module for the Permutation Check protocol -use crate::{errors::PolyIOPErrors, transcript::IOPTranscript, VirtualPolynomial, ZeroCheck}; +use crate::{errors::PolyIOPErrors, VirtualPolynomial, ZeroCheck}; use ark_ff::PrimeField; use ark_poly::DenseMultilinearExtension; +use transcript::IOPTranscript; /// A ProductCheck is derived from ZeroCheck. ///
@@ -2,17 +2,18 @@ //! This module defines structs that are shared by all sub protocols.
use crate::VirtualPolynomial; use ark_ff::PrimeField; +use ark_serialize::{CanonicalSerialize, SerializationError, Write}; /// An IOP proof is a collections of messages from prover to verifier at each /// round through the interactive protocol. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, CanonicalSerialize)] pub struct IOPProof<F: PrimeField> { pub proofs: Vec<IOPProverMessage<F>>, } /// A message from the prover to the verifier at a given round /// is a list of evaluations. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, CanonicalSerialize)] pub struct IOPProverMessage<F: PrimeField> { pub(crate) evaluations: Vec<F>, }
@@ -3,13 +3,13 @@
use crate::{ errors::PolyIOPErrors, structs::{IOPProof, IOPProverState, IOPVerifierState}, - transcript::IOPTranscript, virtual_poly::{VPAuxInfo, VirtualPolynomial}, PolyIOP, }; use ark_ff::PrimeField; use ark_poly::DenseMultilinearExtension; use ark_std::{end_timer, start_timer}; +use transcript::IOPTranscript; mod prover; mod verifier;@@ -160,7 +160,7 @@ transcript: &mut Self::Transcript,
) -> Result<Self::Proof, PolyIOPErrors> { let start = start_timer!(|| "sum check prove"); - transcript.append_aux_info(&poly.aux_info)?; + transcript.append_serializable_element(b"aux info", &poly.aux_info)?; let mut prover_state = IOPProverState::prover_init(poly)?; let mut challenge = None;@@ -168,7 +168,7 @@ let mut prover_msgs = Vec::with_capacity(poly.aux_info.num_variables);
for _ in 0..poly.aux_info.num_variables { let prover_msg = IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge)?; - transcript.append_prover_message(&prover_msg)?; + transcript.append_serializable_element(b"prover msg", &prover_msg)?; prover_msgs.push(prover_msg); challenge = Some(transcript.get_and_append_challenge(b"Internal round")?); }@@ -188,11 +188,11 @@ transcript: &mut Self::Transcript,
) -> Result<Self::SumCheckSubClaim, PolyIOPErrors> { let start = start_timer!(|| "sum check verify"); - transcript.append_aux_info(aux_info)?; + transcript.append_serializable_element(b"aux info", aux_info)?; let mut verifier_state = IOPVerifierState::verifier_init(aux_info); for i in 0..aux_info.num_variables { let prover_msg = proof.proofs.get(i).expect("proof is incomplete"); - transcript.append_prover_message(prover_msg)?; + transcript.append_serializable_element(b"prover msg", prover_msg)?; IOPVerifierState::verify_round_and_update_state( &mut verifier_state, prover_msg,
@@ -4,11 +4,11 @@ use super::{SumCheckSubClaim, SumCheckVerifier};
use crate::{ errors::PolyIOPErrors, structs::{IOPProverMessage, IOPVerifierState}, - transcript::IOPTranscript, virtual_poly::VPAuxInfo, }; use ark_ff::PrimeField; use ark_std::{end_timer, start_timer}; +use transcript::IOPTranscript; #[cfg(feature = "parallel")] use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
@@ -3,13 +3,14 @@ //! TODO(ZZ): move this module to HyperPlonk where the transcript will also be
//! useful. //! TODO(ZZ): decide which APIs need to be public. +mod errors; +pub use errors::TranscriptErrors; + use ark_ff::PrimeField; use ark_serialize::CanonicalSerialize; use merlin::Transcript; use std::marker::PhantomData; -use crate::{errors::PolyIOPErrors, structs::IOPProverMessage, to_bytes, virtual_poly::VPAuxInfo}; - /// An IOP transcript consists of a Merlin transcript and a flag `is_empty` to /// indicate that if the transcript is empty. ///@@ -27,6 +28,7 @@ #[doc(hidden)]
phantom: PhantomData<F>, } +// TODO: Make this into a Trait impl<F: PrimeField> IOPTranscript<F> { /// Create a new IOP transcript. pub fn new(label: &'static [u8]) -> Self {@@ -42,29 +44,18 @@ pub fn append_message(
&mut self, label: &'static [u8], msg: &[u8], - ) -> Result<(), PolyIOPErrors> { + ) -> Result<(), TranscriptErrors> { self.transcript.append_message(label, msg); self.is_empty = false; Ok(()) } - // Append the aux information for a virtual polynomial. - pub(crate) fn append_aux_info(&mut self, aux_info: &VPAuxInfo<F>) -> Result<(), PolyIOPErrors> { - let message = format!( - "max_mul {} num_var {}", - aux_info.max_degree, aux_info.num_variables - ); - self.append_message(b"aux info", message.as_bytes())?; - - Ok(()) - } - // Append the message to the transcript. pub fn append_field_element( &mut self, label: &'static [u8], field_elem: &F, - ) -> Result<(), PolyIOPErrors> { + ) -> Result<(), TranscriptErrors> { self.append_message(label, &to_bytes!(field_elem)?) }@@ -73,30 +64,22 @@ pub fn append_serializable_element<S: CanonicalSerialize>(
&mut self, label: &'static [u8], group_elem: &S, - ) -> Result<(), PolyIOPErrors> { + ) -> Result<(), TranscriptErrors> { self.append_message(label, &to_bytes!(group_elem)?) } - // Append a prover message to the transcript. - pub(crate) fn append_prover_message( - &mut self, - prover_message: &IOPProverMessage<F>, - ) -> Result<(), PolyIOPErrors> { - for e in prover_message.evaluations.iter() { - self.append_field_element(b"prover_message", e)?; - } - Ok(()) - } - // Generate the challenge from the current transcript // and append it to the transcript. // // The output field element is statistical uniform as long // as the field has a size less than 2^384. - pub fn get_and_append_challenge(&mut self, label: &'static [u8]) -> Result<F, PolyIOPErrors> { + pub fn get_and_append_challenge( + &mut self, + label: &'static [u8], + ) -> Result<F, TranscriptErrors> { // we need to reject when transcript is empty if self.is_empty { - return Err(PolyIOPErrors::InvalidTranscript( + return Err(TranscriptErrors::InvalidTranscript( "transcript is empty".to_string(), )); }@@ -114,14 +97,14 @@ // and append them to the transcript.
// // The output field element are statistical uniform as long // as the field has a size less than 2^384. - pub(crate) fn get_and_append_challenge_vectors( + pub fn get_and_append_challenge_vectors( &mut self, label: &'static [u8], len: usize, - ) -> Result<Vec<F>, PolyIOPErrors> { + ) -> Result<Vec<F>, TranscriptErrors> { // we need to reject when transcript is empty if self.is_empty { - return Err(PolyIOPErrors::InvalidTranscript( + return Err(TranscriptErrors::InvalidTranscript( "transcript is empty".to_string(), )); }@@ -133,3 +116,14 @@ }
Ok(res) } } + +/// Takes as input a struct, and converts them to a series of bytes. All traits +/// that implement `CanonicalSerialize` can be automatically converted to bytes +/// in this manner. +#[macro_export] +macro_rules! to_bytes { + ($x:expr) => {{ + let mut buf = ark_std::vec![]; + ark_serialize::CanonicalSerialize::serialize($x, &mut buf).map(|_| buf) + }}; +}
@@ -4,6 +4,7 @@
use crate::errors::PolyIOPErrors; use ark_ff::PrimeField; use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; +use ark_serialize::{CanonicalSerialize, SerializationError, Write}; use ark_std::{ end_timer, rand::{Rng, RngCore},@@ -51,7 +52,7 @@ /// Pointers to the above poly extensions
raw_pointers_lookup_table: HashMap<*const DenseMultilinearExtension<F>, usize>, } -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, CanonicalSerialize)] /// Auxiliary information about the multilinear polynomial pub struct VPAuxInfo<F: PrimeField> { /// max number of multiplicands in each product
@@ -1,8 +1,9 @@
//! Main module for the ZeroCheck protocol. -use crate::{errors::PolyIOPErrors, sum_check::SumCheck, transcript::IOPTranscript, PolyIOP}; +use crate::{errors::PolyIOPErrors, sum_check::SumCheck, PolyIOP}; use ark_ff::PrimeField; use ark_std::{end_timer, start_timer}; +use transcript::IOPTranscript; /// A zero check IOP subclaim for \hat f(x) is 0, consists of the following: /// - the SubClaim from the SumCheck
@@ -0,0 +1,17 @@
+[package] +name = "transcript" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +merlin = { version = "3.0.0", default-features = false } + + +ark-ff = { version = "^0.3.0", default-features = false } +ark-serialize = { version = "^0.3.0", default-features = false } +ark-std = { version = "^0.3.0", default-features = false } + +displaydoc = { version = "0.2.3", default-features = false }
@@ -0,0 +1,19 @@
+//! Error module. + +use ark_std::string::String; +use displaydoc::Display; + +/// A `enum` specifying the possible failure modes of the Transcript. +#[derive(Display, Debug)] +pub enum TranscriptErrors { + /// Invalid Transcript: {0} + InvalidTranscript(String), + /// An error during (de)serialization: {0} + SerializationError(ark_serialize::SerializationError), +} + +impl From<ark_serialize::SerializationError> for TranscriptErrors { + fn from(e: ark_serialize::SerializationError) -> Self { + Self::SerializationError(e) + } +}