diff --git a/src/plonk.rs b/src/plonk.rs index 7844d287..bb00b2c6 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -5,11 +5,14 @@ //! [halo]: https://eprint.iacr.org/2019/1021 //! [plonk]: https://eprint.iacr.org/2019/953 -use crate::arithmetic::CurveAffine; +use blake2b_simd::Params as Blake2bParams; + +use crate::arithmetic::{CurveAffine, FieldExt}; use crate::poly::{ commitment::Params, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, }; use crate::transcript::{ChallengeScalar, Transcript}; +use std::convert::TryInto; mod circuit; mod keygen; @@ -77,13 +80,38 @@ impl VerifyingKey { /// Hashes a verification key into a transcript. pub fn hash>(&self, transcript: &mut T) -> io::Result<()> { + let mut hasher = Blake2bParams::new() + .hash_length(64) + .personal(C::BLAKE2B_PERSONALIZATION) + .to_state(); + + // Hash in constants in the domain which influence the proof + let domain_hash = &self.domain.hash(&mut hasher); + transcript.common_scalar(C::Scalar::from_bytes_wide(domain_hash))?; + + // Hash in `ConstraintSystem` + let cs_hash = &self.cs.hash(&mut hasher); + transcript.common_scalar(C::Scalar::from_bytes_wide(cs_hash))?; + + // Hash in vector of fixed commitments + hasher.update(b"num_fixed_commitments"); + hasher.update(&self.fixed_commitments.len().to_le_bytes()); for commitment in &self.fixed_commitments { transcript.common_point(*commitment)?; } + + // Hash in vector of permutation arguments + hasher.update(b"num_permutations"); + hasher.update(&self.permutations.len().to_le_bytes()); for permutation in &self.permutations { permutation.hash(transcript)?; } + // Hash in final Blake2bState + transcript.common_scalar(C::Scalar::from_bytes_wide( + hasher.finalize().as_bytes().try_into().unwrap(), + ))?; + Ok(()) } } diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index e8dfcfcc..020ee35d 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -1,8 +1,9 @@ +use blake2b_simd::State as Blake2bState; use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; use std::{ - convert::TryFrom, + convert::{TryFrom, TryInto}, ops::{Neg, Sub}, }; @@ -10,7 +11,7 @@ use super::{lookup, permutation, Error}; use crate::poly::Rotation; /// A column type -pub trait ColumnType: 'static + Sized {} +pub trait ColumnType: 'static + Sized + std::fmt::Debug {} /// A column with an index and type #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] @@ -27,6 +28,11 @@ impl Column { pub(crate) fn column_type(&self) -> &C { &self.column_type } + + pub(crate) fn hash(&self, hasher: &mut Blake2bState) -> [u8; 64] { + hasher.update(&format!("{:?}", self).as_bytes()); + hasher.finalize().as_bytes().try_into().unwrap() + } } /// An advice column @@ -317,6 +323,12 @@ impl Expression { Expression::Scaled(poly, _) => poly.degree(), } } + + /// Hash an Expression into a Blake2bState + pub fn hash(&self, hasher: &mut Blake2bState) -> [u8; 64] { + hasher.update(&format!("{:?}", self).as_bytes()); + hasher.finalize().as_bytes().try_into().unwrap() + } } impl Neg for Expression { @@ -598,4 +610,70 @@ impl ConstraintSystem { self.num_instance_columns += 1; tmp } + + /// Hashes the `ConstraintSystem` into a `u64`. + pub fn hash(&self, mut hasher: &mut Blake2bState) -> [u8; 64] { + hasher.update(b"num_fixed_columns"); + hasher.update(&self.num_fixed_columns.to_le_bytes()); + + hasher.update(b"num_advice_columns"); + hasher.update(&self.num_advice_columns.to_le_bytes()); + + hasher.update(b"num_aux_columns"); + hasher.update(&self.num_aux_columns.to_le_bytes()); + + hasher.update(b"num_gates"); + hasher.update(&self.gates.len().to_le_bytes()); + for gate in self.gates.iter() { + hasher.update(gate.0.to_owned().as_bytes()); + gate.1.hash(&mut hasher); + } + + hasher.update(b"num_advice_queries"); + hasher.update(&self.advice_queries.len().to_le_bytes()); + for query in self.advice_queries.iter() { + query.0.hash(&mut hasher); + query.1.hash(&mut hasher); + } + + hasher.update(b"num_aux_queries"); + hasher.update(&self.aux_queries.len().to_le_bytes()); + for query in self.aux_queries.iter() { + query.0.hash(&mut hasher); + query.1.hash(&mut hasher); + } + + hasher.update(b"num_fixed_queries"); + hasher.update(&self.fixed_queries.len().to_le_bytes()); + for query in self.fixed_queries.iter() { + query.0.hash(&mut hasher); + query.1.hash(&mut hasher); + } + + hasher.update(b"num_permutations"); + hasher.update(&self.permutations.len().to_le_bytes()); + for argument in self.permutations.iter() { + hasher.update(&argument.get_columns().len().to_le_bytes()); + for column in argument.get_columns().iter() { + column.hash(&mut hasher); + } + } + + hasher.update(b"num_lookups"); + hasher.update(&self.lookups.len().to_le_bytes()); + for argument in self.lookups.iter() { + hasher.update(&argument.input_columns.len().to_le_bytes()); + hasher.update(&argument.table_columns.len().to_le_bytes()); + for (input, table) in argument + .input_columns + .iter() + .zip(argument.table_columns.iter()) + { + input.hash(&mut hasher); + table.hash(&mut hasher); + } + } + + hasher.finalize().as_bytes().try_into().unwrap() + } } diff --git a/src/poly.rs b/src/poly.rs index 5ac1462c..45088f4e 100644 --- a/src/poly.rs +++ b/src/poly.rs @@ -4,7 +4,9 @@ use crate::arithmetic::parallelize; +use blake2b_simd::State as Blake2bState; use ff::Field; +use std::convert::TryInto; use std::fmt::Debug; use std::marker::PhantomData; use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Mul, RangeFrom, RangeFull, Sub}; @@ -228,4 +230,10 @@ impl Rotation { pub fn next() -> Rotation { Rotation(1) } + + /// Hash Rotation into a Blake2bState + pub fn hash(&self, hasher: &mut Blake2bState) -> [u8; 64] { + hasher.update(&format!("{:?}", self).as_bytes()); + hasher.finalize().as_bytes().try_into().unwrap() + } } diff --git a/src/poly/domain.rs b/src/poly/domain.rs index e8cc41ee..c9a9dff8 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -8,6 +8,9 @@ use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, Rotation}; use ff::{Field, PrimeField}; use std::marker::PhantomData; +use blake2b_simd::State as Blake2bState; +use std::convert::TryInto; + /// This structure contains precomputed constants and other details needed for /// performing operations on an evaluation domain of size $2^k$ and an extended /// domain of size $2^{k} * j$ with $j \neq 0$. @@ -376,4 +379,18 @@ impl EvaluationDomain { pub fn get_quotient_poly_degree(&self) -> usize { self.quotient_poly_degree as usize } + + /// Hashes the constants in the domain which influence the proof into a u64 + pub fn hash(&self, hasher: &mut Blake2bState) -> [u8; 64] { + hasher.update(b"k"); + hasher.update(&self.k.to_le_bytes()); + + hasher.update(b"extended_k"); + hasher.update(&self.extended_k.to_le_bytes()); + + hasher.update(b"omega"); + hasher.update(&self.omega.to_bytes()); + + hasher.finalize().as_bytes().try_into().unwrap() + } }