diff --git a/.gitignore b/.gitignore index 9479611..0bc5b19 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build target a.out +Cargo.lock \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 0545ce4..b4df4dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,9 @@ [submodule "hash/snark/src/hash-circuits"] path = hash/snark/external/hash-circuits url = https://github.com/faulhornlabs/hash-circuits +[submodule "hash/risc0/external/risc0"] + path = hash/risc0/external/risc0 + url = https://github.com/risc0/risc0.git +[submodule "hash/plonky2/external/zk_evm"] + path = hash/plonky2/external/zk_evm + url = https://github.com/hashcloak/zk_evm.git diff --git a/hash/cpu/external/Blake3 b/hash/cpu/external/Blake3 index dd30dcb..4d32708 160000 --- a/hash/cpu/external/Blake3 +++ b/hash/cpu/external/Blake3 @@ -1 +1 @@ -Subproject commit dd30dcb00221591db3a983e0215b81d86cff941d +Subproject commit 4d32708f511fd85c6b0fb131295cc73224246738 diff --git a/hash/cpu/external/constantine b/hash/cpu/external/constantine index 4dd0a02..dbd2630 160000 --- a/hash/cpu/external/constantine +++ b/hash/cpu/external/constantine @@ -1 +1 @@ -Subproject commit 4dd0a02f1afd338f5207e40a47cac6705196b490 +Subproject commit dbd2630daa6d599a9e78ad247e6858baf41664da diff --git a/hash/cpu/external/zikkurat-algebra b/hash/cpu/external/zikkurat-algebra index 96e3497..0fb198a 160000 --- a/hash/cpu/external/zikkurat-algebra +++ b/hash/cpu/external/zikkurat-algebra @@ -1 +1 @@ -Subproject commit 96e349786bd004e64a9cf50e0122f89863b24e92 +Subproject commit 0fb198a9087531f32bb00bd13d4feaf813bc473a diff --git a/hash/plonky2/bench/Cargo.toml b/hash/plonky2/bench/Cargo.toml new file mode 100644 index 0000000..ccadada --- /dev/null +++ b/hash/plonky2/bench/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "plonky2_hash_benchmarks" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +# TODO: This can be later changed to original github +plonky2_u32 ={ git = "https://github.com/hashcloak/plonky2-u32.git"} +plonky2 = "0.2.2" +rand = "0.8.5" +anyhow = "1.0.86" +sha2 = "0.10" +tiny-keccak={version="2.0.2", features=["keccak"]} +hex="0.4.3" +evm_arithmetization ={ path = "../external/zk_evm/evm_arithmetization" } +starky = "0.4.0" +env_logger = "0.11.3" +log = "0.4.21" diff --git a/hash/plonky2/bench/README.md b/hash/plonky2/bench/README.md new file mode 100644 index 0000000..cded41d --- /dev/null +++ b/hash/plonky2/bench/README.md @@ -0,0 +1,11 @@ +Plonky2 Hash Circuit Benchmarking +-------------------------------- +- The `plonky2/bench` contains the following hash circuit benchamrking code: sha256, keccak256 and poseidon. +- The code for sha256 is taken from [plonky2-sha256](https://github.com/polymerdao/plonky2-sha256). +- The keccak hash has two different implementation taken from [plonky2-keccak256](https://github.com/qope/plonky2-keccak256) and Polygon-zero [zk_evm](https://github.com/0xPolygonZero/zk_evm/tree/develop). +- The `build.sh` script builds the whole code. You need rust nightly version to build the code. The script overrides the default rust version to nightly. +- `run.sh` and `run_tree.sh` runs the benchmark. (`run.sh` for sha256, keccak, and keccak-polygon and `run_tree.sh` for poseidon) +- Benchmarks can be parameterized using environment variables. By convention, we start the names of these environment variables with the `ZKBENCH_` prefix. +- By default the `run.sh` will run the sha256 benchmark over 256 Bytes of data. other hashes can be run by settig the environment variables accordingly. +- By default the `run_tree.sh` will run the poseidon benchmark over tree depth 4. +- Additional files `bench.cfg` and `bench_tree.cfg` specifies the configurations and parameters. \ No newline at end of file diff --git a/hash/plonky2/bench/bench.cfg b/hash/plonky2/bench/bench.cfg new file mode 100644 index 0000000..1a0d6ea --- /dev/null +++ b/hash/plonky2/bench/bench.cfg @@ -0,0 +1,11 @@ +name: "Plonky2 hashes circuit benchmarking" +author: +timeout: 200 +params: + [ HASH_TYPE: [ "sha256", "keccak", "keccak-polygon"] + , INPUT_SIZE_BYTES: [ 256, 512, 1024, 2048 ] + ] +tags: plonky2, $HASH_TYPE + +comments: + The benchmarks includes for sha256, keccak and poseidon hash. \ No newline at end of file diff --git a/hash/plonky2/bench/bench_tree.cfg b/hash/plonky2/bench/bench_tree.cfg new file mode 100644 index 0000000..b34d338 --- /dev/null +++ b/hash/plonky2/bench/bench_tree.cfg @@ -0,0 +1,10 @@ +name: "Plonky2 hashes circuit benchmarking" +author: +timeout: 100 +params: + [ HASH_TYPE_TREE: [ "poseidon"] + , TREE_DEPTH: [ 2, 4, 8, 16 ] + ] +tags: plonky2, $HASH_TYPE_TREE +comments: + The benchmarks includes for poseidon hash. \ No newline at end of file diff --git a/hash/plonky2/bench/build.sh b/hash/plonky2/bench/build.sh new file mode 100755 index 0000000..7f06aa8 --- /dev/null +++ b/hash/plonky2/bench/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Set nightly as the default toolchain +rustup override set nightly + +# Build +RUSTFLAGS=-Ctarget-cpu=native cargo build --release --bin plonky2_hash_benchmarks + + diff --git a/hash/plonky2/bench/run.sh b/hash/plonky2/bench/run.sh new file mode 100755 index 0000000..82d817e --- /dev/null +++ b/hash/plonky2/bench/run.sh @@ -0,0 +1,15 @@ +#!/bin/bash +if [ -z ${ZKBENCH_HASH_TYPE} ]; then +ZKBENCH_HASH_TYPE="sha256" +fi + +if [ -z ${ZKBENCH_INPUT_SIZE_BYTES} ]; then +ZKBENCH_INPUT_SIZE_BYTES=256 +fi + +echo "Running benchmarks with the following configurations:" +echo "HASH = $ZKBENCH_HASH_TYPE" +echo "Input Size (Bytes) = $ZKBENCH_INPUT_SIZE_BYTES" + +# Run the benchmarks +./target/release/plonky2_hash_benchmarks $ZKBENCH_HASH_TYPE $ZKBENCH_INPUT_SIZE_BYTES \ No newline at end of file diff --git a/hash/plonky2/bench/run_tree.sh b/hash/plonky2/bench/run_tree.sh new file mode 100755 index 0000000..e1e33d6 --- /dev/null +++ b/hash/plonky2/bench/run_tree.sh @@ -0,0 +1,15 @@ +#!/bin/bash +if [ -z ${ZKBENCH_HASH_TYPE_TREE} ]; then +ZKBENCH_HASH_TYPE_TREE="poseidon" +fi + +if [ -z ${ZKBENCH_TREE_DEPTH} ]; then +ZKBENCH_TREE_DEPTH=4 +fi + +echo "Running benchmarks with the following configurations:" +echo "HASH = $ZKBENCH_HASH_TYPE_TREE" +echo "Tree Depth = $ZKBENCH_TREE_DEPTH" + +# Run the benchmarks +./target/release/plonky2_hash_benchmarks $ZKBENCH_HASH_TYPE_TREE $ZKBENCH_TREE_DEPTH \ No newline at end of file diff --git a/hash/plonky2/bench/src/arithmetic/binary_arithmetic.rs b/hash/plonky2/bench/src/arithmetic/binary_arithmetic.rs new file mode 100644 index 0000000..0c644e9 --- /dev/null +++ b/hash/plonky2/bench/src/arithmetic/binary_arithmetic.rs @@ -0,0 +1,78 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::field::extension::Extendable; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::iop::target::BoolTarget; + +pub fn xor_circuit( + a: BoolTarget, + b: BoolTarget, + builder: &mut CircuitBuilder, +) -> BoolTarget +where + F: RichField + Extendable, +{ + + // xor(a, b) = a*(1-b) + (1-a)*b = a + b - 2*ab + let b_minus_2ab = builder.arithmetic(-F::TWO, F::ONE, a.target, b.target, b.target); + let a_plus_b_minus_2ab = builder.add(a.target, b_minus_2ab); + + BoolTarget::new_unsafe(a_plus_b_minus_2ab) +} + +pub fn xor_const_circuit( + a: BoolTarget, + b: bool, + builder: &mut CircuitBuilder, +) -> BoolTarget +where + F: RichField + Extendable, +{ + // b = 0 => xor(a, b) = a + // b = 1 => xor(a, b) = 1 - a = not(a) + if b { + builder.not(a) + } else { + a + } +} + +// reffered to https://github.com/polymerdao/plonky2-sha256 +/// 0 -> [0, 1, 2, ..., 63] +/// 1 -> [63, 0, 1, ..., 62] +/// 63 -> [1, 2, ..., 63, 0] +pub fn rotate_u64(y: usize) -> Vec { + let mut res = Vec::new(); + for i in 64 - y..64 { + res.push(i); + } + for i in 0..64 - y { + res.push(i); + } + res +} + +#[allow(dead_code)] +pub fn from_bits_to_u64(bools: &[bool]) -> u64 { + let mut result: u64 = 0; + let mut shift = 0; + for &bit in bools { + if bit { + result |= 1 << shift; + } + shift += 1; + if shift == 64 { + break; + } + } + result +} + +pub fn u64_to_bits(num: u64) -> Vec { + let mut result = Vec::with_capacity(64); + let mut n = num; + for _ in 0..64 { + result.push(n & 1 == 1); + n >>= 1; + } + result +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/arithmetic/u32_arithmetic.rs b/hash/plonky2/bench/src/arithmetic/u32_arithmetic.rs new file mode 100644 index 0000000..734c74b --- /dev/null +++ b/hash/plonky2/bench/src/arithmetic/u32_arithmetic.rs @@ -0,0 +1,61 @@ +use plonky2::iop::target::BoolTarget; +use plonky2::hash::hash_types::RichField; +use plonky2::field::extension::Extendable; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2_u32::gadgets::arithmetic_u32::U32Target; +use plonky2_u32::gadgets::arithmetic_u32::CircuitBuilderU32; + +pub fn add_u32, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, + b: &U32Target, +) -> U32Target { + let (res, _carry) = builder.add_u32(*a, *b); + res +} + +pub fn u32_to_bits_target, const D: usize, const B: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, +) -> Vec { + let mut res = Vec::new(); + let bit_targets = builder.split_le_base::(a.0, 32); + for i in (0..32).rev() { + res.push(BoolTarget::new_unsafe(bit_targets[i])); + } + res +} + +pub fn bits_to_u32_target, const D: usize>( + builder: &mut CircuitBuilder, + bits_target: Vec, +) -> U32Target { + let bit_len = bits_target.len(); + assert_eq!(bit_len, 32); + U32Target(builder.le_sum(bits_target[0..32].iter().rev())) +} + +// x>>y +// Assume: 0 at index 32 +pub fn shift32(y: usize) -> Vec { + let mut res = Vec::new(); + for _ in 32 - y..32 { + res.push(32); + } + for i in 0..32 - y { + res.push(i); + } + res +} + +// define ROTATE(x, y) (((x)>>(y)) | ((x)<<(32-(y)))) +pub fn rotate32(y: usize) -> Vec { + let mut res = Vec::new(); + for i in 32 - y..32 { + res.push(i); + } + for i in 0..32 - y { + res.push(i); + } + res +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/arithmetic/u64_arithmetic.rs b/hash/plonky2/bench/src/arithmetic/u64_arithmetic.rs new file mode 100644 index 0000000..bc9cbd0 --- /dev/null +++ b/hash/plonky2/bench/src/arithmetic/u64_arithmetic.rs @@ -0,0 +1,152 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::field::extension::Extendable; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use std::marker::PhantomData; +use plonky2::iop::target::BoolTarget; +use plonky2::iop::witness::PartialWitness; +use plonky2::iop::witness::WitnessWrite; + +use crate::arithmetic::binary_arithmetic::{rotate_u64,xor_const_circuit,u64_to_bits,xor_circuit}; + +#[derive(Clone, Debug)] +pub struct U64Target { + pub bits: Vec, + _phantom: PhantomData, +} + +impl U64Target +where + F: RichField + Extendable, +{ + pub fn new(builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + for _ in 0..64 { + result.push(builder.add_virtual_bool_target_safe()); + } + Self { + bits: result, + _phantom: PhantomData, + } + } + + pub fn from(bits: Vec) -> Self { + assert_eq!(bits.len(), 64); + Self { + bits, + _phantom: PhantomData, + } + } + + pub fn set_witness(&self, bits: Vec, pw: &mut PartialWitness) { + for i in 0..64 { + pw.set_bool_target(self.bits[i], bits[i]); + } + } + + pub fn constant(x: u64, builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + let x_bits = u64_to_bits(x); + for i in 0..64 { + result.push(builder.constant_bool(x_bits[i])); + } + Self { + bits: result, + _phantom: PhantomData, + } + } + + pub fn connect(&self, other: &Self, builder: &mut CircuitBuilder) { + for i in 0..64 { + builder.connect(self.bits[i].target, other.bits[i].target); + } + } + + pub fn to_bits(&self, builder: &mut CircuitBuilder) -> Vec { + let output = Self::new(builder); + self.connect(&output, builder); + output.bits + } + + pub fn xor(&self, other: &Self, builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + for i in 0..64 { + let xor_target = xor_circuit(self.bits[i], other.bits[i], builder); + result.push(xor_target); + } + Self { + bits: result, + _phantom: PhantomData, + } + } + + pub fn xor_const(&self, other: u64, builder: &mut CircuitBuilder) -> Self { + let other_bits = u64_to_bits(other); + let mut result = vec![]; + for i in 0..64 { + let xor_target = xor_const_circuit(self.bits[i], other_bits[i], builder); + result.push(xor_target); + } + Self { + bits: result, + _phantom: PhantomData, + } + } + + /* Rotate left by n + * Note that the input parameter n is constant. It is not necessary to make n a constant target or public input, + * because different n generates a different circuit. + */ + pub fn rotl(&self, n: usize) -> Self { + let rotate = rotate_u64(n); + let mut output = vec![]; + for i in 0..64 { + output.push(self.bits[rotate[i]]); + } + + Self { + bits: output, + _phantom: PhantomData, + } + } + + pub fn and(&self, other: &Self, builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + for i in 0..64 { + result.push(builder.and(self.bits[i], other.bits[i])); + } + Self { + bits: result, + _phantom: PhantomData, + } + } + + pub fn not(&self, builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + for i in 0..64 { + result.push(builder.not(self.bits[i])); + } + Self { + bits: result, + _phantom: PhantomData, + } + } + + /// Calculate `self & !other`. + pub fn and_not(&self, other: &Self, builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + for i in 0..64 { + // x(1 - y) = x - xy + result.push(BoolTarget::new_unsafe(builder.arithmetic( + F::NEG_ONE, + F::ONE, + self.bits[i].target, + other.bits[i].target, + self.bits[i].target, + ))); + } + Self { + bits: result, + _phantom: PhantomData, + } + } +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/keccak256/keccak.rs b/hash/plonky2/bench/src/bench/keccak256/keccak.rs new file mode 100644 index 0000000..930059d --- /dev/null +++ b/hash/plonky2/bench/src/bench/keccak256/keccak.rs @@ -0,0 +1,312 @@ +// code taken from https://github.com/qope/plonky2-keccak256/tree/main + +use std::marker::PhantomData; +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::{ + target::BoolTarget, + witness::{PartialWitness, WitnessWrite}, + }, + plonk::{ + circuit_builder::CircuitBuilder, + circuit_data::CircuitConfig, + config::PoseidonGoldilocksConfig, + }, + field::goldilocks_field::GoldilocksField, +}; +use std::time::Instant; +use rand::Rng; +use tiny_keccak::{Keccak,Hasher}; +use anyhow::Result; +use crate::arithmetic::{ + binary_arithmetic::xor_circuit, + u64_arithmetic::U64Target +}; + +pub const ROUND_CONSTANTS: [u64; 24] = [ + 1u64, + 0x8082u64, + 0x800000000000808au64, + 0x8000000080008000u64, + 0x808bu64, + 0x80000001u64, + 0x8000000080008081u64, + 0x8000000000008009u64, + 0x8au64, + 0x88u64, + 0x80008009u64, + 0x8000000au64, + 0x8000808bu64, + 0x800000000000008bu64, + 0x8000000000008089u64, + 0x8000000000008003u64, + 0x8000000000008002u64, + 0x8000000000000080u64, + 0x800au64, + 0x800000008000000au64, + 0x8000000080008081u64, + 0x8000000000008080u64, + 0x80000001u64, + 0x8000000080008008u64, +]; +pub const ROTR: [usize; 25] = [ + 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14, +]; + +#[derive(Clone, Debug)] +pub struct KeccakTarget { + words: Vec>, + _phantom: PhantomData, +} + +impl KeccakTarget +where + F: RichField + Extendable, +{ + pub fn new(builder: &mut CircuitBuilder) -> Self { + let mut result = vec![]; + for _ in 0..25 { + result.push(U64Target::new(builder)); + } + Self { + words: result, + _phantom: PhantomData, + } + } + + pub fn set_witness(&self, bits: Vec, pw: &mut PartialWitness) { + assert_eq!(bits.len(), 1600); + for i in 0..25 { + self.words[i].set_witness(bits[i * 64..(i + 1) * 64].to_vec(), pw); + } + } + + pub fn connect(&self, other: &Self, builder: &mut CircuitBuilder) { + for i in 0..25 { + self.words[i].connect(&other.words[i], builder); + } + } + + pub fn from(bits: Vec) -> Self { + let mut result = vec![]; + for i in 0..25 { + result.push(U64Target::from(bits[i * 64..(i + 1) * 64].to_vec())); + } + Self { + words: result, + _phantom: PhantomData, + } + } + + pub fn keccak_round(&mut self, rc: u64, builder: &mut CircuitBuilder) { + // θ step + let mut c = vec![]; + for x in 0..5 { + let xor01 = self.words[x].xor(&self.words[x + 5], builder); + let xor012 = xor01.xor(&self.words[x + 2 * 5], builder); + let xor0123 = xor012.xor(&self.words[x + 3 * 5], builder); + let xor01234 = xor0123.xor(&self.words[x + 4 * 5], builder); + c.push(xor01234); + } + let mut d = vec![]; + for x in 0..5 { + let rot_c = c[(x + 1) % 5].rotl(1); + d.push(c[(x + 4) % 5].xor(&rot_c, builder)); + } + for x in 0..5 { + for y in 0..5 { + self.words[x + y * 5] = self.words[x + y * 5].xor(&d[x], builder); + } + } + // ρ and π steps + let mut b_words: [Option>; 25] = [(); 25].map(|_| None); + for x in 0..5 { + for y in 0..5 { + let rot_self = self.words[x + y * 5].rotl(ROTR[x + y * 5]); + + b_words[y + ((2 * x + 3 * y) % 5) * 5] = Some(rot_self); + } + } + let b = KeccakTarget { + words: b_words.into_iter().map(|x| x.unwrap()).collect(), + _phantom: PhantomData, + }; + + // χ step + for x in 0..5 { + for y in 0..5 { + // b.words[(x + 2) % 5 + y * 5] & !b.words[(x + 1) % 5 + y * 5] + let and_not_b = + b.words[(x + 2) % 5 + y * 5].and_not(&b.words[(x + 1) % 5 + y * 5], builder); + self.words[x + y * 5] = b.words[x + y * 5].xor(&and_not_b, builder); + } + } + + self.words[0] = self.words[0].xor_const(rc, builder); + } + + pub fn keccakf(&self, builder: &mut CircuitBuilder) -> Self { + let mut result = self.clone(); + for round_constant in ROUND_CONSTANTS.into_iter().take(24) { + result.keccak_round(round_constant, builder); + } + + result + } +} + +pub fn keccak256_circuit( + input: Vec, + builder: &mut CircuitBuilder, +) -> Vec +where + F: RichField + Extendable, +{ + assert_eq!(input.len() % 8, 0); // input should be bytes. + let block_size_in_bytes = 136; // in bytes + let input_len_in_bytes = input.len() / 8; + let num_blocks = input_len_in_bytes / block_size_in_bytes + 1; + + let mut padded = vec![]; + for _ in 0..block_size_in_bytes * 8 * num_blocks { + padded.push(builder.add_virtual_bool_target_safe()); + } + + // register input + for i in 0..input_len_in_bytes * 8 { + builder.connect(padded[i].target, input[i].target); + } + + // append 0x01 = 1000 0000 after the last input + let true_target = builder.constant_bool(true); + builder.connect(padded[input_len_in_bytes * 8].target, true_target.target); + + // pad 0s + let false_target = builder.constant_bool(false); + let last_index = padded.len() - 1; + for i in input_len_in_bytes * 8 + 1..last_index { + builder.connect(padded[i].target, false_target.target); + } + + // xor 0x80 = 0000 0001 with the last byte. + // however the last bit is ensured to be 0, so just fill 1. + builder.connect(padded[last_index].target, true_target.target); + + let mut m = KeccakTarget::new(builder); + for i in 0..1600 { + let word = i / 64; + let bit = i % 64; + builder.connect(m.words[word].bits[bit].target, false_target.target); + } + + for i in 0..num_blocks { + for j in 0..block_size_in_bytes * 8 { + let word = j / 64; + let bit = j % 64; + let xor_t = xor_circuit( + m.words[word].bits[bit], + padded[i * block_size_in_bytes * 8 + j], + builder, + ); + m.words[word].bits[bit] = xor_t; + } + m = m.keccakf(builder); + } + + let mut z = Vec::new(); + for i in 0..256 { + let new_target = builder.add_virtual_bool_target_safe(); + let word = i / 64; + let bit = i % 64; + builder.connect(new_target.target, m.words[word].bits[bit].target); + z.push(new_target); + } + z +} + +pub fn keccak_bench(size: usize) -> Result<()>{ + + type F = GoldilocksField; + type C = PoseidonGoldilocksConfig; + const D: usize = 2; + + let input_bytes = generate_data(size); + let input = hex::encode(input_bytes); + let expected_output = expected_keccak(&hex::decode(input.clone()).unwrap()); + + let input_bits = hex_str_to_bits(input.as_str())?; + let exptected_output_bits = hex_str_to_bits(&expected_output)?; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + let mut input_t = vec![]; + for i in 0..input_bits.len() { + input_t.push(builder.constant_bool(input_bits[i])); + } + let output_t = keccak256_circuit(input_t, &mut builder); + + let mut pw = PartialWitness::new(); + for i in 0..256 { + pw.set_bool_target(output_t[i], exptected_output_bits[i]); + } + let circuit_size = builder.num_gates(); + + let data = builder.build::(); + + let (proof_generation_time, proof) = { + let now = Instant::now(); + let proof = data.prove(pw)?; + (now.elapsed(), proof) + }; + let proof_size = proof.to_bytes().len(); + let (verification_time, verification_result) = { + let now = Instant::now(); + let res = data.verify(proof); + (now.elapsed(), res) + }; + + eprintln!("circuit size: {}", circuit_size); + eprintln!("proof generation time: {:?}", proof_generation_time); + eprintln!("verification time: {:?}", verification_time); + eprintln!("proof size: {:?}", proof_size); + + verification_result +} + +fn generate_data(size: usize) -> Vec { + + let mut rng = rand::thread_rng(); + let mut bytes = vec![0u8; size]; + rng.fill(&mut bytes[..]); + bytes +} + +fn u8_to_bits(num: u8) -> Vec { + let mut result = Vec::with_capacity(8); + let mut n = num; + for _ in 0..8 { + result.push(n & 1 == 1); + n >>= 1; + } + result +} + +fn hex_str_to_bits(input: &str) -> Result> { + let input_u8 = hex::decode(input)?; + let input_bits = input_u8 + .iter() + .flat_map(|x| u8_to_bits(*x)) + .collect::>(); + Ok(input_bits) +} + +fn expected_keccak(input: &[u8]) -> String { + let mut hasher = Keccak::v256(); + hasher.update(input); + let mut hash = [0u8; 32]; + hasher.finalize(&mut hash); + + hex::encode(hash) +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/keccak256/keccak_polygon.rs b/hash/plonky2/bench/src/bench/keccak256/keccak_polygon.rs new file mode 100644 index 0000000..c136491 --- /dev/null +++ b/hash/plonky2/bench/src/bench/keccak256/keccak_polygon.rs @@ -0,0 +1,161 @@ +// original source: https://github.com/0xPolygonZero/zk_evm/tree/develop + +use evm_arithmetization::{ + keccak::keccak_stark::KeccakStark, + prover::prove_single_table, + StarkConfig +}; +use anyhow::Result; +use plonky2::{ + fri::oracle::PolynomialBatch, + iop::challenger::Challenger, + plonk::config::{GenericConfig, PoseidonGoldilocksConfig}, + field::polynomial::PolynomialValues, + field::types::Field, + timed, + util::timing::TimingTree, +}; +use starky::{ + cross_table_lookup::{CtlData, CtlZData}, + lookup::{GrandProductChallenge, GrandProductChallengeSet}, + lookup::{Filter,Column}, +}; + +use env_logger::{ + DEFAULT_FILTER_ENV, + Env, + try_init_from_env +}; + +#[allow(dead_code)] +/// Number of rounds in a Keccak permutation. +pub(crate) const NUM_ROUNDS: usize = 24; + +/// Number of 64-bit elements in the Keccak permutation input. +pub(crate) const NUM_INPUTS: usize = 25; + +fn ceil_div(a: usize, b: usize) -> usize { + (a + b - 1) / b +} + +pub fn keccak_polygon_bench(size: usize) -> Result<()> { + // here input in in terms of block + let mut num_perms = 1; + if size > 25 * 64/8 { + num_perms = ceil_div(size, 25 * 64/8) as usize; + } + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type S = KeccakStark; + let stark = S::default(); + let config = StarkConfig::standard_fast_config(); + + init_logger(); + + let input: Vec<([u64; NUM_INPUTS], usize)> = + (0..num_perms).map(|_| (rand::random(), 0)).collect(); + + let mut timing = TimingTree::new("prove", log::Level::Debug); + let trace_poly_values = timed!( + timing, + "generate trace", + stark.generate_trace(input, 8, &mut timing) + ); + + let cloned_trace_poly_values = timed!(timing, "clone", trace_poly_values.clone()); + + let trace_commitments = timed!( + timing, + "compute trace commitment", + PolynomialBatch::::from_values( + cloned_trace_poly_values, + config.fri_config.rate_bits, + false, + config.fri_config.cap_height, + &mut timing, + None, + ) + ); + let degree = 1 << trace_commitments.degree_log; + + // Fake CTL data. + let ctl_z_data = CtlZData::new( + vec![PolynomialValues::zero(degree)], + PolynomialValues::zero(degree), + GrandProductChallenge { + beta: F::ZERO, + gamma: F::ZERO, + }, + vec![], + vec![Filter::new_simple(Column::constant(F::ZERO))], + ); + let ctl_data = CtlData { + zs_columns: vec![ctl_z_data.clone(); config.num_challenges], + }; + + prove_single_table( + &stark, + &config, + &trace_poly_values, + &trace_commitments, + &ctl_data, + &GrandProductChallengeSet { + challenges: vec![ctl_z_data.challenge; config.num_challenges], + }, + &mut Challenger::new(), + &mut timing, + None, + )?; + + timing.print(); + Ok(()) +} + +fn init_logger() { + let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "debug")); +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use plonky2::field::types::PrimeField64; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use tiny_keccak::keccakf; + use evm_arithmetization::keccak::columns::reg_output_limb; + use super::*; + const NUM_ROUNDS: usize = 24; + + #[test] + fn keccak_correctness_test() -> Result<()> { + let input: [u64; NUM_INPUTS] = rand::random(); + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type S = KeccakStark; + + let stark: KeccakStark<>::F, 2> = S::default(); + + let rows = stark.generate_trace_rows(vec![(input, 0)], 8); + let last_row = rows[NUM_ROUNDS - 1]; + let output = (0..NUM_INPUTS) + .map(|i| { + let hi = last_row[reg_output_limb(2 * i + 1)].to_canonical_u64(); + let lo = last_row[reg_output_limb(2 * i)].to_canonical_u64(); + (hi << 32) | lo + }) + .collect::>(); + + let expected = { + let mut state = input; + keccakf(&mut state); + state + }; + + assert_eq!(output, expected); + + Ok(()) + } +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/poseidon.rs b/hash/plonky2/bench/src/bench/poseidon.rs new file mode 100644 index 0000000..8867ff6 --- /dev/null +++ b/hash/plonky2/bench/src/bench/poseidon.rs @@ -0,0 +1,75 @@ +use anyhow::Result; +use plonky2::{ + field::types::Field, + field::goldilocks_field::GoldilocksField, + hash::poseidon::PoseidonHash, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, + plonk::circuit_data::CircuitConfig, + plonk::config::{GenericConfig, PoseidonGoldilocksConfig}, +}; +use rand::Rng; +use std::time; + +fn generate_data(size: usize) -> Vec { + + let mut data: Vec = Vec::new(); + for _ in 0..(1< Result<()> { + + let data = generate_data(depth); + + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + // The arithmetic circuit. + let initial = builder.add_virtual_targets(data.len()); + + let hash = builder.hash_or_noop::(initial.clone()); + + // Public inputs are the initial value (provided below) and the result (which is generated). + builder.register_public_inputs(initial.clone().as_slice()); + builder.register_public_input(hash.elements[0]); + builder.register_public_input(hash.elements[1]); + builder.register_public_input(hash.elements[2]); + builder.register_public_input(hash.elements[3]); + + // Provide initial values. + let mut pw = PartialWitness::new(); + pw.set_target_arr(initial.as_slice(), data.as_slice()); + + + let data = builder.build::(); + + let (proof_generation_time, proof) = { + + let start = time::Instant::now(); + let proof = data.prove(pw)?; + let end_time = start.elapsed(); + (end_time, proof) + }; + + let (verification_time, result) = { + let start = time::Instant::now(); + let result = data.verify(proof); + let end_time = start.elapsed(); + (end_time, result) + }; + + eprintln!("proof generation time: {:?}", proof_generation_time); + eprintln!("verification time: {:?}", verification_time); + result +} diff --git a/hash/plonky2/bench/src/bench/sha256/ch.rs b/hash/plonky2/bench/src/bench/sha256/ch.rs new file mode 100644 index 0000000..912d64c --- /dev/null +++ b/hash/plonky2/bench/src/bench/sha256/ch.rs @@ -0,0 +1,26 @@ +use plonky2::iop::target::BoolTarget; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::field::extension::Extendable; +use plonky2_u32::gadgets::arithmetic_u32::U32Target; +use crate::arithmetic::u32_arithmetic::{bits_to_u32_target, u32_to_bits_target}; + + +pub fn ch, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, + b: &U32Target, + c: &U32Target, +) -> U32Target { + let a_bits = u32_to_bits_target::(builder, a); + let b_bits = u32_to_bits_target::(builder, b); + let c_bits = u32_to_bits_target::(builder, c); + let mut res_bits = Vec::new(); + for i in 0..32 { + let b_sub_c = builder.sub(b_bits[i].target, c_bits[i].target); + let a_mul_b_sub_c = builder.mul(a_bits[i].target, b_sub_c); + let a_mul_b_sub_c_add_c = builder.add(a_mul_b_sub_c, c_bits[i].target); + res_bits.push(BoolTarget::new_unsafe(a_mul_b_sub_c_add_c)); + } + bits_to_u32_target(builder, res_bits) +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/sha256/constants.rs b/hash/plonky2/bench/src/bench/sha256/constants.rs new file mode 100644 index 0000000..e652bff --- /dev/null +++ b/hash/plonky2/bench/src/bench/sha256/constants.rs @@ -0,0 +1,24 @@ + +pub const H: [u32; 8] = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +]; + +pub const K: [u32; 64] = [ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 +]; \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/sha256/maj.rs b/hash/plonky2/bench/src/bench/sha256/maj.rs new file mode 100644 index 0000000..e4b307e --- /dev/null +++ b/hash/plonky2/bench/src/bench/sha256/maj.rs @@ -0,0 +1,31 @@ +use plonky2::iop::target::BoolTarget; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::field::extension::Extendable; +use plonky2_u32::gadgets::arithmetic_u32::U32Target; + +use crate::arithmetic::u32_arithmetic::{bits_to_u32_target, u32_to_bits_target}; + +pub fn maj, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, + b: &U32Target, + c: &U32Target, +) -> U32Target { + let a_bits = u32_to_bits_target::(builder, a); + let b_bits = u32_to_bits_target::(builder, b); + let c_bits = u32_to_bits_target::(builder, c); + let mut res_bits = Vec::new(); + for i in 0..32 { + let m = builder.mul(b_bits[i].target, c_bits[i].target); + let two = builder.two(); + let two_m = builder.mul(two, m); + let b_add_c = builder.add(b_bits[i].target, c_bits[i].target); + let b_add_c_sub_two_m = builder.sub(b_add_c, two_m); + let a_mul_b_add_c_sub_two_m = builder.mul(a_bits[i].target, b_add_c_sub_two_m); + let res = builder.add(a_mul_b_add_c_sub_two_m, m); + + res_bits.push(BoolTarget::new_unsafe(res)); + } + bits_to_u32_target(builder, res_bits) +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/sha256/sha.rs b/hash/plonky2/bench/src/bench/sha256/sha.rs new file mode 100644 index 0000000..3a862de --- /dev/null +++ b/hash/plonky2/bench/src/bench/sha256/sha.rs @@ -0,0 +1,245 @@ +// code is taken from https://github.com/polymerdao/plonky2-sha256 + +use plonky2::iop::target::BoolTarget; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::field::extension::Extendable; +use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target}; +use anyhow::Result; +use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::plonk::config::GenericConfig; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use sha2::{Digest, Sha256}; +use super::sigma::big_sigma0; +use super::sigma::big_sigma1; +use super::sigma::sigma0; +use super::sigma::sigma1; +use super::maj::maj; +use super::constants::*; +use super::ch::ch; +use crate::arithmetic::u32_arithmetic::add_u32; +use rand::Rng; + +pub struct Sha256Targets { + pub message: Vec, + pub digest: Vec, +} + +pub fn array_to_bits(bytes: &[u8]) -> Vec { + let len = bytes.len(); + let mut ret = Vec::new(); + for i in 0..len { + for j in 0..8 { + let b = (bytes[i] >> (7 - j)) & 1; + ret.push(b == 1); + } + } + ret +} + + +pub fn make_circuits, const D: usize>( + builder: &mut CircuitBuilder, + msg_len_in_bits: u64, + +) -> Sha256Targets { + + + let mut message = Vec::new(); + let mut digest = Vec::new(); + + let block_count = (msg_len_in_bits + 65 + 511) / 512; + let padded_msg_len = 512 * block_count; + let p = padded_msg_len - 64 - msg_len_in_bits; + assert!(p > 1); + + //msg + for _ in 0..msg_len_in_bits { + message.push(builder.add_virtual_bool_target_unsafe()); + } + + //append a single bit '1' + message.push(builder.constant_bool(true)); + + //append '0' bit so that total length become multiple of 512 + for _ in 0..p - 1 { + message.push(builder.constant_bool(false)); + } + + //append the msg length as 64bit big-endian integer + for i in 0..64 { + let b = ((msg_len_in_bits as u64) >> (63 - i)) & 1; + message.push(builder.constant_bool(b == 1)); + } + + // init states + let mut state = Vec::new(); + for i in 0..8 { + state.push(builder.constant_u32(H[i])); + } + + let mut k256 = Vec::new(); + for i in 0..64 { + k256.push(builder.constant_u32(K[i])); + } + + for blk in 0..block_count { + let mut x = Vec::new(); + let mut a = state[0].clone(); + let mut b = state[1].clone(); + let mut c = state[2].clone(); + let mut d = state[3].clone(); + let mut e = state[4].clone(); + let mut f = state[5].clone(); + let mut g = state[6].clone(); + let mut h = state[7].clone(); + + for i in 0..16 { + let index = blk as usize * 512 + i * 32; + let u32_target = builder.le_sum(message[index..index + 32].iter().rev()); + + x.push(U32Target(u32_target)); + let mut t1 = h.clone(); + let big_sigma1_e = big_sigma1(builder, &e); + t1 = add_u32(builder, &t1, &big_sigma1_e); + let ch_e_f_g = ch(builder, &e, &f, &g); + t1 = add_u32(builder, &t1, &ch_e_f_g); + t1 = add_u32(builder, &t1, &k256[i]); + t1 = add_u32(builder, &t1, &x[i]); + + let mut t2 = big_sigma0(builder, &a); + let maj_a_b_c = maj(builder, &a, &b, &c); + t2 = add_u32(builder, &t2, &maj_a_b_c); + + h = g; + g = f; + f = e; + e = add_u32(builder, &d, &t1); + d = c; + c = b; + b = a; + a = add_u32(builder, &t1, &t2); + } + + for i in 16..64 { + let s0 = sigma0(builder, &x[(i + 1) & 0x0f]); + let s1 = sigma1(builder, &x[(i + 14) & 0x0f]); + + let s0_add_s1 = add_u32(builder, &s0, &s1); + let s0_add_s1_add_x = add_u32(builder, &s0_add_s1, &x[(i + 9) & 0xf]); + x[i & 0xf] = add_u32(builder, &x[i & 0xf], &s0_add_s1_add_x); + + let big_sigma0_a = big_sigma0(builder, &a); + let big_sigma1_e = big_sigma1(builder, &e); + let ch_e_f_g = ch(builder, &e, &f, &g); + let maj_a_b_c = maj(builder, &a, &b, &c); + + let h_add_sigma1 = add_u32(builder, &h, &big_sigma1_e); + let h_add_sigma1_add_ch_e_f_g = add_u32(builder, &h_add_sigma1, &ch_e_f_g); + let h_add_sigma1_add_ch_e_f_g_add_k256 = + add_u32(builder, &h_add_sigma1_add_ch_e_f_g, &k256[i]); + + let t1 = add_u32(builder, &x[i & 0xf], &h_add_sigma1_add_ch_e_f_g_add_k256); + let t2 = add_u32(builder, &big_sigma0_a, &maj_a_b_c); + + h = g; + g = f; + f = e; + e = add_u32(builder, &d, &t1); + d = c; + c = b; + b = a; + a = add_u32(builder, &t1, &t2); + } + + state[0] = add_u32(builder, &state[0], &a); + state[1] = add_u32(builder, &state[1], &b); + state[2] = add_u32(builder, &state[2], &c); + state[3] = add_u32(builder, &state[3], &d); + state[4] = add_u32(builder, &state[4], &e); + state[5] = add_u32(builder, &state[5], &f); + state[6] = add_u32(builder, &state[6], &g); + state[7] = add_u32(builder, &state[7], &h); + } + + for i in 0..8 { + let bit_targets = builder.split_le_base::<2>(state[i].0, 32); + for j in (0..32).rev() { + digest.push(BoolTarget::new_unsafe(bit_targets[j])); + } + } + + Sha256Targets { message, digest } +} + + +fn generate_random_bytes(size: usize) -> Vec { + + let mut rng = rand::thread_rng(); + let mut bytes = vec![0u8; size]; + rng.fill(&mut bytes[..]); + + bytes + +} + +pub fn sha256_bench(size: usize) -> Result<()> { + let msg = generate_random_bytes(size); + + let mut hasher = Sha256::new(); + hasher.update(msg.clone()); + let hash = hasher.finalize(); + + let msg_bits = array_to_bits(&msg.clone()); + let len = msg.len() * 8; + println!("block count: {}", (len + 65 + 511) / 512); + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let mut builder = CircuitBuilder::::new(CircuitConfig::standard_recursion_config()); + let targets = make_circuits(&mut builder, len as u64); + let mut pw = PartialWitness::new(); + + for i in 0..len { + pw.set_bool_target(targets.message[i], msg_bits[i]); + } + + let expected_res = array_to_bits(hash.as_slice()); + for i in 0..expected_res.len() { + if expected_res[i] { + builder.assert_one(targets.digest[i].target); + } else { + builder.assert_zero(targets.digest[i].target); + } + } + + println!( + "number of gates: {}", + builder.num_gates() + ); + let data = builder.build::(); + + let (proof_time, proof ) = { + + let start = std::time::Instant::now(); + let proof = data.prove(pw).unwrap(); + let end = start.elapsed(); + (end, proof) + }; + let proof_size = proof.to_bytes().len(); + + let (verification_time, res) = { + let start = std::time::Instant::now(); + let res = data.verify(proof); + let end = start.elapsed(); + (end, res) + }; + + eprintln!("Proof Generation Time: {:?}", proof_time); + eprintln!("Verification Time: {:?}", verification_time); + eprintln!("Proof size: {:?}", proof_size); + + res + +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/sha256/sigma.rs b/hash/plonky2/bench/src/bench/sha256/sigma.rs new file mode 100644 index 0000000..f6a0660 --- /dev/null +++ b/hash/plonky2/bench/src/bench/sha256/sigma.rs @@ -0,0 +1,91 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::field::extension::Extendable; +use plonky2_u32::gadgets::arithmetic_u32::U32Target; +use crate::arithmetic::u32_arithmetic::{rotate32, shift32}; +use crate::arithmetic::u32_arithmetic::u32_to_bits_target; +use crate::arithmetic::u32_arithmetic::bits_to_u32_target; +use super::xor3::xor3; + +pub fn sigma0, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, +) -> U32Target { + let mut a_bits = u32_to_bits_target::(builder, a); + a_bits.push(builder.constant_bool(false)); + let rotate7 = rotate32(7); + let rotate18 = rotate32(18); + let shift3 = shift32(3); + let mut res_bits = Vec::new(); + for i in 0..32 { + res_bits.push(xor3( + builder, + a_bits[rotate7[i]], + a_bits[rotate18[i]], + a_bits[shift3[i]], + )); + } + bits_to_u32_target(builder, res_bits) +} + +pub fn sigma1, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, +) -> U32Target { + let mut a_bits = u32_to_bits_target::(builder, a); + a_bits.push(builder.constant_bool(false)); + let rotate17 = rotate32(17); + let rotate19 = rotate32(19); + let shift10 = shift32(10); + let mut res_bits = Vec::new(); + for i in 0..32 { + res_bits.push(xor3( + builder, + a_bits[rotate17[i]], + a_bits[rotate19[i]], + a_bits[shift10[i]], + )); + } + bits_to_u32_target(builder, res_bits) +} + +//#define Sigma0(x) (ROTATE((x), 2) ^ ROTATE((x),13) ^ ROTATE((x),22)) +pub fn big_sigma0, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, +) -> U32Target { + let a_bits = u32_to_bits_target::(builder, a); + let rotate2 = rotate32(2); + let rotate13 = rotate32(13); + let rotate22 = rotate32(22); + let mut res_bits = Vec::new(); + for i in 0..32 { + res_bits.push(xor3( + builder, + a_bits[rotate2[i]], + a_bits[rotate13[i]], + a_bits[rotate22[i]], + )); + } + bits_to_u32_target(builder, res_bits) +} + +pub fn big_sigma1, const D: usize>( + builder: &mut CircuitBuilder, + a: &U32Target, +) -> U32Target { + let a_bits = u32_to_bits_target::(builder, a); + let rotate6 = rotate32(6); + let rotate11 = rotate32(11); + let rotate25 = rotate32(25); + let mut res_bits = Vec::new(); + for i in 0..32 { + res_bits.push(xor3( + builder, + a_bits[rotate6[i]], + a_bits[rotate11[i]], + a_bits[rotate25[i]], + )); + } + bits_to_u32_target(builder, res_bits) +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/bench/sha256/xor3.rs b/hash/plonky2/bench/src/bench/sha256/xor3.rs new file mode 100644 index 0000000..4a176ac --- /dev/null +++ b/hash/plonky2/bench/src/bench/sha256/xor3.rs @@ -0,0 +1,26 @@ +use plonky2::iop::target::BoolTarget; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::field::extension::Extendable; + +pub fn xor3, const D: usize>( + builder: &mut CircuitBuilder, + a: BoolTarget, + b: BoolTarget, + c: BoolTarget, +) -> BoolTarget { + let m = builder.mul(b.target, c.target); + let two_b = builder.add(b.target, b.target); + let two_c = builder.add(c.target, c.target); + let two_m = builder.add(m, m); + let four_m = builder.add(two_m, two_m); + let one = builder.one(); + let one_sub_two_b = builder.sub(one, two_b); + let one_sub_two_b_sub_two_c = builder.sub(one_sub_two_b, two_c); + let one_sub_two_b_sub_two_c_add_four_m = builder.add(one_sub_two_b_sub_two_c, four_m); + let mut res = builder.mul(a.target, one_sub_two_b_sub_two_c_add_four_m); + res = builder.add(res, b.target); + res = builder.add(res, c.target); + + BoolTarget::new_unsafe(builder.sub(res, two_m)) +} \ No newline at end of file diff --git a/hash/plonky2/bench/src/main.rs b/hash/plonky2/bench/src/main.rs new file mode 100644 index 0000000..e804c69 --- /dev/null +++ b/hash/plonky2/bench/src/main.rs @@ -0,0 +1,77 @@ + +use std::process; +mod bench{ + pub mod poseidon; + pub mod sha256{ + pub mod constants; + pub mod sigma; + pub mod sha; + pub mod xor3; + pub mod maj; + pub mod ch; + + } + + pub mod keccak256{ + pub mod keccak; + pub mod keccak_polygon; + } +} + +mod arithmetic { + pub mod binary_arithmetic; + pub mod u32_arithmetic; + pub mod u64_arithmetic; +} + +use bench::poseidon::poseidon_bench; +use bench::keccak256::keccak::keccak_bench; +use bench::sha256::sha::sha256_bench; +use bench::keccak256::keccak_polygon::keccak_polygon_bench; + + +fn main() { + let args: Vec = std::env::args().collect(); + + if args.len() != 3 { + println!("Wrong number of arguments! The program expects two arguments: and "); + // Exit the program with a non-zero exit code + process::exit(1); + } + + let hash_type = &args[1]; + let size = args[2].parse::().unwrap(); + + match hash_type.as_str() { + + "poseidon" => { + println!("Running Poseidon: "); + eprintln!("Tree Depth: {:?}", size); + let _ = poseidon_bench(size); + } + + "keccak" => { + println!("Running keccak: "); + eprintln!("input size: {:?}", size); + let _ = keccak_bench(size); + } + + "keccak-polygon" => { + println!("Running keccak of plolygon zk_evm: "); + let _ = keccak_polygon_bench(size); + } + + + "sha256" => { + println!("Running sha256: "); + let _ = sha256_bench(size); + } + + _ => { + println!("Wrong Benchmark Name!"); + } + } + + println!("All Done!"); + +} \ No newline at end of file diff --git a/hash/plonky2/external/zk_evm b/hash/plonky2/external/zk_evm new file mode 160000 index 0000000..5511569 --- /dev/null +++ b/hash/plonky2/external/zk_evm @@ -0,0 +1 @@ +Subproject commit 5511569d166c29cc85211df31bb9485870ca53ab diff --git a/hash/snark/external/hash-circuits b/hash/snark/external/hash-circuits index e6b99b2..3ae1517 160000 --- a/hash/snark/external/hash-circuits +++ b/hash/snark/external/hash-circuits @@ -1 +1 @@ -Subproject commit e6b99b20f038f27390f590313ce7de227d6dd42a +Subproject commit 3ae1517526f1061a8d37a159270cc15727e6b503