From 42a7ff9cc2bae22a78fff273b68550120e10a466 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 24 Sep 2021 13:06:07 +0200 Subject: [PATCH 1/4] Working --- src/bin/bench_recursion.rs | 2 +- src/field/field_types.rs | 2 +- src/gates/poseidon.rs | 19 +++++-------------- src/hash/gmimc.rs | 4 ++++ src/hash/hashing.rs | 12 +++++++----- src/hash/merkle_proofs.rs | 9 ++------- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 117403fc..256864b1 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -41,7 +41,7 @@ fn bench_prove, const D: usize>() -> Result<()> { let zero = builder.zero(); let zero_ext = builder.zero_extension(); - let mut state = [zero; 12]; + let mut state = [zero; 8]; for _ in 0..10000 { state = builder.permute(state); } diff --git a/src/field/field_types.rs b/src/field/field_types.rs index 82f27d60..97db0948 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -16,7 +16,7 @@ use crate::hash::poseidon::Poseidon; use crate::util::bits_u64; /// A prime order field with the features we need to use it as a base field in our argument system. -pub trait RichField: PrimeField + GMiMC<12> + Poseidon<12> {} +pub trait RichField: PrimeField + GMiMC<8> + Poseidon<8> {} /// A finite field. pub trait Field: diff --git a/src/gates/poseidon.rs b/src/gates/poseidon.rs index 3aef44ab..0d2a358b 100644 --- a/src/gates/poseidon.rs +++ b/src/gates/poseidon.rs @@ -103,7 +103,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(swap * (swap - F::Extension::ONE)); - let mut state = Vec::with_capacity(12); + let mut state = Vec::with_capacity(8); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -114,9 +114,6 @@ where let b = vars.local_wires[i]; state.push(a + swap * (b - a)); } - for i in 8..12 { - state.push(vars.local_wires[i]); - } let mut state: [F::Extension; WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; @@ -182,7 +179,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(swap * (swap - F::ONE)); - let mut state = Vec::with_capacity(12); + let mut state = Vec::with_capacity(8); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -193,9 +190,6 @@ where let b = vars.local_wires[i]; state.push(a + swap * (b - a)); } - for i in 8..12 { - state.push(vars.local_wires[i]); - } let mut state: [F; WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; @@ -265,7 +259,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(builder.mul_sub_extension(swap, swap, swap)); - let mut state = Vec::with_capacity(12); + let mut state = Vec::with_capacity(8); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -278,9 +272,6 @@ where let delta = builder.sub_extension(b, a); state.push(builder.mul_add_extension(swap, delta, a)); } - for i in 8..12 { - state.push(vars.local_wires[i]); - } let mut state: [ExtensionTarget; WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; @@ -555,7 +546,7 @@ mod tests { #[test] fn low_degree() { type F = CrandallField; - const WIDTH: usize = 12; + const WIDTH: usize = 8; let gate = PoseidonGate::::new(); test_low_degree(gate) } @@ -563,7 +554,7 @@ mod tests { #[test] fn eval_fns() -> Result<()> { type F = CrandallField; - const WIDTH: usize = 12; + const WIDTH: usize = 8; let gate = PoseidonGate::::new(); test_eval_fns(gate) } diff --git a/src/hash/gmimc.rs b/src/hash/gmimc.rs index bb259d54..44af69d6 100644 --- a/src/hash/gmimc.rs +++ b/src/hash/gmimc.rs @@ -79,6 +79,10 @@ const CRANDALL_AND_GOLDILOCKS_ROUND_CONSTANTS: [u64; NUM_ROUNDS] = [ 0x780f22441e8dbc04, ]; +impl GMiMC<8> for CrandallField { + const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = CRANDALL_AND_GOLDILOCKS_ROUND_CONSTANTS; +} + impl GMiMC<12> for CrandallField { const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = CRANDALL_AND_GOLDILOCKS_ROUND_CONSTANTS; } diff --git a/src/hash/hashing.rs b/src/hash/hashing.rs index d5474cc4..dee3e320 100644 --- a/src/hash/hashing.rs +++ b/src/hash/hashing.rs @@ -1,5 +1,7 @@ //! Concrete instantiation of a hash function. +use std::convert::TryInto; + use crate::field::extension_field::Extendable; use crate::field::field_types::RichField; use crate::gates::poseidon::PoseidonGate; @@ -7,7 +9,7 @@ use crate::hash::hash_types::{HashOut, HashOutTarget}; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; -pub(crate) const SPONGE_RATE: usize = 8; +pub(crate) const SPONGE_RATE: usize = 4; pub(crate) const SPONGE_CAPACITY: usize = 4; pub(crate) const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; @@ -86,10 +88,10 @@ impl, const D: usize> CircuitBuilder { /// A one-way compression function which takes two ~256 bit inputs and returns a ~256 bit output. pub fn compress(x: HashOut, y: HashOut) -> HashOut { - let mut inputs = Vec::with_capacity(8); - inputs.extend(&x.elements); - inputs.extend(&y.elements); - hash_n_to_hash(inputs, false) + let perm_inputs = [x.elements, y.elements].concat().try_into().unwrap(); + HashOut { + elements: permute(perm_inputs)[..4].try_into().unwrap(), + } } /// If `pad` is enabled, the message is padded using the pad10*1 rule. In general this is required diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 85719b51..d595d61f 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -63,12 +63,10 @@ impl, const D: usize> CircuitBuilder { merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { - let zero = self.zero(); - let mut state: HashOutTarget = self.hash_or_noop(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { - let perm_inputs = [state.elements, sibling.elements, [zero; 4]] + let perm_inputs = [state.elements, sibling.elements] .concat() .try_into() .unwrap(); @@ -100,13 +98,10 @@ impl, const D: usize> CircuitBuilder { merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { - let zero = self.zero(); - let zero_x4 = [zero; 4]; - let mut state: HashOutTarget = self.hash_or_noop(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { - let inputs = [state.elements, sibling.elements, zero_x4] + let inputs = [state.elements, sibling.elements] .concat() .try_into() .unwrap(); From 1a55538e23e7704c44b98e6c58f91783ed45511e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 24 Sep 2021 15:50:48 +0200 Subject: [PATCH 2/4] 8->SPONGE_WIDTH in most places --- src/bin/bench_recursion.rs | 3 ++- src/gates/poseidon.rs | 23 ++++++++++++++++------- src/hash/hashing.rs | 6 ++++-- src/hash/merkle_proofs.rs | 20 ++++++++++---------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 256864b1..650bee11 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -5,6 +5,7 @@ use plonky2::field::crandall_field::CrandallField; use plonky2::field::extension_field::Extendable; use plonky2::field::field_types::RichField; use plonky2::fri::FriConfig; +use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; @@ -41,7 +42,7 @@ fn bench_prove, const D: usize>() -> Result<()> { let zero = builder.zero(); let zero_ext = builder.zero_extension(); - let mut state = [zero; 8]; + let mut state = [zero; SPONGE_WIDTH]; for _ in 0..10000 { state = builder.permute(state); } diff --git a/src/gates/poseidon.rs b/src/gates/poseidon.rs index 0d2a358b..bbc42b0d 100644 --- a/src/gates/poseidon.rs +++ b/src/gates/poseidon.rs @@ -5,6 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::{Field, RichField}; use crate::gates::gate::Gate; +use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon; use crate::hash::poseidon::Poseidon; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -103,7 +104,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(swap * (swap - F::Extension::ONE)); - let mut state = Vec::with_capacity(8); + let mut state = Vec::with_capacity(SPONGE_WIDTH); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -114,6 +115,9 @@ where let b = vars.local_wires[i]; state.push(a + swap * (b - a)); } + for i in 8..SPONGE_WIDTH { + state.push(vars.local_wires[i]); + } let mut state: [F::Extension; WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; @@ -179,7 +183,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(swap * (swap - F::ONE)); - let mut state = Vec::with_capacity(8); + let mut state = Vec::with_capacity(SPONGE_WIDTH); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -190,6 +194,9 @@ where let b = vars.local_wires[i]; state.push(a + swap * (b - a)); } + for i in 8..SPONGE_WIDTH { + state.push(vars.local_wires[i]); + } let mut state: [F; WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; @@ -259,7 +266,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(builder.mul_sub_extension(swap, swap, swap)); - let mut state = Vec::with_capacity(8); + let mut state = Vec::with_capacity(SPONGE_WIDTH); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -272,6 +279,9 @@ where let delta = builder.sub_extension(b, a); state.push(builder.mul_add_extension(swap, delta, a)); } + for i in 8..SPONGE_WIDTH { + state.push(vars.local_wires[i]); + } let mut state: [ExtensionTarget; WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; @@ -489,6 +499,7 @@ mod tests { use crate::field::field_types::Field; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::poseidon::PoseidonGate; + use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon::Poseidon; use crate::iop::generator::generate_partial_witness; use crate::iop::wire::Wire; @@ -546,16 +557,14 @@ mod tests { #[test] fn low_degree() { type F = CrandallField; - const WIDTH: usize = 8; - let gate = PoseidonGate::::new(); + let gate = PoseidonGate::::new(); test_low_degree(gate) } #[test] fn eval_fns() -> Result<()> { type F = CrandallField; - const WIDTH: usize = 8; - let gate = PoseidonGate::::new(); + let gate = PoseidonGate::::new(); test_eval_fns(gate) } } diff --git a/src/hash/hashing.rs b/src/hash/hashing.rs index dee3e320..77ee1534 100644 --- a/src/hash/hashing.rs +++ b/src/hash/hashing.rs @@ -11,7 +11,7 @@ use crate::plonk::circuit_builder::CircuitBuilder; pub(crate) const SPONGE_RATE: usize = 4; pub(crate) const SPONGE_CAPACITY: usize = 4; -pub(crate) const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; +pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; pub(crate) const HASH_FAMILY: HashFamily = HashFamily::Poseidon; @@ -88,7 +88,9 @@ impl, const D: usize> CircuitBuilder { /// A one-way compression function which takes two ~256 bit inputs and returns a ~256 bit output. pub fn compress(x: HashOut, y: HashOut) -> HashOut { - let perm_inputs = [x.elements, y.elements].concat().try_into().unwrap(); + let mut perm_inputs = [F::ZERO; SPONGE_WIDTH]; + perm_inputs[..4].copy_from_slice(&x.elements); + perm_inputs[4..8].copy_from_slice(&y.elements); HashOut { elements: permute(perm_inputs)[..4].try_into().unwrap(), } diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index d595d61f..ac62d8f0 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -7,7 +7,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::{Field, RichField}; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; -use crate::hash::hashing::{compress, hash_or_noop}; +use crate::hash::hashing::{compress, hash_or_noop, SPONGE_WIDTH}; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; @@ -63,13 +63,13 @@ impl, const D: usize> CircuitBuilder { merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { + let zero = self.zero(); let mut state: HashOutTarget = self.hash_or_noop(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { - let perm_inputs = [state.elements, sibling.elements] - .concat() - .try_into() - .unwrap(); + let mut perm_inputs = [zero; SPONGE_WIDTH]; + perm_inputs[..4].copy_from_slice(&state.elements); + perm_inputs[4..8].copy_from_slice(&sibling.elements); let outputs = self.permute_swapped(perm_inputs, bit); state = HashOutTarget::from_vec(outputs[0..4].to_vec()); } @@ -98,14 +98,14 @@ impl, const D: usize> CircuitBuilder { merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, ) { + let zero = self.zero(); let mut state: HashOutTarget = self.hash_or_noop(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { - let inputs = [state.elements, sibling.elements] - .concat() - .try_into() - .unwrap(); - let perm_outs = self.permute_swapped(inputs, bit); + let mut perm_inputs = [zero; SPONGE_WIDTH]; + perm_inputs[..4].copy_from_slice(&state.elements); + perm_inputs[4..8].copy_from_slice(&sibling.elements); + let perm_outs = self.permute_swapped(perm_inputs, bit); let hash_outs = perm_outs[0..4].try_into().unwrap(); state = HashOutTarget { elements: hash_outs, From 747c9f894b49c423d2ac4eb1c93e069f59192ee4 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sun, 26 Sep 2021 20:09:26 +0200 Subject: [PATCH 3/4] Back to width 12 --- src/field/field_types.rs | 2 +- src/hash/hashing.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field/field_types.rs b/src/field/field_types.rs index 97db0948..82f27d60 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -16,7 +16,7 @@ use crate::hash::poseidon::Poseidon; use crate::util::bits_u64; /// A prime order field with the features we need to use it as a base field in our argument system. -pub trait RichField: PrimeField + GMiMC<8> + Poseidon<8> {} +pub trait RichField: PrimeField + GMiMC<12> + Poseidon<12> {} /// A finite field. pub trait Field: diff --git a/src/hash/hashing.rs b/src/hash/hashing.rs index 77ee1534..b39bc175 100644 --- a/src/hash/hashing.rs +++ b/src/hash/hashing.rs @@ -9,7 +9,7 @@ use crate::hash::hash_types::{HashOut, HashOutTarget}; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; -pub(crate) const SPONGE_RATE: usize = 4; +pub(crate) const SPONGE_RATE: usize = 8; pub(crate) const SPONGE_CAPACITY: usize = 4; pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; From df9a2114751b88e572922b2d36a9fba821b9d38a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 27 Sep 2021 12:29:27 +0200 Subject: [PATCH 4/4] PR comments --- src/gates/poseidon.rs | 13 ++++++------- src/hash/gmimc.rs | 4 ++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/gates/poseidon.rs b/src/gates/poseidon.rs index bbc42b0d..c45be25f 100644 --- a/src/gates/poseidon.rs +++ b/src/gates/poseidon.rs @@ -5,7 +5,6 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::{Field, RichField}; use crate::gates::gate::Gate; -use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon; use crate::hash::poseidon::Poseidon; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -104,7 +103,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(swap * (swap - F::Extension::ONE)); - let mut state = Vec::with_capacity(SPONGE_WIDTH); + let mut state = Vec::with_capacity(WIDTH); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -115,7 +114,7 @@ where let b = vars.local_wires[i]; state.push(a + swap * (b - a)); } - for i in 8..SPONGE_WIDTH { + for i in 8..WIDTH { state.push(vars.local_wires[i]); } @@ -183,7 +182,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(swap * (swap - F::ONE)); - let mut state = Vec::with_capacity(SPONGE_WIDTH); + let mut state = Vec::with_capacity(WIDTH); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -194,7 +193,7 @@ where let b = vars.local_wires[i]; state.push(a + swap * (b - a)); } - for i in 8..SPONGE_WIDTH { + for i in 8..WIDTH { state.push(vars.local_wires[i]); } @@ -266,7 +265,7 @@ where let swap = vars.local_wires[Self::WIRE_SWAP]; constraints.push(builder.mul_sub_extension(swap, swap, swap)); - let mut state = Vec::with_capacity(SPONGE_WIDTH); + let mut state = Vec::with_capacity(WIDTH); for i in 0..4 { let a = vars.local_wires[i]; let b = vars.local_wires[i + 4]; @@ -279,7 +278,7 @@ where let delta = builder.sub_extension(b, a); state.push(builder.mul_add_extension(swap, delta, a)); } - for i in 8..SPONGE_WIDTH { + for i in 8..WIDTH { state.push(vars.local_wires[i]); } diff --git a/src/hash/gmimc.rs b/src/hash/gmimc.rs index 44af69d6..e64c940f 100644 --- a/src/hash/gmimc.rs +++ b/src/hash/gmimc.rs @@ -87,6 +87,10 @@ impl GMiMC<12> for CrandallField { const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = CRANDALL_AND_GOLDILOCKS_ROUND_CONSTANTS; } +impl GMiMC<8> for GoldilocksField { + const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = CRANDALL_AND_GOLDILOCKS_ROUND_CONSTANTS; +} + impl GMiMC<12> for GoldilocksField { const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = CRANDALL_AND_GOLDILOCKS_ROUND_CONSTANTS; }