Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature to serialize/deserialize KZG params, verifying key, and proving key into uncompressed Montgomery form #111

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions halo2_proofs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -68,11 +68,13 @@ rand_core = { version = "0.6", default-features = false, features = ["getrandom"
getrandom = { version = "0.2", features = ["js"] }

[features]
default = ["batch"]
default = ["batch", "serde-raw"]
dev-graph = ["plotters", "tabbycat"]
gadget-traces = ["backtrace"]
sanity-checks = []
batch = ["rand_core/getrandom"]
serde-raw = []
raw-unchecked = ["serde-raw"]

[lib]
bench = false
Expand Down
2 changes: 1 addition & 1 deletion halo2_proofs/examples/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fn main() {

let f = File::open("serialization-test.pk").unwrap();
let mut reader = BufReader::new(f);
let pk = ProvingKey::<G1Affine>::read::<_, StandardPlonk>(&mut reader, &params).unwrap();
let pk = ProvingKey::<G1Affine>::read::<_, StandardPlonk>(&mut reader).unwrap();

std::fs::remove_file("serialization-test.pk").unwrap();

Expand Down
81 changes: 72 additions & 9 deletions halo2_proofs/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::poly::Polynomial;
use ff::PrimeField;
use halo2curves::CurveAffine;
#[cfg(feature = "serde-raw")]
use halo2curves::serde::SerdeObject;
use halo2curves::{pairing::Engine, CurveAffine};
use std::io;

// 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`.
Expand All @@ -13,10 +16,48 @@ pub(crate) trait CurveRead: CurveAffine {
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid point encoding in proof"))
}
}

impl<C: CurveAffine> CurveRead for C {}

pub(crate) trait SerdePrimeField: PrimeField {
#[cfg(not(feature = "serde-raw"))]
pub trait SerdeCurveAffine: CurveAffine {
/// Reads a compressed element from the buffer and attempts to parse it
/// using `from_bytes`.
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
<Self as CurveRead>::read(reader)
}
/// Writes a curve element as a compressed affine point in bytes.
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(self.to_bytes().as_ref())
}
}
#[cfg(not(feature = "serde-raw"))]
impl<C: CurveAffine> SerdeCurveAffine for C {}

#[cfg(feature = "serde-raw")]
pub trait SerdeCurveAffine: CurveAffine + SerdeObject {
/// Reads a curve element from raw bytes.
/// The curve element is stored exactly as it is in memory (two field elements in Montgomery representation).
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
#[cfg(feature = "raw-unchecked")]
{
Ok(Self::read_raw_unchecked(reader))
}
#[cfg(not(feature = "raw-unchecked"))]
{
Self::read_raw(reader)
}
}
/// Writes a curve element into raw bytes.
/// The curve element is stored exactly as it is in memory (two field elements in Montgomery representation).
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
self.write_raw(writer)
}
}
#[cfg(feature = "serde-raw")]
impl<C: CurveAffine + SerdeObject> SerdeCurveAffine for C {}

#[cfg(not(feature = "serde-raw"))]
pub trait SerdePrimeField: PrimeField {
/// Reads a field element as bytes from the buffer using `from_repr`.
/// Endianness is specified by `PrimeField` implementation.
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
Expand All @@ -33,9 +74,31 @@ pub(crate) trait SerdePrimeField: PrimeField {
writer.write_all(self.to_repr().as_ref())
}
}

#[cfg(not(feature = "serde-raw"))]
impl<F: PrimeField> SerdePrimeField for F {}

#[cfg(feature = "serde-raw")]
pub trait SerdePrimeField: PrimeField + SerdeObject {
/// Reads a field element from raw bytes in its internal Montgomery representation.
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
#[cfg(feature = "raw-unchecked")]
{
Ok(Self::read_raw_unchecked(reader))
}
#[cfg(not(feature = "raw-unchecked"))]
{
Self::read_raw(reader)
}
}
/// Writes a field element into raw bytes in its internal Montgomery representation,
/// WITHOUT performing the expensive Montgomery reduction.
fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
self.write_raw(writer)
}
}
#[cfg(feature = "serde-raw")]
impl<F: PrimeField + SerdeObject> SerdePrimeField for F {}

