diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index abf200061a..b611531f80 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -48,7 +48,7 @@ backtrace = { version = "0.3", optional = true } rayon = "1.5.1" ff = "0.12" group = "0.12" -halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = '0.3.0' } +halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves.git', tag = "0.3.1" } rand_core = { version = "0.6", default-features = false } tracing = "0.1" blake2b_simd = "1" diff --git a/halo2_proofs/examples/serialization.rs b/halo2_proofs/examples/serialization.rs index fbd19a89b4..91ed5464e4 100644 --- a/halo2_proofs/examples/serialization.rs +++ b/halo2_proofs/examples/serialization.rs @@ -21,6 +21,7 @@ use halo2_proofs::{ transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, + SerdeFormat, }; use halo2curves::bn256::{Bn256, Fr, G1Affine}; use rand_core::OsRng; @@ -134,12 +135,13 @@ fn main() { let f = File::create("serialization-test.pk").unwrap(); let mut writer = BufWriter::new(f); - pk.write(&mut writer).unwrap(); + pk.write(&mut writer, SerdeFormat::RawBytes).unwrap(); writer.flush().unwrap(); let f = File::open("serialization-test.pk").unwrap(); let mut reader = BufReader::new(f); - let pk = ProvingKey::::read::<_, StandardPlonk>(&mut reader, ¶ms).unwrap(); + let pk = ProvingKey::::read::<_, StandardPlonk>(&mut reader, SerdeFormat::RawBytes) + .unwrap(); std::fs::remove_file("serialization-test.pk").unwrap(); diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index f601eab984..41fc2e8d1e 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -1,8 +1,25 @@ use crate::poly::Polynomial; use ff::PrimeField; -use halo2curves::CurveAffine; +use halo2curves::{pairing::Engine, serde::SerdeObject, CurveAffine}; use std::io; +/// This enum specifies how various types are serialized and deserialized. +#[derive(Clone, Copy, Debug)] +pub enum SerdeFormat { + /// Curve elements are serialized in compressed form. + /// Field elements are serialized in standard form, with endianness specified by the + /// `PrimeField` implementation. + Processed, + /// Curve elements are serialized in uncompressed form. Field elements are serialized + /// in their internal Montgomery representation. + /// When deserializing, checks are performed to ensure curve elements indeed lie on the curve and field elements + /// are less than modulus. + RawBytes, + /// Serialization is the same as `RawBytes`, but no checks are performed. + RawBytesUnchecked, +} + +// Keep this trait for compatibility with IPA serialization pub(crate) trait CurveRead: CurveAffine { /// Reads a compressed element from the buffer and attempts to parse it /// using `from_bytes`. @@ -13,28 +30,68 @@ pub(crate) trait CurveRead: CurveAffine { .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid point encoding in proof")) } } - impl CurveRead for C {} -pub(crate) trait SerdePrimeField: PrimeField { - /// Reads a field element as bytes from the buffer using `from_repr`. - /// Endianness is specified by `PrimeField` implementation. - fn read(reader: &mut R) -> io::Result { - let mut compressed = Self::Repr::default(); - reader.read_exact(compressed.as_mut())?; - Option::from(Self::from_repr(compressed)).ok_or_else(|| { - io::Error::new(io::ErrorKind::Other, "Invalid prime field point encoding") - }) +pub trait SerdeCurveAffine: CurveAffine + SerdeObject { + /// Reads an element from the buffer and parses it according to the `format`: + /// - `Processed`: Reads a compressed curve element and decompress it + /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form. + /// Checks that field elements are less than modulus, and then checks that the point is on the curve. + /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form; + /// does not perform any checks + fn read(reader: &mut R, format: SerdeFormat) -> io::Result { + match format { + SerdeFormat::Processed => ::read(reader), + SerdeFormat::RawBytes => ::read_raw(reader), + SerdeFormat::RawBytesUnchecked => Ok(::read_raw_unchecked(reader)), + } } - - /// Writes a field element as bytes to the buffer using `to_repr`. - /// Endianness is specified by `PrimeField` implementation. - fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(self.to_repr().as_ref()) + /// Writes a curve element according to `format`: + /// - `Processed`: Writes a compressed curve element + /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form + fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { + match format { + SerdeFormat::Processed => writer.write_all(self.to_bytes().as_ref()), + _ => self.write_raw(writer), + } } } +impl SerdeCurveAffine for C {} + +pub trait SerdePrimeField: PrimeField + SerdeObject { + /// Reads a field element as bytes from the buffer according to the `format`: + /// - `Processed`: Reads a field element in standard form, with endianness specified by the + /// `PrimeField` implementation, and checks that the element is less than the modulus. + /// - `RawBytes`: Reads a field element from raw bytes in its internal Montgomery representations, + /// and checks that the element is less than the modulus. + /// - `RawBytesUnchecked`: Reads a field element in Montgomery form and performs no checks. + fn read(reader: &mut R, format: SerdeFormat) -> io::Result { + match format { + SerdeFormat::Processed => { + let mut compressed = Self::Repr::default(); + reader.read_exact(compressed.as_mut())?; + Option::from(Self::from_repr(compressed)).ok_or_else(|| { + io::Error::new(io::ErrorKind::Other, "Invalid prime field point encoding") + }) + } + SerdeFormat::RawBytes => ::read_raw(reader), + SerdeFormat::RawBytesUnchecked => Ok(::read_raw_unchecked(reader)), + } + } -impl SerdePrimeField for F {} + /// Writes a field element as bytes to the buffer according to the `format`: + /// - `Processed`: Writes a field element in standard form, with endianness specified by the + /// `PrimeField` implementation. + /// - Otherwise: Writes a field element into raw bytes in its internal Montgomery representation, + /// WITHOUT performing the expensive Montgomery reduction. + fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { + match format { + SerdeFormat::Processed => writer.write_all(self.to_repr().as_ref()), + _ => self.write_raw(writer), + } + } +} +impl SerdePrimeField for F {} /// Convert a slice of `bool` into a `u8`. /// @@ -56,26 +113,28 @@ pub fn unpack(byte: u8, bits: &mut [bool]) { } /// Reads a vector of polynomials from buffer -pub(crate) fn read_polynomial_vec( +pub(crate) fn read_polynomial_vec( reader: &mut R, + format: SerdeFormat, ) -> io::Result>> { - let mut len_be_bytes = [0u8; 4]; - reader.read_exact(&mut len_be_bytes)?; - let len = u32::from_be_bytes(len_be_bytes); + let mut len = [0u8; 4]; + reader.read_exact(&mut len)?; + let len = u32::from_be_bytes(len); (0..len) - .map(|_| Polynomial::::read(reader)) + .map(|_| Polynomial::::read(reader, format)) .collect::>>() } /// Writes a slice of polynomials to buffer -pub(crate) fn write_polynomial_slice( +pub(crate) fn write_polynomial_slice( slice: &[Polynomial], writer: &mut W, + format: SerdeFormat, ) -> io::Result<()> { writer.write_all(&(slice.len() as u32).to_be_bytes())?; for poly in slice.iter() { - poly.write(writer)?; + poly.write(writer, format)?; } Ok(()) } diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index c84e482675..52676ddb19 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -35,3 +35,4 @@ pub mod transcript; pub mod dev; mod helpers; +pub use helpers::SerdeFormat; diff --git a/halo2_proofs/src/plonk.rs b/halo2_proofs/src/plonk.rs index 70ae557eed..00f2c51586 100644 --- a/halo2_proofs/src/plonk.rs +++ b/halo2_proofs/src/plonk.rs @@ -11,7 +11,7 @@ use group::ff::Field; use crate::arithmetic::{CurveAffine, FieldExt}; use crate::helpers::{ - polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, CurveRead, + polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, SerdeCurveAffine, SerdePrimeField, }; use crate::poly::{ @@ -19,6 +19,7 @@ use crate::poly::{ PinnedEvaluationDomain, Polynomial, }; use crate::transcript::{ChallengeScalar, EncodedChallenge, Transcript}; +use crate::SerdeFormat; mod assigned; mod circuit; @@ -57,14 +58,26 @@ pub struct VerifyingKey { selectors: Vec>, } -impl VerifyingKey { +impl VerifyingKey +where + C::Scalar: SerdePrimeField, +{ /// Writes a verifying key to a buffer. - pub fn write(&self, writer: &mut W) -> io::Result<()> { + /// + /// Writes a curve element according to `format`: + /// - `Processed`: Writes a compressed curve element with coordinates in standard form. + /// Writes a field element in standard form, with endianness specified by the + /// `PrimeField` implementation. + /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form + /// Writes a field element into raw bytes in its internal Montgomery representation, + /// WITHOUT performing the expensive Montgomery reduction. + pub fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { + writer.write_all(&self.domain.k().to_be_bytes())?; writer.write_all(&(self.fixed_commitments.len() as u32).to_be_bytes())?; for commitment in &self.fixed_commitments { - writer.write_all(commitment.to_bytes().as_ref())?; + commitment.write(writer, format)?; } - self.permutation.write(writer)?; + self.permutation.write(writer, format)?; // write self.selectors for selector in &self.selectors { @@ -77,23 +90,35 @@ impl VerifyingKey { } /// Reads a verification key from a buffer. - pub fn read<'params, R: io::Read, ConcreteCircuit: Circuit>( + /// + /// Reads a curve element from the buffer and parses it according to the `format`: + /// - `Processed`: Reads a compressed curve element and decompresses it. + /// Reads a field element in standard form, with endianness specified by the + /// `PrimeField` implementation, and checks that the element is less than the modulus. + /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form. + /// Checks that field elements are less than modulus, and then checks that the point is on the curve. + /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form; + /// does not perform any checks + pub fn read>( reader: &mut R, - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - let (domain, cs, _) = keygen::create_domain::(params.k()); - let mut num_fixed_columns_be_bytes = [0u8; 4]; - reader.read_exact(&mut num_fixed_columns_be_bytes)?; - let num_fixed_columns = u32::from_be_bytes(num_fixed_columns_be_bytes); + let mut k = [0u8; 4]; + reader.read_exact(&mut k)?; + let k = u32::from_be_bytes(k); + let (domain, cs, _) = keygen::create_domain::(k); + let mut num_fixed_columns = [0u8; 4]; + reader.read_exact(&mut num_fixed_columns)?; + let num_fixed_columns = u32::from_be_bytes(num_fixed_columns); let fixed_commitments: Vec<_> = (0..num_fixed_columns) - .map(|_| C::read(reader)) + .map(|_| C::read(reader, format)) .collect::>()?; - let permutation = permutation::VerifyingKey::read(reader, &cs.permutation)?; + let permutation = permutation::VerifyingKey::read(reader, &cs.permutation, format)?; // read selectors - let selectors: Vec> = vec![vec![false; params.n() as usize]; cs.num_selectors] + let selectors: Vec> = vec![vec![false; 1 << k]; cs.num_selectors] .into_iter() .map(|mut selector| { let mut selector_bytes = vec![0u8; (selector.len() + 7) / 8]; @@ -103,8 +128,7 @@ impl VerifyingKey { } Ok(selector) }) - .collect::>>>() - .unwrap(); + .collect::>()?; let (cs, _) = cs.compress_selectors(selectors.clone()); Ok(Self::from_parts( @@ -116,23 +140,25 @@ impl VerifyingKey { )) } - /// Writes a verifying key to a vector of bytes. - pub fn to_bytes(&self) -> Vec { + /// Writes a verifying key to a vector of bytes using [`Self::write`]. + pub fn to_bytes(&self, format: SerdeFormat) -> Vec { let mut bytes = Vec::::with_capacity(self.bytes_length()); - Self::write(self, &mut bytes).expect("Writing to vector should not fail"); + Self::write(self, &mut bytes, format).expect("Writing to vector should not fail"); bytes } - /// Reads a verification key from a slice of bytes. - pub fn from_bytes<'params, ConcreteCircuit: Circuit>( + /// Reads a verification key from a slice of bytes using [`Self::read`]. + pub fn from_bytes>( mut bytes: &[u8], - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - Self::read::<_, ConcreteCircuit>(&mut bytes, params) + Self::read::<_, ConcreteCircuit>(&mut bytes, format) } +} +impl VerifyingKey { fn bytes_length(&self) -> usize { - 4 + (self.fixed_commitments.len() * C::default().to_bytes().as_ref().len()) + 8 + (self.fixed_commitments.len() * C::default().to_bytes().as_ref().len()) + self.permutation.bytes_length() + self.selectors.len() * (self @@ -251,34 +277,68 @@ impl ProvingKey { &self.vk } + /// Gets the total number of bytes in the serialization of `self` + fn bytes_length(&self) -> usize { + let scalar_len = C::Scalar::default().to_repr().as_ref().len(); + self.vk.bytes_length() + + 12 + + scalar_len * (self.l0.len() + self.l_last.len() + self.l_active_row.len()) + + polynomial_slice_byte_length(&self.fixed_values) + + polynomial_slice_byte_length(&self.fixed_polys) + + polynomial_slice_byte_length(&self.fixed_cosets) + + self.permutation.bytes_length() + } +} + +impl ProvingKey +where + C::Scalar: SerdePrimeField, +{ /// Writes a proving key to a buffer. + /// + /// Writes a curve element according to `format`: + /// - `Processed`: Writes a compressed curve element with coordinates in standard form. + /// Writes a field element in standard form, with endianness specified by the + /// `PrimeField` implementation. + /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form + /// Writes a field element into raw bytes in its internal Montgomery representation, + /// WITHOUT performing the expensive Montgomery reduction. /// Does so by first writing the verifying key and then serializing the rest of the data (in the form of field polynomials) - pub fn write(&self, writer: &mut W) -> io::Result<()> { - self.vk.write(writer)?; - self.l0.write(writer)?; - self.l_last.write(writer)?; - self.l_active_row.write(writer)?; - write_polynomial_slice(&self.fixed_values, writer)?; - write_polynomial_slice(&self.fixed_polys, writer)?; - write_polynomial_slice(&self.fixed_cosets, writer)?; - self.permutation.write(writer)?; + pub fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { + self.vk.write(writer, format)?; + self.l0.write(writer, format)?; + self.l_last.write(writer, format)?; + self.l_active_row.write(writer, format)?; + write_polynomial_slice(&self.fixed_values, writer, format)?; + write_polynomial_slice(&self.fixed_polys, writer, format)?; + write_polynomial_slice(&self.fixed_cosets, writer, format)?; + self.permutation.write(writer, format)?; Ok(()) } /// Reads a proving key from a buffer. /// Does so by reading verification key first, and then deserializing the rest of the file into the remaining proving key data. - pub fn read<'params, R: io::Read, ConcreteCircuit: Circuit>( + /// + /// Reads a curve element from the buffer and parses it according to the `format`: + /// - `Processed`: Reads a compressed curve element and decompresses it. + /// Reads a field element in standard form, with endianness specified by the + /// `PrimeField` implementation, and checks that the element is less than the modulus. + /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form. + /// Checks that field elements are less than modulus, and then checks that the point is on the curve. + /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form; + /// does not perform any checks + pub fn read>( reader: &mut R, - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - let vk = VerifyingKey::::read::(reader, params)?; - let l0 = Polynomial::read(reader)?; - let l_last = Polynomial::read(reader)?; - let l_active_row = Polynomial::read(reader)?; - let fixed_values = read_polynomial_vec(reader)?; - let fixed_polys = read_polynomial_vec(reader)?; - let fixed_cosets = read_polynomial_vec(reader)?; - let permutation = permutation::ProvingKey::read(reader)?; + let vk = VerifyingKey::::read::(reader, format)?; + let l0 = Polynomial::read(reader, format)?; + let l_last = Polynomial::read(reader, format)?; + let l_active_row = Polynomial::read(reader, format)?; + let fixed_values = read_polynomial_vec(reader, format)?; + let fixed_polys = read_polynomial_vec(reader, format)?; + let fixed_cosets = read_polynomial_vec(reader, format)?; + let permutation = permutation::ProvingKey::read(reader, format)?; let ev = Evaluator::new(vk.cs()); Ok(Self { vk, @@ -293,31 +353,19 @@ impl ProvingKey { }) } - /// Writes a proving key to a vector of bytes. - pub fn to_bytes(&self) -> Vec { + /// Writes a proving key to a vector of bytes using [`Self::write`]. + pub fn to_bytes(&self, format: SerdeFormat) -> Vec { let mut bytes = Vec::::with_capacity(self.bytes_length()); - Self::write(self, &mut bytes).expect("Writing to vector should not fail"); + Self::write(self, &mut bytes, format).expect("Writing to vector should not fail"); bytes } - /// Reads a proving key from a slice of bytes. - pub fn from_bytes<'params, ConcreteCircuit: Circuit>( + /// Reads a proving key from a slice of bytes using [`Self::read`]. + pub fn from_bytes>( mut bytes: &[u8], - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - Self::read::<_, ConcreteCircuit>(&mut bytes, params) - } - - /// Gets the total number of bytes in the serialization of `self` - fn bytes_length(&self) -> usize { - let scalar_len = C::Scalar::default().to_repr().as_ref().len(); - self.vk.bytes_length() - + 12 - + scalar_len * (self.l0.len() + self.l_last.len() + self.l_active_row.len()) - + polynomial_slice_byte_length(&self.fixed_values) - + polynomial_slice_byte_length(&self.fixed_polys) - + polynomial_slice_byte_length(&self.fixed_cosets) - + self.permutation.bytes_length() + Self::read::<_, ConcreteCircuit>(&mut bytes, format) } } diff --git a/halo2_proofs/src/plonk/permutation.rs b/halo2_proofs/src/plonk/permutation.rs index 7d0d8cc774..05cae2d373 100644 --- a/halo2_proofs/src/plonk/permutation.rs +++ b/halo2_proofs/src/plonk/permutation.rs @@ -2,9 +2,11 @@ use super::circuit::{Any, Column}; use crate::{ arithmetic::CurveAffine, helpers::{ - polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, CurveRead, + polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, + SerdeCurveAffine, SerdePrimeField, }, poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}, + SerdeFormat, }; use ff::PrimeField; @@ -87,17 +89,26 @@ impl VerifyingKey { &self.commitments } - pub(crate) fn write(&self, writer: &mut W) -> io::Result<()> { + pub(crate) fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> + where + C: SerdeCurveAffine, + { for commitment in &self.commitments { - writer.write_all(commitment.to_bytes().as_ref())?; + commitment.write(writer, format)?; } - Ok(()) } - pub(crate) fn read(reader: &mut R, argument: &Argument) -> io::Result { + pub(crate) fn read( + reader: &mut R, + argument: &Argument, + format: SerdeFormat, + ) -> io::Result + where + C: SerdeCurveAffine, + { let commitments = (0..argument.columns.len()) - .map(|_| C::read(reader)) + .map(|_| C::read(reader, format)) .collect::, _>>()?; Ok(VerifyingKey { commitments }) } @@ -115,12 +126,15 @@ pub(crate) struct ProvingKey { pub(super) cosets: Vec>, } -impl ProvingKey { +impl ProvingKey +where + C::Scalar: SerdePrimeField, +{ /// Reads proving key for a single permutation argument from buffer using `Polynomial::read`. - pub(super) fn read(reader: &mut R) -> io::Result { - let permutations = read_polynomial_vec(reader)?; - let polys = read_polynomial_vec(reader)?; - let cosets = read_polynomial_vec(reader)?; + pub(super) fn read(reader: &mut R, format: SerdeFormat) -> io::Result { + let permutations = read_polynomial_vec(reader, format)?; + let polys = read_polynomial_vec(reader, format)?; + let cosets = read_polynomial_vec(reader, format)?; Ok(ProvingKey { permutations, polys, @@ -129,13 +143,19 @@ impl ProvingKey { } /// Writes proving key for a single permutation argument to buffer using `Polynomial::write`. - pub(super) fn write(&self, writer: &mut W) -> io::Result<()> { - write_polynomial_slice(&self.permutations, writer)?; - write_polynomial_slice(&self.polys, writer)?; - write_polynomial_slice(&self.cosets, writer)?; + pub(super) fn write( + &self, + writer: &mut W, + format: SerdeFormat, + ) -> io::Result<()> { + write_polynomial_slice(&self.permutations, writer, format)?; + write_polynomial_slice(&self.polys, writer, format)?; + write_polynomial_slice(&self.cosets, writer, format)?; Ok(()) } +} +impl ProvingKey { /// Gets the total number of bytes in the serialization of `self` pub(super) fn bytes_length(&self) -> usize { polynomial_slice_byte_length(&self.permutations) diff --git a/halo2_proofs/src/poly.rs b/halo2_proofs/src/poly.rs index 1e2ac6366c..44cde43dd9 100644 --- a/halo2_proofs/src/poly.rs +++ b/halo2_proofs/src/poly.rs @@ -5,6 +5,7 @@ use crate::arithmetic::parallelize; use crate::helpers::SerdePrimeField; use crate::plonk::Assigned; +use crate::SerdeFormat; use ff::PrimeField; use group::ff::{BatchInvert, Field}; @@ -146,15 +147,15 @@ impl Polynomial { } } -impl Polynomial { +impl Polynomial { /// Reads polynomial from buffer using `SerdePrimeField::read`. - pub(crate) fn read(reader: &mut R) -> io::Result { - let mut poly_len_be_bytes = [0u8; 4]; - reader.read_exact(&mut poly_len_be_bytes)?; - let poly_len = u32::from_be_bytes(poly_len_be_bytes); + pub(crate) fn read(reader: &mut R, format: SerdeFormat) -> io::Result { + let mut poly_len = [0u8; 4]; + reader.read_exact(&mut poly_len)?; + let poly_len = u32::from_be_bytes(poly_len); (0..poly_len) - .map(|_| F::read(reader)) + .map(|_| F::read(reader, format)) .collect::>>() .map(|values| Self { values, @@ -163,10 +164,14 @@ impl Polynomial { } /// Writes polynomial to buffer using `SerdePrimeField::write`. - pub(crate) fn write(&self, writer: &mut W) -> io::Result<()> { + pub(crate) fn write( + &self, + writer: &mut W, + format: SerdeFormat, + ) -> io::Result<()> { writer.write_all(&(self.values.len() as u32).to_be_bytes())?; for value in self.values.iter() { - value.write(writer)?; + value.write(writer, format)?; } Ok(()) } diff --git a/halo2_proofs/src/poly/kzg/commitment.rs b/halo2_proofs/src/poly/kzg/commitment.rs index 3e8cce6d09..03f6340200 100644 --- a/halo2_proofs/src/poly/kzg/commitment.rs +++ b/halo2_proofs/src/poly/kzg/commitment.rs @@ -1,9 +1,10 @@ use crate::arithmetic::{ best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, FieldExt, Group, }; -use crate::helpers::CurveRead; +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier, MSM}; use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; +use crate::SerdeFormat; use ff::{Field, PrimeField}; use group::{prime::PrimeCurveAffine, Curve, Group as _}; @@ -34,7 +35,11 @@ pub struct KZGCommitmentScheme { _marker: PhantomData, } -impl CommitmentScheme for KZGCommitmentScheme { +impl CommitmentScheme for KZGCommitmentScheme +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type Scalar = E::Scalar; type Curve = E::G1Affine; @@ -132,6 +137,111 @@ impl ParamsKZG { pub fn s_g2(&self) -> E::G2Affine { self.s_g2 } + + /// Writes parameters to buffer + pub fn write_custom(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> + where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, + { + writer.write_all(&self.k.to_le_bytes())?; + for el in self.g.iter() { + el.write(writer, format)?; + } + for el in self.g_lagrange.iter() { + el.write(writer, format)?; + } + self.g2.write(writer, format)?; + self.s_g2.write(writer, format)?; + Ok(()) + } + + /// Reads params from a buffer. + pub fn read_custom(reader: &mut R, format: SerdeFormat) -> io::Result + where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, + { + let mut k = [0u8; 4]; + reader.read_exact(&mut k[..])?; + let k = u32::from_le_bytes(k); + let n = 1 << k; + + let (g, g_lagrange) = match format { + SerdeFormat::Processed => { + use group::GroupEncoding; + let load_points_from_file_parallelly = + |reader: &mut R| -> io::Result>> { + let mut points_compressed = + vec![<::G1Affine as GroupEncoding>::Repr::default(); n]; + for points_compressed in points_compressed.iter_mut() { + reader.read_exact((*points_compressed).as_mut())?; + } + + let mut points = vec![Option::::None; n]; + parallelize(&mut points, |points, chunks| { + for (i, point) in points.iter_mut().enumerate() { + *point = Option::from(E::G1Affine::from_bytes( + &points_compressed[chunks + i], + )); + } + }); + Ok(points) + }; + + let g = load_points_from_file_parallelly(reader)?; + let g: Vec<::G1Affine> = g + .iter() + .map(|point| { + point.ok_or_else(|| { + io::Error::new(io::ErrorKind::Other, "invalid point encoding") + }) + }) + .collect::>()?; + let g_lagrange = load_points_from_file_parallelly(reader)?; + let g_lagrange: Vec<::G1Affine> = g_lagrange + .iter() + .map(|point| { + point.ok_or_else(|| { + io::Error::new(io::ErrorKind::Other, "invalid point encoding") + }) + }) + .collect::>()?; + (g, g_lagrange) + } + SerdeFormat::RawBytes => { + let g = (0..n) + .map(|_| ::read(reader, format)) + .collect::, _>>()?; + let g_lagrange = (0..n) + .map(|_| ::read(reader, format)) + .collect::, _>>()?; + (g, g_lagrange) + } + SerdeFormat::RawBytesUnchecked => { + // avoid try branching for performance + let g = (0..n) + .map(|_| ::read(reader, format).unwrap()) + .collect::>(); + let g_lagrange = (0..n) + .map(|_| ::read(reader, format).unwrap()) + .collect::>(); + (g, g_lagrange) + } + }; + + let g2 = E::G2Affine::read(reader, format)?; + let s_g2 = E::G2Affine::read(reader, format)?; + + Ok(Self { + k, + n: n as u64, + g, + g_lagrange, + g2, + s_g2, + }) + } } // TODO: see the issue at https://github.com/appliedzkp/halo2/issues/45 @@ -139,7 +249,11 @@ impl ParamsKZG { /// KZG multi-open verification parameters pub type ParamsVerifierKZG = ParamsKZG; -impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG { +impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type MSM = MSMKZG; fn k(&self) -> u32 { @@ -179,79 +293,27 @@ impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG { /// Writes params to a buffer. fn write(&self, writer: &mut W) -> io::Result<()> { - use group::GroupEncoding; - writer.write_all(&self.k.to_le_bytes())?; - for el in self.g.iter() { - writer.write_all(el.to_bytes().as_ref())?; - } - for el in self.g_lagrange.iter() { - writer.write_all(el.to_bytes().as_ref())?; - } - writer.write_all(self.g2.to_bytes().as_ref())?; - writer.write_all(self.s_g2.to_bytes().as_ref())?; - Ok(()) + self.write_custom(writer, SerdeFormat::RawBytes) } /// Reads params from a buffer. fn read(reader: &mut R) -> io::Result { - use group::GroupEncoding; - - let mut k = [0u8; 4]; - reader.read_exact(&mut k[..])?; - let k = u32::from_le_bytes(k); - let n = 1 << k; - - let load_points_from_file_parallelly = - |reader: &mut R| -> io::Result>> { - let mut points_compressed = - vec![<::G1Affine as GroupEncoding>::Repr::default(); n]; - for points_compressed in points_compressed.iter_mut() { - reader.read_exact((*points_compressed).as_mut())?; - } - - let mut points = vec![Option::::None; n]; - parallelize(&mut points, |points, chunks| { - for (i, point) in points.iter_mut().enumerate() { - *point = - Option::from(E::G1Affine::from_bytes(&points_compressed[chunks + i])); - } - }); - Ok(points) - }; - - let g = load_points_from_file_parallelly(reader)?; - let g: Vec<::G1Affine> = g - .iter() - .map(|point| { - point.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding")) - }) - .collect::>()?; - - let g_lagrange = load_points_from_file_parallelly(reader)?; - let g_lagrange: Vec<::G1Affine> = g_lagrange - .iter() - .map(|point| { - point.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding")) - }) - .collect::>()?; - - let g2 = E::G2Affine::read(reader)?; - let s_g2 = E::G2Affine::read(reader)?; - - Ok(Self { - k, - n: n as u64, - g, - g_lagrange, - g2, - s_g2, - }) + Self::read_custom(reader, SerdeFormat::RawBytes) } } -impl<'params, E: Engine + Debug> ParamsVerifier<'params, E::G1Affine> for ParamsKZG {} +impl<'params, E: Engine + Debug> ParamsVerifier<'params, E::G1Affine> for ParamsKZG +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ +} -impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZG { +impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZG +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type ParamsVerifier = ParamsVerifierKZG; fn verifier_params(&'params self) -> &'params Self::ParamsVerifier { @@ -278,11 +340,9 @@ impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZ #[cfg(test)] mod test { - use crate::arithmetic::{ best_fft, best_multiexp, parallelize, CurveAffine, CurveExt, FieldExt, Group, }; - use crate::helpers::CurveRead; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::{Blind, CommitmentScheme, Params, MSM}; use crate::poly::kzg::commitment::{ParamsKZG, ParamsVerifierKZG}; diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs index e5077b1b58..e7bff84ade 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs @@ -1,6 +1,6 @@ use super::{construct_intermediate_sets, ChallengeV, Query}; use crate::arithmetic::{eval_polynomial, kate_division, powers, CurveAffine, FieldExt}; - +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::Prover; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -27,7 +27,11 @@ pub struct ProverGWC<'params, E: Engine> { } /// Create a multi-opening proof -impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverGWC<'params, E> { +impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverGWC<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ const QUERY_INSTANCE: bool = false; fn new(params: &'params ParamsKZG) -> Self { diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs index 8f9d348942..1ec003d638 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use super::{construct_intermediate_sets, ChallengeU, ChallengeV}; use crate::arithmetic::{eval_polynomial, lagrange_interpolate, powers, CurveAffine, FieldExt}; - +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::Verifier; use crate::poly::commitment::MSM; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -30,8 +30,11 @@ pub struct VerifierGWC<'params, E: Engine> { params: &'params ParamsKZG, } -impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme> - for VerifierGWC<'params, E> +impl<'params, E> Verifier<'params, KZGCommitmentScheme> for VerifierGWC<'params, E> +where + E: MultiMillerLoop + Debug, + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Guard = GuardKZG<'params, E>; type MSMAccumulator = DualMSM<'params, E>; diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs index b916228857..3206364b8f 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs @@ -5,7 +5,7 @@ use crate::arithmetic::{ eval_polynomial, evaluate_vanishing_polynomial, kate_division, lagrange_interpolate, parallelize, powers, CurveAffine, FieldExt, }; - +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, ParamsProver, Prover}; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use crate::poly::query::{PolynomialPointer, ProverQuery}; @@ -104,6 +104,9 @@ impl<'a, E: Engine> ProverSHPLONK<'a, E> { /// Create a multi-opening proof impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverSHPLONK<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { const QUERY_INSTANCE: bool = false; diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs index 75626d74c6..11ffa880ef 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs @@ -7,6 +7,7 @@ use crate::arithmetic::{ eval_polynomial, evaluate_vanishing_polynomial, lagrange_interpolate, powers, CurveAffine, FieldExt, }; +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::Verifier; use crate::poly::commitment::MSM; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -33,8 +34,11 @@ pub struct VerifierSHPLONK<'params, E: Engine> { params: &'params ParamsKZG, } -impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme> - for VerifierSHPLONK<'params, E> +impl<'params, E> Verifier<'params, KZGCommitmentScheme> for VerifierSHPLONK<'params, E> +where + E: MultiMillerLoop + Debug, + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Guard = GuardKZG<'params, E>; type MSMAccumulator = DualMSM<'params, E>; diff --git a/halo2_proofs/src/poly/kzg/strategy.rs b/halo2_proofs/src/poly/kzg/strategy.rs index 896760067d..ca4b4fb18a 100644 --- a/halo2_proofs/src/poly/kzg/strategy.rs +++ b/halo2_proofs/src/poly/kzg/strategy.rs @@ -6,6 +6,7 @@ use super::{ multiopen::VerifierGWC, }; use crate::{ + helpers::SerdeCurveAffine, plonk::Error, poly::{ commitment::{Verifier, MSM}, @@ -29,7 +30,12 @@ pub struct GuardKZG<'params, E: MultiMillerLoop + Debug> { } /// Define accumulator type as `DualMSM` -impl<'params, E: MultiMillerLoop + Debug> Guard> for GuardKZG<'params, E> { +impl<'params, E> Guard> for GuardKZG<'params, E> +where + E: MultiMillerLoop + Debug, + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type MSMAccumulator = DualMSM<'params, E>; } @@ -85,6 +91,9 @@ impl< Guard = GuardKZG<'params, E>, >, > VerificationStrategy<'params, KZGCommitmentScheme, V> for AccumulatorStrategy<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Output = Self; @@ -120,6 +129,9 @@ impl< Guard = GuardKZG<'params, E>, >, > VerificationStrategy<'params, KZGCommitmentScheme, V> for SingleStrategy<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Output = ();