From 48bfea978207a3d333890d5e64a47ab6c9e7efe4 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 27 Jan 2021 18:30:39 +0800 Subject: [PATCH] Replace DummyHash with BLAKE2b --- benches/plonk.rs | 10 +-- examples/performance_model.rs | 8 +-- src/plonk.rs | 10 +-- src/poly/commitment.rs | 6 +- src/poly/multiopen.rs | 6 +- src/transcript.rs | 122 +++++++++++++--------------------- 6 files changed, 65 insertions(+), 97 deletions(-) diff --git a/benches/plonk.rs b/benches/plonk.rs index cdc9e6c4..7b7bbb48 100644 --- a/benches/plonk.rs +++ b/benches/plonk.rs @@ -3,10 +3,10 @@ extern crate criterion; extern crate halo2; use halo2::arithmetic::FieldExt; -use halo2::pasta::{EqAffine, Fp, Fq}; +use halo2::pasta::{EqAffine, Fp}; use halo2::plonk::*; use halo2::poly::{commitment::Params, Rotation}; -use halo2::transcript::{DummyHashRead, DummyHashWrite}; +use halo2::transcript::{Blake2bRead, Blake2bWrite}; use std::marker::PhantomData; @@ -242,7 +242,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { }; // Create a proof - let mut transcript = DummyHashWrite::init(vec![], Fq::one()); + let mut transcript = Blake2bWrite::init(vec![]); create_proof(¶ms, &pk, &[circuit], &[], &mut transcript) .expect("proof generation should not fail") }); @@ -254,7 +254,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { }; // Create a proof - let mut transcript = DummyHashWrite::init(vec![], Fq::one()); + let mut transcript = Blake2bWrite::init(vec![]); create_proof(¶ms, &pk, &[circuit], &[], &mut transcript) .expect("proof generation should not fail"); let proof = transcript.finalize(); @@ -262,7 +262,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { c.bench_function(&verifier_name, |b| { b.iter(|| { let msm = params.empty_msm(); - let mut transcript = DummyHashRead::init(&proof[..], Fq::one()); + let mut transcript = Blake2bRead::init(&proof[..]); let guard = verify_proof(¶ms, pk.get_vk(), msm, &[], &mut transcript).unwrap(); let msm = guard.clone().use_challenges(); assert!(msm.eval()); diff --git a/examples/performance_model.rs b/examples/performance_model.rs index c19246ba..23785eb1 100644 --- a/examples/performance_model.rs +++ b/examples/performance_model.rs @@ -1,13 +1,13 @@ use halo2::{ arithmetic::{Curve, FieldExt}, model::ModelRecorder, - pasta::{EqAffine, Fp, Fq}, + pasta::{EqAffine, Fp}, plonk::*, poly::{ commitment::{Blind, Params}, Rotation, }, - transcript::{DummyHashRead, DummyHashWrite}, + transcript::{Blake2bRead, Blake2bWrite}, }; use std::marker::PhantomData; @@ -279,7 +279,7 @@ fn main() { }; // Create a proof - let mut transcript = DummyHashWrite::init(vec![], Fq::one()); + let mut transcript = Blake2bWrite::init(vec![]); create_proof(¶ms, &pk, &[circuit], &[&[pubinputs]], &mut transcript) .expect("proof generation should not fail"); let proof: Vec = transcript.finalize(); @@ -289,7 +289,7 @@ fn main() { let pubinput_slice = &[pubinput]; let msm = params.empty_msm(); - let mut transcript = DummyHashRead::init(&proof[..], Fq::one()); + let mut transcript = Blake2bRead::init(&proof[..]); let guard = verify_proof( ¶ms, pk.get_vk(), diff --git a/src/plonk.rs b/src/plonk.rs index 239d3622..d612df58 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -147,12 +147,12 @@ type ChallengeX = ChallengeScalar; fn test_proving() { use crate::arithmetic::{Curve, FieldExt}; use crate::dev::MockProver; - use crate::pasta::{EqAffine, Fp, Fq}; + use crate::pasta::{EqAffine, Fp}; use crate::poly::{ commitment::{Blind, Params}, Rotation, }; - use crate::transcript::{DummyHashRead, DummyHashWrite}; + use crate::transcript::{Blake2bRead, Blake2bWrite}; use circuit::{Advice, Column, Fixed}; use std::marker::PhantomData; const K: u32 = 5; @@ -504,7 +504,7 @@ fn test_proving() { assert_eq!(prover.verify(), Ok(())); for _ in 0..100 { - let mut transcript = DummyHashWrite::init(vec![], Fq::one()); + let mut transcript = Blake2bWrite::init(vec![]); // Create a proof create_proof( ¶ms, @@ -519,7 +519,7 @@ fn test_proving() { let pubinput_slice = &[pubinput]; let pubinput_slice_copy = &[pubinput]; let msm = params.empty_msm(); - let mut transcript = DummyHashRead::init(&proof[..], Fq::one()); + let mut transcript = Blake2bRead::init(&proof[..]); let guard = verify_proof( ¶ms, pk.get_vk(), @@ -539,7 +539,7 @@ fn test_proving() { } let msm = guard.clone().use_challenges(); assert!(msm.clone().eval()); - let mut transcript = DummyHashRead::init(&proof[..], Fq::one()); + let mut transcript = Blake2bRead::init(&proof[..]); let mut vk_buffer = vec![]; pk.get_vk().write(&mut vk_buffer).unwrap(); let vk = VerifyingKey::::read::<_, MyCircuit>(&mut &vk_buffer[..], ¶ms) diff --git a/src/poly/commitment.rs b/src/poly/commitment.rs index f4098a81..c8272193 100644 --- a/src/poly/commitment.rs +++ b/src/poly/commitment.rs @@ -336,7 +336,7 @@ fn test_opening_proof() { use crate::arithmetic::{eval_polynomial, FieldExt}; use crate::pasta::{EpAffine, Fq}; use crate::transcript::{ - ChallengeScalar, DummyHashRead, DummyHashWrite, Transcript, TranscriptRead, TranscriptWrite, + Blake2bRead, Blake2bWrite, ChallengeScalar, Transcript, TranscriptRead, TranscriptWrite, }; let params = Params::::new(K); @@ -356,7 +356,7 @@ fn test_opening_proof() { let p = params.commit(&px, blind).to_affine(); - let mut transcript = DummyHashWrite::, EpAffine>::init(vec![], Field::zero()); + let mut transcript = Blake2bWrite::, EpAffine>::init(vec![]); transcript.write_point(p).unwrap(); let x = ChallengeScalar::<_, ()>::get(&mut transcript); // Evaluate the polynomial @@ -370,7 +370,7 @@ fn test_opening_proof() { }; // Verify the opening proof - let mut transcript = DummyHashRead::<&[u8], EpAffine>::init(&proof[..], Field::zero()); + let mut transcript = Blake2bRead::<&[u8], EpAffine>::init(&proof[..]); let p_prime = transcript.read_point().unwrap(); assert_eq!(p, p_prime); let x_prime = ChallengeScalar::<_, ()>::get(&mut transcript); diff --git a/src/poly/multiopen.rs b/src/poly/multiopen.rs index 98fd7468..c5937e49 100644 --- a/src/poly/multiopen.rs +++ b/src/poly/multiopen.rs @@ -242,7 +242,7 @@ fn test_roundtrip() { let bvx = eval_polynomial(&bx, x); let cvy = eval_polynomial(&cx, y); - let mut transcript = crate::transcript::DummyHashWrite::init(vec![], Field::one()); + let mut transcript = crate::transcript::Blake2bWrite::init(vec![]); create_proof( ¶ms, &mut transcript, @@ -268,7 +268,7 @@ fn test_roundtrip() { { let mut proof = &proof[..]; - let mut transcript = crate::transcript::DummyHashRead::init(&mut proof, Field::one()); + let mut transcript = crate::transcript::Blake2bRead::init(&mut proof); let msm = params.empty_msm(); let guard = verify_proof( @@ -301,7 +301,7 @@ fn test_roundtrip() { { let mut proof = &proof[..]; - let mut transcript = crate::transcript::DummyHashRead::init(&mut proof, Field::one()); + let mut transcript = crate::transcript::Blake2bRead::init(&mut proof); let msm = params.empty_msm(); let guard = verify_proof( diff --git a/src/transcript.rs b/src/transcript.rs index b1cbeb96..ec09120f 100644 --- a/src/transcript.rs +++ b/src/transcript.rs @@ -1,7 +1,9 @@ //! This module contains utilities and traits for dealing with Fiat-Shamir //! transcripts. +use blake2b_simd::{Params as Blake2bParams, State as Blake2bState}; use ff::Field; +use std::convert::TryInto; use std::ops::Deref; use crate::arithmetic::{CurveAffine, FieldExt}; @@ -39,30 +41,29 @@ pub trait TranscriptWrite: Transcript { fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()>; } -/// This is just a simple (and completely broken) transcript reader -/// implementation, standing in for some algebraic hash function that we'll -/// switch to later. +/// We will replace BLAKE2b with an algebraic hash function in a later version. #[derive(Debug, Clone)] -pub struct DummyHashRead { - base_state: C::Base, - scalar_state: C::Scalar, - read_scalar: bool, +pub struct Blake2bRead { + state: Blake2bState, reader: R, + _marker: PhantomData, } -impl DummyHashRead { +impl Blake2bRead { /// Initialize a transcript given an input buffer and a key. - pub fn init(reader: R, key: C::Base) -> Self { - DummyHashRead { - base_state: key + &C::Base::from_u64(1013), - scalar_state: C::Scalar::from_u64(1013), - read_scalar: false, + pub fn init(reader: R) -> Self { + Blake2bRead { + state: Blake2bParams::new() + .hash_length(64) + .personal(C::BLAKE2B_PERSONALIZATION) + .to_state(), reader, + _marker: PhantomData, } } } -impl TranscriptRead for DummyHashRead { +impl TranscriptRead for Blake2bRead { fn read_point(&mut self) -> io::Result { let mut compressed = [0u8; 32]; self.reader.read_exact(&mut compressed[..])?; @@ -77,21 +78,19 @@ impl TranscriptRead for DummyHashRead { fn read_scalar(&mut self) -> io::Result { let mut data = [0u8; 32]; self.reader.read_exact(&mut data)?; - let scalar = Option::from(C::Scalar::from_bytes(&data)).ok_or_else(|| { + let scalar: C::Scalar = Option::from(C::Scalar::from_bytes(&data)).ok_or_else(|| { io::Error::new( io::ErrorKind::Other, "invalid field element encoding in proof", ) })?; - self.scalar_state += &(scalar * &C::Scalar::ZETA); - self.scalar_state = self.scalar_state.square(); - self.read_scalar = true; + self.state.update(&scalar.to_bytes()); Ok(scalar) } } -impl Transcript for DummyHashRead { +impl Transcript for Blake2bRead { fn common_point(&mut self, point: C) -> io::Result<()> { let (x, y) = Option::from(point.get_xy()).ok_or_else(|| { io::Error::new( @@ -99,53 +98,38 @@ impl Transcript for DummyHashRead { "cannot write points at infinity to the transcript", ) })?; - self.base_state += &(x * &C::Base::ZETA); - self.base_state = self.base_state.square(); - self.base_state += &(y * &C::Base::ZETA); - self.base_state = self.base_state.square(); + self.state.update(&x.to_bytes()); + self.state.update(&y.to_bytes()); Ok(()) } fn squeeze_challenge(&mut self) -> C::Base { - if self.read_scalar { - let x = C::Base::from_bytes(&self.scalar_state.to_bytes()).unwrap(); - self.base_state += &(x * &C::Base::ZETA); - self.base_state = self.base_state.square(); - self.scalar_state = self.scalar_state.square(); - self.read_scalar = false; - } - - let tmp = self.base_state; - for _ in 0..5 { - self.base_state *= &(C::Base::ZETA + &C::Base::ZETA); - self.base_state += &C::Base::ZETA; - self.base_state = self.base_state.square(); - } - - tmp + let hasher = self.state.clone(); + let result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap(); + self.state.update(&result[..]); + C::Base::from_bytes_wide(&result) } } -/// This is just a simple (and completely broken) transcript writer -/// implementation, standing in for some algebraic hash function that we'll -/// switch to later. +/// We will replace BLAKE2b with an algebraic hash function in a later version. #[derive(Debug, Clone)] -pub struct DummyHashWrite { - base_state: C::Base, - scalar_state: C::Scalar, - written_scalar: bool, +pub struct Blake2bWrite { + state: Blake2bState, writer: W, + _marker: PhantomData, } -impl DummyHashWrite { +impl Blake2bWrite { /// Initialize a transcript given an output buffer and a key. - pub fn init(writer: W, key: C::Base) -> Self { - DummyHashWrite { - base_state: key + &C::Base::from_u64(1013), - scalar_state: C::Scalar::from_u64(1013), - written_scalar: false, + pub fn init(writer: W) -> Self { + Blake2bWrite { + state: Blake2bParams::new() + .hash_length(64) + .personal(C::BLAKE2B_PERSONALIZATION) + .to_state(), writer, + _marker: PhantomData, } } @@ -156,22 +140,20 @@ impl DummyHashWrite { } } -impl TranscriptWrite for DummyHashWrite { +impl TranscriptWrite for Blake2bWrite { fn write_point(&mut self, point: C) -> io::Result<()> { self.common_point(point)?; let compressed = point.to_bytes(); self.writer.write_all(&compressed[..]) } fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { - self.scalar_state += &(scalar * &C::Scalar::ZETA); - self.scalar_state = self.scalar_state.square(); - self.written_scalar = true; + self.state.update(&scalar.to_bytes()); let data = scalar.to_bytes(); self.writer.write_all(&data[..]) } } -impl Transcript for DummyHashWrite { +impl Transcript for Blake2bWrite { fn common_point(&mut self, point: C) -> io::Result<()> { let (x, y) = Option::from(point.get_xy()).ok_or_else(|| { io::Error::new( @@ -179,31 +161,17 @@ impl Transcript for DummyHashWrite { "cannot write points at infinity to the transcript", ) })?; - self.base_state += &(x * &C::Base::ZETA); - self.base_state = self.base_state.square(); - self.base_state += &(y * &C::Base::ZETA); - self.base_state = self.base_state.square(); + self.state.update(&x.to_bytes()); + self.state.update(&y.to_bytes()); Ok(()) } fn squeeze_challenge(&mut self) -> C::Base { - if self.written_scalar { - let x = C::Base::from_bytes(&self.scalar_state.to_bytes()).unwrap(); - self.base_state += &(x * &C::Base::ZETA); - self.base_state = self.base_state.square(); - self.scalar_state = self.scalar_state.square(); - self.written_scalar = false; - } - - let tmp = self.base_state; - for _ in 0..5 { - self.base_state *= &(C::Base::ZETA + &C::Base::ZETA); - self.base_state += &C::Base::ZETA; - self.base_state = self.base_state.square(); - } - - tmp + let hasher = self.state.clone(); + let result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap(); + self.state.update(&result[..]); + C::Base::from_bytes_wide(&result) } }