/// Convert a slice of `bool` into a `u8`.
///
/// Panics if the slice has length greater than 8.
Expand All @@ -56,20 +119,20 @@ pub fn unpack(byte: u8, bits: &mut [bool]) {
}

/// Reads a vector of polynomials from buffer
pub(crate) fn read_polynomial_vec<R: io::Read, F: PrimeField, B>(
pub(crate) fn read_polynomial_vec<R: io::Read, F: SerdePrimeField, B>(
reader: &mut R,
) -> io::Result<Vec<Polynomial<F, B>>> {
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::<F, B>::read(reader))
.collect::<io::Result<Vec<_>>>()
}

/// Writes a slice of polynomials to buffer
pub(crate) fn write_polynomial_slice<W: io::Write, F: PrimeField, B>(
pub(crate) fn write_polynomial_slice<W: io::Write, F: SerdePrimeField, B>(
slice: &[Polynomial<F, B>],
writer: &mut W,
) -> io::Result<()> {
Expand Down
81 changes: 43 additions & 38 deletions halo2_proofs/src/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -57,12 +57,16 @@ pub struct VerifyingKey<C: CurveAffine> {
selectors: Vec<Vec<bool>>,
}

impl<C: CurveAffine> VerifyingKey<C> {
impl<C: SerdeCurveAffine> VerifyingKey<C>
where
C::Scalar: SerdePrimeField,
{
/// Writes a verifying key to a buffer.
pub fn write<W: io::Write>(&self, writer: &mut W) -> 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)?;
}
self.permutation.write(writer)?;

Expand All @@ -77,14 +81,16 @@ impl<C: CurveAffine> VerifyingKey<C> {
}

/// Reads a verification key from a buffer.
pub fn read<'params, R: io::Read, ConcreteCircuit: Circuit<C::Scalar>>(
pub fn read<R: io::Read, ConcreteCircuit: Circuit<C::Scalar>>(
reader: &mut R,
params: &impl Params<'params, C>,
) -> io::Result<Self> {
let (domain, cs, _) = keygen::create_domain::<C, ConcreteCircuit>(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::<C, ConcreteCircuit>(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))
Expand All @@ -93,7 +99,7 @@ impl<C: CurveAffine> VerifyingKey<C> {
let permutation = permutation::VerifyingKey::read(reader, &cs.permutation)?;

// read selectors
let selectors: Vec<Vec<bool>> = vec![vec![false; params.n() as usize]; cs.num_selectors]
let selectors: Vec<Vec<bool>> = vec![vec![false; 1 << k]; cs.num_selectors]
.into_iter()
.map(|mut selector| {
let mut selector_bytes = vec![0u8; (selector.len() + 7) / 8];
Expand All @@ -103,8 +109,7 @@ impl<C: CurveAffine> VerifyingKey<C> {
}
Ok(selector)
})
.collect::<io::Result<Vec<Vec<bool>>>>()
.unwrap();
.collect::<io::Result<_>>()?;
let (cs, _) = cs.compress_selectors(selectors.clone());

Ok(Self::from_parts(
Expand All @@ -124,15 +129,14 @@ impl<C: CurveAffine> VerifyingKey<C> {
}

/// Reads a verification key from a slice of bytes.
pub fn from_bytes<'params, ConcreteCircuit: Circuit<C::Scalar>>(
mut bytes: &[u8],
params: &impl Params<'params, C>,
) -> io::Result<Self> {
Self::read::<_, ConcreteCircuit>(&mut bytes, params)
pub fn from_bytes<ConcreteCircuit: Circuit<C::Scalar>>(mut bytes: &[u8]) -> io::Result<Self> {
Self::read::<_, ConcreteCircuit>(&mut bytes)
}
}

impl<C: CurveAffine> VerifyingKey<C> {
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
Expand Down Expand Up @@ -251,6 +255,23 @@ impl<C: CurveAffine> ProvingKey<C> {
&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<C: SerdeCurveAffine> ProvingKey<C>
where
C::Scalar: SerdePrimeField,
{
/// Writes a proving key to a buffer.
/// 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<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
Expand All @@ -267,11 +288,10 @@ impl<C: CurveAffine> ProvingKey<C> {

/// 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<C::Scalar>>(
pub fn read<R: io::Read, ConcreteCircuit: Circuit<C::Scalar>>(
reader: &mut R,
params: &impl Params<'params, C>,
) -> io::Result<Self> {
let vk = VerifyingKey::<C>::read::<R, ConcreteCircuit>(reader, params)?;
let vk = VerifyingKey::<C>::read::<R, ConcreteCircuit>(reader)?;
let l0 = Polynomial::read(reader)?;
let l_last = Polynomial::read(reader)?;
let l_active_row = Polynomial::read(reader)?;
Expand Down Expand Up @@ -301,23 +321,8 @@ impl<C: CurveAffine> ProvingKey<C> {
}

/// Reads a proving key from a slice of bytes.
pub fn from_bytes<'params, ConcreteCircuit: Circuit<C::Scalar>>(
mut bytes: &[u8],
params: &impl Params<'params, C>,
) -> io::Result<Self> {
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()
pub fn from_bytes<ConcreteCircuit: Circuit<C::Scalar>>(mut bytes: &[u8]) -> io::Result<Self> {
Self::read::<_, ConcreteCircuit>(&mut bytes)
}
}

Expand Down
23 changes: 17 additions & 6 deletions halo2_proofs/src/plonk/permutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ 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},
};
Expand Down Expand Up @@ -87,15 +88,20 @@ impl<C: CurveAffine> VerifyingKey<C> {
&self.commitments
}

pub(crate) fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
pub(crate) fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()>
where
C: SerdeCurveAffine,
{
for commitment in &self.commitments {
writer.write_all(commitment.to_bytes().as_ref())?;
commitment.write(writer)?;
}

Ok(())
}

pub(crate) fn read<R: io::Read>(reader: &mut R, argument: &Argument) -> io::Result<Self> {
pub(crate) fn read<R: io::Read>(reader: &mut R, argument: &Argument) -> io::Result<Self>
where
C: SerdeCurveAffine,
{
let commitments = (0..argument.columns.len())
.map(|_| C::read(reader))
.collect::<Result<Vec<_>, _>>()?;
Expand All @@ -115,7 +121,10 @@ pub(crate) struct ProvingKey<C: CurveAffine> {
pub(super) cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
}

impl<C: CurveAffine> ProvingKey<C> {
impl<C: SerdeCurveAffine> ProvingKey<C>
where
C::Scalar: SerdePrimeField,
{
/// Reads proving key for a single permutation argument from buffer using `Polynomial::read`.
pub(super) fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let permutations = read_polynomial_vec(reader)?;
Expand All @@ -135,7 +144,9 @@ impl<C: CurveAffine> ProvingKey<C> {
write_polynomial_slice(&self.cosets, writer)?;
Ok(())
}
}

impl<C: CurveAffine> ProvingKey<C> {
/// Gets the total number of bytes in the serialization of `self`
pub(super) fn bytes_length(&self) -> usize {
polynomial_slice_byte_length(&self.permutations)
Expand Down
8 changes: 4 additions & 4 deletions halo2_proofs/src/poly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ impl<F, B> Polynomial<F, B> {
}
}

impl<F: PrimeField, B> Polynomial<F, B> {
impl<F: SerdePrimeField, B> Polynomial<F, B> {
/// Reads polynomial from buffer using `SerdePrimeField::read`.
pub(crate) fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
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);
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))
Expand Down
Loading