Compare commits

...

7 Commits

Author SHA1 Message Date
Nalin 1055bfe982
Merge 58e797da93 into 7df93fd855 2024-02-29 11:06:56 -08:00
Daira-Emma Hopwood 7df93fd855
Merge pull request #814 from adria0/fix/mdbook
Fix MD book generation
2024-02-26 23:50:17 +00:00
adria0 daaa638966 fix(mdbook): fix generation 2024-02-22 22:28:36 +01:00
Daira Emma Hopwood 58e797da93 feat: added `to/from_bytes` for `ProvingKey` and `VerifyingKey`
* add `pack`/`unpack` helper functions between `&[bool]` and `u8`.

Extracted from 2c7f288932

Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com>
Signed-off-by: Daira Emma Hopwood <daira@jacaranda.org>
2023-05-01 16:34:40 +01:00
Daira Emma Hopwood bae30538b5 Apply review suggestions for VerifyingKey serialization:
* write an initial 0x01 version byte, and check it on read;
* use little-endian byte order for lengths;
* add length fields before the selectors and the permutation commitments,
  and check their consistency with the expected lengths on read;
* do not write an extra byte for a selector bit vector if the number of
  bits is a multiple of 8;
* ensure that original I/O errors are preserved.

Signed-off-by: Daira Emma Hopwood <daira@jacaranda.org>
2023-05-01 11:00:53 +01:00
Jonathan Wang 3489dcde9e fix: add `num_fixed_commitments` to vkey serialization so correct number
of fixed columns, post selector compression, are read

Signed-off-by: Daira Emma Hopwood <daira@jacaranda.org>
2023-05-01 10:50:00 +01:00
Nalin Bhardwaj 0ca2296921 Vkey serialisation
Signed-off-by: Daira Emma Hopwood <daira@jacaranda.org>
2023-05-01 10:48:24 +01:00
6 changed files with 180 additions and 7 deletions

View File

@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
toolchain: '1.76.0'
override: true
# - name: Setup mdBook
@ -26,7 +26,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: install
args: mdbook --git https://github.com/HollowMan6/mdBook.git --rev 62e01b34c23b957579c04ee1b24b57814ed8a4d5
args: mdbook --git https://github.com/HollowMan6/mdBook.git --rev 5830c9555a4dc051675d17f1fcb04dd0920543e8
- name: Install mdbook-katex and mdbook-pdf
uses: actions-rs/cargo@v1
@ -40,6 +40,11 @@ jobs:
- name: Build halo2 book
run: mdbook build book/
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly-2023-10-05
override: true
- name: Build latest rustdocs
uses: actions-rs/cargo@v1
with:

View File

@ -14,8 +14,6 @@ title = "The halo2 Book"
macros = "macros.txt"
renderers = ["html"]
[output.katex]
[output.html]
[output.html.print]

View File

@ -14,3 +14,22 @@ pub(crate) trait CurveRead: CurveAffine {
}
impl<C: CurveAffine> CurveRead for C {}
/// Converts a slice of `bool` into a `u8`.
///
/// Panics if the slice has length greater than 8.
pub fn pack(bits: &[bool]) -> u8 {
let mut value = 0u8;
assert!(bits.len() <= 8);
for (bit_index, bit) in bits.iter().enumerate() {
value |= (*bit as u8) << bit_index;
}
value
}
/// Writes the first `bits.len()` bits of a `u8` into `bits`.
pub fn unpack(byte: u8, bits: &mut [bool]) {
for (bit_index, bit) in bits.iter_mut().enumerate() {
*bit = (byte >> bit_index) & 1 == 1;
}
}

View File

