diff --git a/Cargo.toml b/Cargo.toml index d60b76c7..65a0fb22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,10 @@ harness = false name = "plonk" harness = false +[[bench]] +name = "sha256" +harness = false + [dependencies] backtrace = { version = "0.3", optional = true } subtle = "2.3" diff --git a/benches/sha256.rs b/benches/sha256.rs new file mode 100644 index 00000000..febf47f8 --- /dev/null +++ b/benches/sha256.rs @@ -0,0 +1,164 @@ +#[macro_use] +extern crate criterion; + +extern crate halo2; +use halo2::{ + arithmetic::FieldExt, + circuit::Chip, + circuit::{layouter, Layouter}, + gadget::sha256::{BlockWord, Sha256, Table16Chip, Table16Config, BLOCK_SIZE}, + pasta::EqAffine, + plonk::{ + create_proof, keygen_pk, keygen_vk, verify_proof, Assignment, Circuit, ConstraintSystem, + Error, VerifyingKey, + }, + poly::commitment::Params, + transcript::{Blake2bRead, Blake2bWrite}, +}; + +use std::{ + fs::File, + io::{prelude::*, BufReader}, + path::Path, +}; + +use criterion::Criterion; + +fn bench(name: &str, k: u32, c: &mut Criterion) { + struct MyCircuit {} + + impl Circuit for MyCircuit { + type Config = Table16Config; + + fn configure(meta: &mut ConstraintSystem) -> Table16Config { + Table16Chip::configure(meta) + } + + fn synthesize( + &self, + cs: &mut impl Assignment, + config: Table16Config, + ) -> Result<(), Error> { + let mut layouter = layouter::SingleChip::, _>::new(cs, config)?; + Table16Chip::load(&mut layouter)?; + + // Test vector: "abc" + let test_input = [ + BlockWord::new(0b01100001011000100110001110000000), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + BlockWord::new(0), + ]; + + // Create a message of length 31 blocks + let mut input = Vec::with_capacity(31 * BLOCK_SIZE); + for _ in 0..31 { + input.extend_from_slice(&test_input); + } + + Sha256::digest(layouter.namespace(|| "test vector"), &input)?; + + Ok(()) + } + } + + // Initialize the polynomial commitment parameters + let params_path = Path::new("./benches/sha256_assets/sha256_params"); + if let Err(_) = File::open(¶ms_path) { + let params: Params = Params::new(k); + let mut buf = Vec::new(); + + params.write(&mut buf).expect("Failed to write params"); + let mut file = File::create(¶ms_path).expect("Failed to create sha256_params"); + + file.write_all(&buf[..]) + .expect("Failed to write params to file"); + } + + let params_fs = File::open(¶ms_path).expect("couldn't load sha256_params"); + let params: Params = + Params::read::<_>(&mut BufReader::new(params_fs)).expect("Failed to read params"); + + let empty_circuit: MyCircuit = MyCircuit {}; + + // Initialize the proving key + let vk_path = Path::new("./benches/sha256_assets/sha256_vk"); + if let Err(_) = File::open(&vk_path) { + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let mut buf = Vec::new(); + + vk.write(&mut buf).expect("Failed to write vk"); + let mut file = File::create(&vk_path).expect("Failed to create sha256_vk"); + + file.write_all(&buf[..]) + .expect("Failed to write vk to file"); + } + + let vk_fs = File::open(&vk_path).expect("couldn't load sha256_params"); + let vk: VerifyingKey = + VerifyingKey::::read::<_, MyCircuit>(&mut BufReader::new(vk_fs), ¶ms) + .expect("Failed to read vk"); + + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); + + let circuit: MyCircuit = MyCircuit {}; + + // let prover_name = name.to_string() + "-prover"; + let verifier_name = name.to_string() + "-verifier"; + + // /// Benchmark proof creation + // c.bench_function(&prover_name, |b| { + // b.iter(|| { + // let mut transcript = Blake2bWrite::init(Fq::one()); + // create_proof(¶ms, &pk, &circuit, &[], &mut transcript) + // .expect("proof generation should not fail"); + // let proof: Vec = transcript.finalize(); + // }); + // }); + + // Create a proof + let proof_path = Path::new("./benches/sha256_assets/sha256_proof"); + if let Err(_) = File::open(&proof_path) { + let mut transcript = Blake2bWrite::init(vec![]); + create_proof(¶ms, &pk, &[circuit], &[], &mut transcript) + .expect("proof generation should not fail"); + let proof: Vec = transcript.finalize(); + let mut file = File::create(&proof_path).expect("Failed to create sha256_proof"); + file.write_all(&proof[..]).expect("Failed to write proof"); + } + + let mut proof_fs = File::open(&proof_path).expect("couldn't load sha256_proof"); + let mut proof = Vec::::new(); + proof_fs + .read_to_end(&mut proof) + .expect("Couldn't read proof"); + + c.bench_function(&verifier_name, |b| { + b.iter(|| { + let msm = params.empty_msm(); + 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()); + }); + }); +} + +fn criterion_benchmark(c: &mut Criterion) { + bench("sha256", 16, c); + // bench("sha256", 20, c); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/gadget/sha256.rs b/src/gadget/sha256.rs index 0b5fd612..e41fe880 100644 --- a/src/gadget/sha256.rs +++ b/src/gadget/sha256.rs @@ -13,10 +13,10 @@ use crate::{ mod table16; -pub use table16::Table16Chip; +pub use table16::{BlockWord, Table16Chip, Table16Config}; /// The size of a SHA-256 block, in 32-bit words. -const BLOCK_SIZE: usize = 16; +pub const BLOCK_SIZE: usize = 16; /// The size of a SHA-256 digest, in 32-bit words. const DIGEST_SIZE: usize = 8; diff --git a/src/gadget/sha256/table16.rs b/src/gadget/sha256/table16.rs index df66ccae..ca2bf75c 100644 --- a/src/gadget/sha256/table16.rs +++ b/src/gadget/sha256/table16.rs @@ -45,12 +45,14 @@ const IV: [u32; STATE] = [ ]; #[derive(Clone, Copy, Debug)] +/// A word in a `Table16` message block. pub struct BlockWord { var: (), value: Option, } impl BlockWord { + /// Create a new `BlockWord`. pub fn new(value: u32) -> Self { BlockWord { var: (),