//! This module provides an implementation of a variant of (Turbo)[PLONK][plonk] //! that is designed specifically for the polynomial commitment scheme described //! in the [Halo][halo] paper. //! //! [halo]: https://eprint.iacr.org/2019/1021 //! [plonk]: https://eprint.iacr.org/2019/953 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::{ commitment::Params, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, PinnedEvaluationDomain, Polynomial, }; use crate::transcript::{ChallengeScalar, EncodedChallenge, Transcript}; mod assigned; mod circuit; mod error; mod keygen; mod lookup; pub(crate) mod permutation; mod vanishing; mod prover; mod verifier; pub use assigned::*; pub use circuit::*; pub use error::*; pub use keygen::*; pub use prover::*; pub use verifier::*; use std::io; /// This is a verifying key which allows for the verification of proofs for a /// particular circuit. #[derive(Clone, Debug)] pub struct VerifyingKey { domain: EvaluationDomain, fixed_commitments: Vec, permutation: permutation::VerifyingKey, cs: ConstraintSystem, /// Cached maximum degree of `cs` (which doesn't change after construction). cs_degree: usize, /// The representative of this `VerifyingKey` in transcripts. transcript_repr: C::Scalar, selectors: Vec>, } impl VerifyingKey where C::Scalar: FromUniformBytes<64>, { /// Writes a verifying key to a buffer. pub fn 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>( reader: &mut R, params: &Params, ) -> io::Result { let (domain, cs, _) = keygen::create_domain::(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::>()?; 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![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::>()?; 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 { let mut bytes = Vec::::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>( mut bytes: &[u8], params: &Params, ) -> io::Result { 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, fixed_commitments: Vec, permutation: permutation::VerifyingKey, cs: ConstraintSystem, selectors: Vec>, ) -> Self { // Compute cached values. let cs_degree = cs.degree(); let mut vk = Self { domain, fixed_commitments, permutation, cs, cs_degree, // Temporary, this is not pinned. transcript_repr: C::Scalar::ZERO, selectors, }; let mut hasher = Blake2bParams::new() .hash_length(64) .personal(b"Halo2-Verify-Key") .to_state(); let s = format!("{:?}", vk.pinned()); hasher.update(&(s.len() as u64).to_le_bytes()); hasher.update(s.as_bytes()); // Hash in final Blake2bState vk.transcript_repr = C::Scalar::from_uniform_bytes(hasher.finalize().as_array()); vk } } impl VerifyingKey { /// Hashes a verification key into a transcript. pub fn hash_into, T: Transcript>( &self, transcript: &mut T, ) -> io::Result<()> { transcript.common_scalar(self.transcript_repr)?; Ok(()) } /// Obtains a pinned representation of this verification key that contains /// the minimal information necessary to reconstruct the verification key. pub fn pinned(&self) -> PinnedVerificationKey<'_, C> { PinnedVerificationKey { base_modulus: C::Base::MODULUS, scalar_modulus: C::Scalar::MODULUS, domain: self.domain.pinned(), fixed_commitments: &self.fixed_commitments, permutation: &self.permutation, cs: self.cs.pinned(), } } } /// Minimal representation of a verification key that can be used to identify /// its active contents. #[allow(dead_code)] #[derive(Debug)] pub struct PinnedVerificationKey<'a, C: CurveAffine> { base_modulus: &'static str, scalar_modulus: &'static str, domain: PinnedEvaluationDomain<'a, C::Scalar>, cs: PinnedConstraintSystem<'a, C::Scalar>, fixed_commitments: &'a Vec, permutation: &'a permutation::VerifyingKey, } /// This is a proving key which allows for the creation of proofs for a /// particular circuit. #[derive(Clone, Debug)] pub struct ProvingKey { vk: VerifyingKey, l0: Polynomial, l_blind: Polynomial, l_last: Polynomial, fixed_values: Vec>, fixed_polys: Vec>, fixed_cosets: Vec>, permutation: permutation::ProvingKey, } impl ProvingKey { /// Get the underlying [`VerifyingKey`]. pub fn get_vk(&self) -> &VerifyingKey { &self.vk } } impl VerifyingKey { /// Get the underlying [`EvaluationDomain`]. pub fn get_domain(&self) -> &EvaluationDomain { &self.domain } } #[derive(Clone, Copy, Debug)] struct Theta; type ChallengeTheta = ChallengeScalar; #[derive(Clone, Copy, Debug)] struct Beta; type ChallengeBeta = ChallengeScalar; #[derive(Clone, Copy, Debug)] struct Gamma; type ChallengeGamma = ChallengeScalar; #[derive(Clone, Copy, Debug)] struct Y; type ChallengeY = ChallengeScalar; #[derive(Clone, Copy, Debug)] struct X; type ChallengeX = ChallengeScalar;