@ -9,9 +9,10 @@ use blake2b_simd::Params as Blake2bParams;
use group::ff::{Field, FromUniformBytes, PrimeField};
use crate::arithmetic::CurveAffine;
use crate::helpers::{pack, unpack, CurveRead};
use crate::poly::{
Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, PinnedEvaluationDomain,
Polynomial,
commitment::Params, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff,
PinnedEvaluationDomain, Polynomial,
};
use crate::transcript::{ChallengeScalar, EncodedChallenge, Transcript};
@ -47,17 +48,131 @@ pub struct VerifyingKey<C: CurveAffine> {
cs_degree: usize,
/// The representative of this `VerifyingKey` in transcripts.
transcript_repr: C::Scalar,
selectors: Vec<Vec<bool>>,
}
impl<C: CurveAffine> VerifyingKey<C>
where
C::Scalar: FromUniformBytes<64>,
{
/// Writes a verifying key to a buffer.
pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
// Version byte that will be checked on read.
writer.write_all(&[0x01])?;
writer.write_all(&(u32::try_from(self.fixed_commitments.len()).unwrap()).to_le_bytes())?;
for commitment in &self.fixed_commitments {
writer.write_all(commitment.to_bytes().as_ref())?;
}
self.permutation.write(writer)?;
// write self.selectors
writer.write_all(&(u32::try_from(self.selectors.len()).unwrap()).to_le_bytes())?;
for selector in &self.selectors {
// since `selector` is filled with `bool`, we pack them 8 at a time into bytes and then write
for bits in selector.chunks(8) {
writer.write_all(&[pack(bits)])?;
}
}
Ok(())
}
/// Reads a verifying key from a buffer.
pub fn read<R: io::Read, ConcreteCircuit: Circuit<C::Scalar>>(
reader: &mut R,
params: &Params<C>,
) -> io::Result<Self> {
let (domain, cs, _) = keygen::create_domain::<C, ConcreteCircuit>(params);
let mut version_byte = [0u8; 1];
reader.read_exact(&mut version_byte)?;
if 0x01 != version_byte[0] {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"unexpected version byte",
));
}
let mut num_fixed_columns_le_bytes = [0u8; 4];
reader.read_exact(&mut num_fixed_columns_le_bytes)?;
let num_fixed_columns = u32::from_le_bytes(num_fixed_columns_le_bytes);
let fixed_commitments: Vec<_> = (0..num_fixed_columns)
.map(|_| C::read(reader))
.collect::<io::Result<_>>()?;
let permutation = permutation::VerifyingKey::read(reader, &cs.permutation)?;
// read selectors
let mut num_selectors_le_bytes = [0u8; 4];
reader.read_exact(&mut num_selectors_le_bytes)?;
let num_selectors = u32::from_le_bytes(num_selectors_le_bytes);
if cs.num_selectors != num_selectors.try_into().unwrap() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"unexpected number of selectors",
));
}
let selectors: Vec<Vec<bool>> = vec![vec![false; params.n as usize]; cs.num_selectors]
.into_iter()
.map(|mut selector| {
let mut selector_bytes = vec![0u8; (selector.len() + 7) / 8];
reader.read_exact(&mut selector_bytes)?;
for (bits, byte) in selector.chunks_mut(8).zip(selector_bytes) {
unpack(byte, bits);
}
Ok(selector)
})
.collect::<io::Result<_>>()?;
let (cs, _) = cs.compress_selectors(selectors.clone());
Ok(Self::from_parts(
domain,
fixed_commitments,
permutation,
cs,
selectors,
))
}
/// Writes a verifying key to a vector of bytes.
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::<u8>::with_capacity(self.bytes_length());
self.write(&mut bytes)
.expect("Writing to vector should not fail");
bytes
}
/// Reads a verifying key from a slice of bytes.
pub fn from_bytes<ConcreteCircuit: Circuit<C::Scalar>>(
mut bytes: &[u8],
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 {
1 + 4
+ self.fixed_commitments.len() * C::default().to_bytes().as_ref().len()
+ self.permutation.bytes_length()
+ 4
+ self.selectors.len()
* self
.selectors
.get(0)
.map(|selector| (selector.len() + 7) / 8)
.unwrap_or(0)
}
fn from_parts(
domain: EvaluationDomain<C::Scalar>,
fixed_commitments: Vec<C>,
permutation: permutation::VerifyingKey<C>,
cs: ConstraintSystem<C::Scalar>,
selectors: Vec<Vec<bool>>,
) -> Self {
// Compute cached values.
let cs_degree = cs.degree();
@ -70,6 +185,7 @@ where
cs_degree,
// Temporary, this is not pinned.
transcript_repr: C::Scalar::ZERO,
selectors,
};
let mut hasher = Blake2bParams::new()

View File

@ -219,7 +219,7 @@ where
)?;
let mut fixed = batch_invert_assigned(assembly.fixed);
let (cs, selector_polys) = cs.compress_selectors(assembly.selectors);
let (cs, selector_polys) = cs.compress_selectors(assembly.selectors.clone());
fixed.extend(
selector_polys
.into_iter()
@ -240,6 +240,7 @@ where
fixed_commitments,
permutation_vk,
cs,
assembly.selectors,
))
}

View File

@ -8,6 +8,9 @@ pub(crate) mod keygen;
pub(crate) mod prover;
pub(crate) mod verifier;
use crate::helpers::CurveRead;
use std::io;
/// A permutation argument.
#[derive(Debug, Clone)]
pub(crate) struct Argument {
@ -75,6 +78,37 @@ pub(crate) struct VerifyingKey<C: CurveAffine> {
commitments: Vec<C>,
}
impl<C: CurveAffine> VerifyingKey<C> {
pub(crate) fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&(u32::try_from(self.commitments.len()).unwrap()).to_le_bytes())?;
for commitment in &self.commitments {
writer.write_all(commitment.to_bytes().as_ref())?;
}
Ok(())
}
pub(crate) fn read<R: io::Read>(reader: &mut R, argument: &Argument) -> io::Result<Self> {
let mut num_commitments_le_bytes = [0u8; 4];
reader.read_exact(&mut num_commitments_le_bytes)?;
let num_commitments = u32::from_le_bytes(num_commitments_le_bytes);
if argument.columns.len() != num_commitments.try_into().unwrap() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"unexpected number of column commitments",
));
}
let commitments: Vec<_> = (0..argument.columns.len())
.map(|_| C::read(reader))
.collect::<io::Result<_>>()?;
Ok(VerifyingKey { commitments })
}
pub(crate) fn bytes_length(&self) -> usize {
4 + self.commitments.len() * C::default().to_bytes().as_ref().len()
}
}
/// The proving key for a single permutation argument.
#[derive(Clone, Debug)]
pub(crate) struct ProvingKey<C: CurveAffine> {