From 8f212d31ef3e3d8180db1811a2c1025a55cfb6ed Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 1 Oct 2021 14:59:16 +0200 Subject: [PATCH] Working custom (de)serializer --- src/gadgets/arithmetic_extension.rs | 10 +- src/plonk/recursive_verifier.rs | 8 + src/util/mod.rs | 1 + src/util/serialization.rs | 357 ++++++++++++++++++++++++++++ 4 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 src/util/serialization.rs diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index af838ab6..de608be5 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -510,6 +510,7 @@ mod tests { use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::verifier::verify; + use crate::util::serialization::Buffer; #[test] fn test_mul_many() -> Result<()> { @@ -583,7 +584,7 @@ mod tests { let config = CircuitConfig::large_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config.clone()); let x = FF::rand_vec(4); let y = FF::rand_vec(4); @@ -602,6 +603,13 @@ mod tests { let data = builder.build(); let proof = data.prove(pw)?; + let mut buffer = Buffer::new(Vec::new()); + buffer.write_proof(&proof.proof).unwrap(); + dbg!(buffer.len()); + let mut buffer = Buffer::new(buffer.bytes()); + let oproof = buffer.read_proof(&data.common, &config).unwrap(); + assert_eq!(proof.proof, oproof); + verify(proof, &data.verifier_only, &data.common) } } diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index 75158d67..7babb26f 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -139,6 +139,7 @@ mod tests { use crate::plonk::proof::{OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs}; use crate::plonk::verifier::verify; use crate::util::log2_strict; + use crate::util::serialization::Buffer; // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. fn get_fri_query_round, const D: usize>( @@ -480,6 +481,13 @@ mod tests { builder.print_gate_counts(0); let data = builder.build(); let recursive_proof = data.prove(pw)?; + let mut buffer = Buffer::new(Vec::new()); + buffer.write_proof(&recursive_proof.proof).unwrap(); + dbg!(recursive_proof.public_inputs.len()); + dbg!(buffer.len()); + let mut buffer = Buffer::new(buffer.bytes()); + let proof = buffer.read_proof(&data.common, &config).unwrap(); + assert_eq!(recursive_proof.proof, proof); let now = std::time::Instant::now(); let compressed_recursive_proof = recursive_proof.clone().compress(&data.common)?; info!("{:.4} to compress proof", now.elapsed().as_secs_f64()); diff --git a/src/util/mod.rs b/src/util/mod.rs index daa6716b..d8e05a18 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod context_tree; pub(crate) mod marking; pub(crate) mod partial_products; pub mod reducing; +pub mod serialization; pub(crate) mod timing; pub(crate) fn bits_u64(n: u64) -> usize { diff --git a/src/util/serialization.rs b/src/util/serialization.rs new file mode 100644 index 00000000..5a32becb --- /dev/null +++ b/src/util/serialization.rs @@ -0,0 +1,357 @@ +use std::convert::TryInto; +use std::fmt; +use std::io::Cursor; +use std::io::{Error, ErrorKind, Read, Result, Write}; + +use crate::field::crandall_field::CrandallField; +use crate::field::extension_field::quartic::QuarticExtension; +use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::field_types::{Field, PrimeField, RichField}; +use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep}; +use crate::hash::hash_types::HashOut; +use crate::hash::merkle_proofs::MerkleProof; +use crate::hash::merkle_tree::{MerkleCap, MerkleTree}; +use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; +use crate::plonk::proof::{OpeningSet, Proof}; +use crate::polynomial::polynomial::PolynomialCoeffs; + +#[derive(Debug)] +pub struct Buffer(Cursor>); + +impl Buffer { + pub fn new(buffer: Vec) -> Self { + Self(Cursor::new(buffer)) + } + + pub fn len(&self) -> usize { + self.0.get_ref().len() + } + + pub fn bytes(self) -> Vec { + self.0.into_inner() + } + + pub fn write_u8(&mut self, x: u8) -> Result<()> { + self.0.write_all(&[x]) + } + pub fn read_u8(&mut self) -> Result { + let mut buf = [0; 1]; + self.0.read_exact(&mut buf)?; + Ok(buf[0]) + } + + pub fn write_field(&mut self, x: F) -> Result<()> { + self.0.write_all(&x.to_canonical_u64().to_le_bytes()) + } + pub fn read_field(&mut self) -> Result { + let mut buf = [0; std::mem::size_of::()]; + self.0.read_exact(&mut buf)?; + Ok(F::from_canonical_u64(u64::from_le_bytes( + buf.try_into().unwrap(), + ))) + } + + pub fn write_field_ext, const D: usize>( + &mut self, + x: F::Extension, + ) -> Result<()> { + for &a in &x.to_basefield_array() { + self.write_field(a)?; + } + Ok(()) + } + pub fn read_field_ext, const D: usize>(&mut self) -> Result { + let mut arr = [F::ZERO; D]; + for a in arr.iter_mut() { + *a = self.read_field()?; + } + Ok(>::from_basefield_array( + arr, + )) + } + + pub fn write_hash(&mut self, h: HashOut) -> Result<()> { + for &a in &h.elements { + self.write_field(a)?; + } + Ok(()) + } + pub fn read_hash(&mut self) -> Result> { + let mut elements = [F::ZERO; 4]; + for a in elements.iter_mut() { + *a = self.read_field()?; + } + Ok(HashOut { elements }) + } + + pub fn write_merkle_cap(&mut self, cap: &MerkleCap) -> Result<()> { + for &a in &cap.0 { + self.write_hash(a)?; + } + Ok(()) + } + pub fn read_merkle_cap(&mut self, cap_height: usize) -> Result> { + let cap_length = 1 << cap_height; + Ok(MerkleCap( + (0..cap_length) + .map(|_| self.read_hash()) + .collect::>>()?, + )) + } + + pub fn write_field_vec(&mut self, v: &[F]) -> Result<()> { + for &a in v { + self.write_field(a)?; + } + Ok(()) + } + pub fn read_field_vec(&mut self, length: usize) -> Result> { + Ok((0..length) + .map(|_| self.read_field()) + .collect::>>()?) + } + + pub fn write_field_ext_vec, const D: usize>( + &mut self, + v: &[F::Extension], + ) -> Result<()> { + for &a in v { + self.write_field_ext::(a)?; + } + Ok(()) + } + pub fn read_field_ext_vec, const D: usize>( + &mut self, + length: usize, + ) -> Result> { + Ok((0..length) + .map(|_| self.read_field_ext::()) + .collect::>>()?) + } + + pub fn write_opening_set, const D: usize>( + &mut self, + os: &OpeningSet, + ) -> Result<()> { + self.write_field_ext_vec::(&os.constants)?; + self.write_field_ext_vec::(&os.plonk_sigmas)?; + self.write_field_ext_vec::(&os.wires)?; + self.write_field_ext_vec::(&os.plonk_zs)?; + self.write_field_ext_vec::(&os.plonk_zs_right)?; + self.write_field_ext_vec::(&os.partial_products)?; + self.write_field_ext_vec::(&os.quotient_polys) + } + pub fn read_opening_set, const D: usize>( + &mut self, + common_data: &CommonCircuitData, + config: &CircuitConfig, + ) -> Result> { + let constants = self.read_field_ext_vec::(common_data.num_constants)?; + let plonk_sigmas = self.read_field_ext_vec::(config.num_routed_wires)?; + let wires = self.read_field_ext_vec::(config.num_wires)?; + let plonk_zs = self.read_field_ext_vec::(config.num_challenges)?; + let plonk_zs_right = self.read_field_ext_vec::(config.num_challenges)?; + let partial_products = self.read_field_ext_vec::( + common_data.num_partial_products.0 * config.num_challenges, + )?; + let quotient_polys = self.read_field_ext_vec::( + common_data.quotient_degree_factor * config.num_challenges, + )?; + Ok(OpeningSet { + constants, + plonk_sigmas, + wires, + plonk_zs, + plonk_zs_right, + partial_products, + quotient_polys, + }) + } + + pub fn write_merkle_proof(&mut self, p: &MerkleProof) -> Result<()> { + let length = p.siblings.len(); + self.write_u8( + length + .try_into() + .expect("Merkle proof length must fit in u8."), + ); + for &h in &p.siblings { + self.write_hash(h)?; + } + Ok(()) + } + pub fn read_merkle_proof(&mut self) -> Result> { + let length = self.read_u8()?; + Ok(MerkleProof { + siblings: (0..length) + .map(|_| self.read_hash()) + .collect::>>()?, + }) + } + + pub fn write_fri_initial_proof( + &mut self, + fitp: &FriInitialTreeProof, + ) -> Result<()> { + for (v, p) in &fitp.evals_proofs { + self.write_field_vec(v)?; + self.write_merkle_proof(p)?; + } + Ok(()) + } + pub fn read_fri_initial_proof, const D: usize>( + &mut self, + common_data: &CommonCircuitData, + config: &CircuitConfig, + ) -> Result> { + let mut evals_proofs = Vec::with_capacity(4); + + let constants_sigmas_v = + self.read_field_vec(common_data.num_constants + config.num_routed_wires)?; + let constants_sigmas_p = self.read_merkle_proof()?; + evals_proofs.push((constants_sigmas_v, constants_sigmas_p)); + + let wires_v = self.read_field_vec(config.num_wires)?; + let wires_p = self.read_merkle_proof()?; + evals_proofs.push((wires_v, wires_p)); + + let zs_partial_v = + self.read_field_vec(config.num_challenges * (1 + common_data.num_partial_products.0))?; + let zs_partial_p = self.read_merkle_proof()?; + evals_proofs.push((zs_partial_v, zs_partial_p)); + + let quotient_v = + self.read_field_vec(config.num_challenges * common_data.quotient_degree_factor)?; + let quotient_p = self.read_merkle_proof()?; + evals_proofs.push((quotient_v, quotient_p)); + + Ok(FriInitialTreeProof { evals_proofs }) + } + + pub fn write_fri_query_steps, const D: usize>( + &mut self, + fqss: &[FriQueryStep], + ) -> Result<()> { + for fqs in fqss { + self.write_field_ext_vec::(&fqs.evals)?; + self.write_merkle_proof(&fqs.merkle_proof)?; + } + Ok(()) + } + pub fn read_fri_query_steps, const D: usize>( + &mut self, + config: &CircuitConfig, + ) -> Result>> { + let mut fqss = Vec::with_capacity(config.fri_config.reduction_arity_bits.len()); + for &arity_bits in &config.fri_config.reduction_arity_bits { + let evals = self.read_field_ext_vec::(1 << arity_bits)?; + let merkle_proof = self.read_merkle_proof()?; + fqss.push(FriQueryStep { + evals, + merkle_proof, + }) + } + Ok(fqss) + } + + pub fn write_fri_query_rounds, const D: usize>( + &mut self, + fqrs: &[FriQueryRound], + ) -> Result<()> { + for fqr in fqrs { + self.write_fri_initial_proof(&fqr.initial_trees_proof)?; + self.write_fri_query_steps(&fqr.steps)?; + } + Ok(()) + } + pub fn read_fri_query_rounds, const D: usize>( + &mut self, + common_data: &CommonCircuitData, + config: &CircuitConfig, + ) -> Result>> { + let mut fqrs = Vec::with_capacity(config.fri_config.num_query_rounds); + for i in 0..config.fri_config.num_query_rounds { + let initial_trees_proof = self.read_fri_initial_proof(common_data, config)?; + let steps = self.read_fri_query_steps(config)?; + fqrs.push(FriQueryRound { + initial_trees_proof, + steps, + }) + } + Ok(fqrs) + } + + pub fn write_fri_proof, const D: usize>( + &mut self, + fp: &FriProof, + ) -> Result<()> { + for cap in &fp.commit_phase_merkle_caps { + self.write_merkle_cap(cap)?; + } + self.write_fri_query_rounds(&fp.query_round_proofs)?; + self.write_field_ext_vec::(&fp.final_poly.coeffs)?; + self.write_field(fp.pow_witness) + } + pub fn read_fri_proof, const D: usize>( + &mut self, + common_data: &CommonCircuitData, + config: &CircuitConfig, + ) -> Result> { + let commit_phase_merkle_caps = (0..config.fri_config.reduction_arity_bits.len()) + .map(|_| self.read_merkle_cap(config.cap_height)) + .collect::>>()?; + let query_round_proofs = self.read_fri_query_rounds(common_data, config)?; + let final_poly = PolynomialCoeffs::new(self.read_field_ext_vec::( + 1 << (common_data.degree_bits + - config.fri_config.reduction_arity_bits.iter().sum::()), + )?); + let pow_witness = self.read_field()?; + Ok(FriProof { + commit_phase_merkle_caps, + query_round_proofs, + final_poly, + pow_witness, + }) + } + + pub fn write_proof, const D: usize>( + &mut self, + proof: &Proof, + ) -> Result<()> { + self.write_merkle_cap(&proof.wires_cap)?; + self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; + self.write_merkle_cap(&proof.quotient_polys_cap)?; + self.write_opening_set(&proof.openings)?; + self.write_fri_proof(&proof.opening_proof) + } + pub fn read_proof, const D: usize>( + &mut self, + common_data: &CommonCircuitData, + config: &CircuitConfig, + ) -> Result> { + let wires_cap = self.read_merkle_cap(config.cap_height)?; + let plonk_zs_partial_products_cap = self.read_merkle_cap(config.cap_height)?; + let quotient_polys_cap = self.read_merkle_cap(config.cap_height)?; + let openings = self.read_opening_set(common_data, config)?; + let opening_proof = self.read_fri_proof(common_data, config)?; + + Ok(Proof { + wires_cap, + plonk_zs_partial_products_cap, + quotient_polys_cap, + openings, + opening_proof, + }) + } +} + +#[test] +fn yo() { + type F = CrandallField; + type FF = QuarticExtension; + let mut buffer = Buffer::new(Vec::new()); + let x = FF::rand(); + buffer.write_field_ext::(x).unwrap(); + let mut buffer = Buffer::new(buffer.0.into_inner()); + let y: FF = buffer.read_field_ext::().unwrap(); +}