From 229148eb5a7566e1af3cef1891a3a2f5776b2232 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 26 Jul 2022 11:34:47 -0400 Subject: [PATCH] move transcript to trait (#46) --- Cargo.toml | 3 +- pcs/Cargo.toml | 5 +- pcs/src/errors.rs | 12 ++-- pcs/src/multilinear_kzg/batching.rs | 6 +- pcs/src/multilinear_kzg/util.rs | 13 ++++- poly-iop/Cargo.toml | 3 +- poly-iop/src/errors.rs | 13 ++++- poly-iop/src/hyperplonk/mod.rs | 6 +- poly-iop/src/lib.rs | 2 - poly-iop/src/perm_check/mod.rs | 11 ++-- poly-iop/src/prod_check/mod.rs | 3 +- poly-iop/src/structs.rs | 5 +- poly-iop/src/sum_check/mod.rs | 10 ++-- poly-iop/src/sum_check/verifier.rs | 2 +- poly-iop/src/virtual_poly.rs | 3 +- poly-iop/src/zero_check/mod.rs | 3 +- transcript/Cargo.toml | 17 ++++++ transcript/src/errors.rs | 19 ++++++ .../transcript.rs => transcript/src/lib.rs | 58 +++++++++---------- 19 files changed, 122 insertions(+), 72 deletions(-) create mode 100644 transcript/Cargo.toml create mode 100644 transcript/src/errors.rs rename poly-iop/src/transcript.rs => transcript/src/lib.rs (71%) diff --git a/Cargo.toml b/Cargo.toml index d841a62..2300049 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ members = [ "hyperplonk", "pcs", - "poly-iop" + "poly-iop", + "transcript", ] diff --git a/pcs/Cargo.toml b/pcs/Cargo.toml index 42929f5..e74ebc5 100644 --- a/pcs/Cargo.toml +++ b/pcs/Cargo.toml @@ -17,8 +17,7 @@ ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "cur displaydoc = { version = "0.2.3", default-features = false } -poly-iop = { path = "../poly-iop" } - +transcript = { path = "../transcript" } # Benchmarks [[bench]] @@ -34,9 +33,7 @@ parallel = [ "ark-ff/parallel", "ark-poly/parallel", "ark-ec/parallel", - "poly-iop/parallel" ] print-trace = [ "ark-std/print-trace", - "poly-iop/print-trace" ] \ No newline at end of file diff --git a/pcs/src/errors.rs b/pcs/src/errors.rs index 99d060d..804c8b9 100644 --- a/pcs/src/errors.rs +++ b/pcs/src/errors.rs @@ -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 @@ pub enum PCSErrors { InvalidParameters(String), /// An error during (de)serialization: {0} SerializationError(SerializationError), - /// PolyIOP error {0} - PolyIOPErrors(PolyIOPErrors), + /// Transcript error {0} + TranscriptError(TranscriptErrors), } impl From for PCSErrors { @@ -28,8 +28,8 @@ impl From for PCSErrors { } } -impl From for PCSErrors { - fn from(e: PolyIOPErrors) -> Self { - Self::PolyIOPErrors(e) +impl From for PCSErrors { + fn from(e: TranscriptErrors) -> Self { + Self::TranscriptError(e) } } diff --git a/pcs/src/multilinear_kzg/batching.rs b/pcs/src/multilinear_kzg/batching.rs index 875eb89..de26eef 100644 --- a/pcs/src/multilinear_kzg/batching.rs +++ b/pcs/src/multilinear_kzg/batching.rs @@ -13,7 +13,7 @@ use crate::{ 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 @@ pub(super) fn batch_verify_internal( // 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)] diff --git a/pcs/src/multilinear_kzg/util.rs b/pcs/src/multilinear_kzg/util.rs index 1846a04..09d26de 100644 --- a/pcs/src/multilinear_kzg/util.rs +++ b/pcs/src/multilinear_kzg/util.rs @@ -7,9 +7,20 @@ use ark_poly::{ 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 { + 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))` /// where l(x) is a list of polynomials that go through all points. diff --git a/poly-iop/Cargo.toml b/poly-iop/Cargo.toml index 3fcf4bd..f90f2dc 100644 --- a/poly-iop/Cargo.toml +++ b/poly-iop/Cargo.toml @@ -14,11 +14,12 @@ 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]] name = "poly-iop-benches" diff --git a/poly-iop/src/errors.rs b/poly-iop/src/errors.rs index 748cfbe..60ecdcd 100644 --- a/poly-iop/src/errors.rs +++ b/poly-iop/src/errors.rs @@ -2,6 +2,7 @@ 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 @@ pub enum PolyIOPErrors { 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 for PolyIOPErrors { @@ -27,3 +30,9 @@ impl From for PolyIOPErrors { Self::SerializationError(e) } } + +impl From for PolyIOPErrors { + fn from(e: TranscriptErrors) -> Self { + Self::TranscriptError(e) + } +} diff --git a/poly-iop/src/hyperplonk/mod.rs b/poly-iop/src/hyperplonk/mod.rs index 2401adc..4eb3846 100644 --- a/poly-iop/src/hyperplonk/mod.rs +++ b/poly-iop/src/hyperplonk/mod.rs @@ -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 { diff --git a/poly-iop/src/lib.rs b/poly-iop/src/lib.rs index 57f83f5..117f7c0 100644 --- a/poly-iop/src/lib.rs +++ b/poly-iop/src/lib.rs @@ -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 @@ pub use perm_check::{ }; 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; diff --git a/poly-iop/src/perm_check/mod.rs b/poly-iop/src/perm_check/mod.rs index d6c33e8..1eb9399 100644 --- a/poly-iop/src/perm_check/mod.rs +++ b/poly-iop/src/perm_check/mod.rs @@ -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 @@ impl PermutationCheck for PolyIOP { 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 @@ impl PermutationCheck for PolyIOP { 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 @@ impl PermutationCheck for PolyIOP { let alpha = match challenge.alpha { Some(p) => p, None => { - return Err(PolyIOPErrors::InvalidTranscript( + return Err(PolyIOPErrors::InvalidChallenge( "alpha is not sampled yet".to_string(), )) }, diff --git a/poly-iop/src/prod_check/mod.rs b/poly-iop/src/prod_check/mod.rs index 7f3ff33..8fd377f 100644 --- a/poly-iop/src/prod_check/mod.rs +++ b/poly-iop/src/prod_check/mod.rs @@ -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. /// diff --git a/poly-iop/src/structs.rs b/poly-iop/src/structs.rs index ecccfc8..459a30e 100644 --- a/poly-iop/src/structs.rs +++ b/poly-iop/src/structs.rs @@ -2,17 +2,18 @@ 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 { pub proofs: Vec>, } /// 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 { pub(crate) evaluations: Vec, } diff --git a/poly-iop/src/sum_check/mod.rs b/poly-iop/src/sum_check/mod.rs index ebd036e..a8f7d5b 100644 --- a/poly-iop/src/sum_check/mod.rs +++ b/poly-iop/src/sum_check/mod.rs @@ -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 @@ impl SumCheck for PolyIOP { ) -> Result { 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 @@ impl SumCheck for PolyIOP { 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 @@ impl SumCheck for PolyIOP { ) -> Result { 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, diff --git a/poly-iop/src/sum_check/verifier.rs b/poly-iop/src/sum_check/verifier.rs index 0e41269..24d90b7 100644 --- a/poly-iop/src/sum_check/verifier.rs +++ b/poly-iop/src/sum_check/verifier.rs @@ -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}; diff --git a/poly-iop/src/virtual_poly.rs b/poly-iop/src/virtual_poly.rs index 197b261..c16ced8 100644 --- a/poly-iop/src/virtual_poly.rs +++ b/poly-iop/src/virtual_poly.rs @@ -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 @@ pub struct VirtualPolynomial { raw_pointers_lookup_table: HashMap<*const DenseMultilinearExtension, usize>, } -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, CanonicalSerialize)] /// Auxiliary information about the multilinear polynomial pub struct VPAuxInfo { /// max number of multiplicands in each product diff --git a/poly-iop/src/zero_check/mod.rs b/poly-iop/src/zero_check/mod.rs index eab9e65..56b77f0 100644 --- a/poly-iop/src/zero_check/mod.rs +++ b/poly-iop/src/zero_check/mod.rs @@ -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 diff --git a/transcript/Cargo.toml b/transcript/Cargo.toml new file mode 100644 index 0000000..91c7c2f --- /dev/null +++ b/transcript/Cargo.toml @@ -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 } diff --git a/transcript/src/errors.rs b/transcript/src/errors.rs new file mode 100644 index 0000000..0886575 --- /dev/null +++ b/transcript/src/errors.rs @@ -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 for TranscriptErrors { + fn from(e: ark_serialize::SerializationError) -> Self { + Self::SerializationError(e) + } +} diff --git a/poly-iop/src/transcript.rs b/transcript/src/lib.rs similarity index 71% rename from poly-iop/src/transcript.rs rename to transcript/src/lib.rs index 7202379..63ad852 100644 --- a/poly-iop/src/transcript.rs +++ b/transcript/src/lib.rs @@ -3,13 +3,14 @@ //! 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 @@ pub struct IOPTranscript { phantom: PhantomData, } +// TODO: Make this into a Trait impl IOPTranscript { /// Create a new IOP transcript. pub fn new(label: &'static [u8]) -> Self { @@ -42,29 +44,18 @@ impl IOPTranscript { &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) -> 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 @@ impl IOPTranscript { &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, - ) -> 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 { + pub fn get_and_append_challenge( + &mut self, + label: &'static [u8], + ) -> Result { // 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 @@ impl IOPTranscript { // // 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, PolyIOPErrors> { + ) -> Result, 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 @@ impl IOPTranscript { 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) + }}; +}