From c76eb9ddeb98b13c5409e7d5a7c87b69e34cc65c Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 13 Sep 2021 10:22:25 -0700 Subject: [PATCH] Prepare for the switch to Poseidon (#228) * Prepare for the switch to Poseidon Everything will now select a permutation based on the `PERMUTATION_FAMILY` const. The `Poseidon` variant won't work quite yet since the gate isn't in place; I left that as a `todo!()` * fix --- src/field/field_types.rs | 3 ++- src/gadgets/hash.rs | 37 ++++++++++++++++++++++++--- src/hash/hashing.rs | 53 +++++++++++---------------------------- src/hash/merkle_proofs.rs | 41 +++++------------------------- 4 files changed, 57 insertions(+), 77 deletions(-) diff --git a/src/field/field_types.rs b/src/field/field_types.rs index 0038dec7..3fb214e0 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -12,10 +12,11 @@ use serde::Serialize; use crate::field::extension_field::Frobenius; use crate::hash::gmimc::GMiMC; +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> {} +pub trait RichField: PrimeField + GMiMC<12> + Poseidon<12> {} /// A finite field. pub trait Field: diff --git a/src/gadgets/hash.rs b/src/gadgets/hash.rs index 48a728d7..01519912 100644 --- a/src/gadgets/hash.rs +++ b/src/gadgets/hash.rs @@ -4,7 +4,8 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::RichField; use crate::gates::gmimc::GMiMCGate; use crate::hash::gmimc::GMiMC; -use crate::iop::target::Target; +use crate::hash::hashing::{HashFamily, HASH_FAMILY}; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::wire::Wire; use crate::plonk::circuit_builder::CircuitBuilder; @@ -14,7 +15,37 @@ impl, const D: usize> CircuitBuilder { where F: GMiMC, { - let zero = self.zero(); + // We don't want to swap any inputs, so set that wire to 0. + let _false = self._false(); + self.permute_swapped(inputs, _false) + } + + /// Conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), then apply + /// a cryptographic permutation. + pub(crate) fn permute_swapped( + &mut self, + inputs: [Target; W], + swap: BoolTarget, + ) -> [Target; W] + where + F: GMiMC, + { + match HASH_FAMILY { + HashFamily::GMiMC => self.gmimc_permute_swapped(inputs, swap), + HashFamily::Poseidon => todo!(), + } + } + + /// Conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), then apply + /// the GMiMC permutation. + pub(crate) fn gmimc_permute_swapped( + &mut self, + inputs: [Target; W], + swap: BoolTarget, + ) -> [Target; W] + where + F: GMiMC, + { let gate_type = GMiMCGate::::new(); let gate = self.add_gate(gate_type, vec![]); @@ -24,7 +55,7 @@ impl, const D: usize> CircuitBuilder { gate, input: swap_wire, }); - self.connect(zero, swap_wire); + self.connect(swap.target, swap_wire); // Route input wires. for i in 0..W { diff --git a/src/hash/hashing.rs b/src/hash/hashing.rs index 3b496445..6e243773 100644 --- a/src/hash/hashing.rs +++ b/src/hash/hashing.rs @@ -11,38 +11,12 @@ pub(crate) const SPONGE_RATE: usize = 8; pub(crate) const SPONGE_CAPACITY: usize = 4; pub(crate) const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; -pub const NUM_ROUNDS: usize = 101; +pub(crate) const HASH_FAMILY: HashFamily = HashFamily::GMiMC; -/// This is the result of `gmimc_automatic_constants`; i.e. it's from ChaCha20 seeded with 0. -#[rustfmt::skip] -pub const ROUND_CONSTANTS: [u64; NUM_ROUNDS] = [ - 0xb585f767417ee042, 0x7746a55f77c10331, 0xb2fb0d321d356f7a, 0x0f6760a486f1621f, - 0xe10d6666b36abcdf, 0x8cae14cb455cc50b, 0xd438539cf2cee334, 0xef781c7d4c1fd8b4, - 0xcdc4a23a0aca4b1f, 0x277fa208d07b52e3, 0xe17653a300493d38, 0xc54302f27c287dc1, - 0x8628782231d47d10, 0x59cd1a8a690b49f2, 0xc3b919ad9efec0b0, 0xa484c4c637641d97, - 0x308bbd23f191398b, 0x6e4a40c1bf713cf1, 0x9a2eedb7510414fb, 0xe360c6e111c2c63b, - 0xd5c771901d4d89aa, 0xc35eae076e7d6b2f, 0x849c2656d0a09cad, 0xc0572c8c5cf1df2b, - 0xe9fa634a883b8bf3, 0xf56f6d4900fb1fdd, 0xf7d713e872a72a1b, 0x8297132b6ba47612, - 0xad6805e12ee8af1c, 0xac51d9f6485c22b9, 0x502ad7dc3bd56bf8, 0x57a1550c3761c577, - 0x66bbd30e99d311da, 0x0da2abef5e948f87, 0xf0612750443f8e94, 0x28b8ec3afb937d8c, - 0x92a756e6be54ca18, 0x70e741ec304e925d, 0x019d5ee2b037c59f, 0x6f6f2ed7a30707d1, - 0x7cf416d01e8c169c, 0x61df517bb17617df, 0x85dc499b4c67dbaa, 0x4b959b48dad27b23, - 0xe8be3e5e0dd779a0, 0xf5c0bc1e525ed8e6, 0x40b12cbf263cf853, 0xa637093f13e2ea3c, - 0x3cc3f89232e3b0c8, 0x2e479dc16bfe86c0, 0x6f49de07d6d39469, 0x213ce7beecc232de, - 0x5b043134851fc00a, 0xa2de45784a861506, 0x7103aaf97bed8dd5, 0x5326fc0dbb88a147, - 0xa9ceb750364cb77a, 0x27f8ec88cc9e991f, 0xfceb4fda8c93fb83, 0xfac6ff13b45b260e, - 0x7131aa455813380b, 0x93510360d5d68119, 0xad535b24fb96e3db, 0x4627f5c6b7efc045, - 0x645cf794e4da78a9, 0x241c70ed1ac2877f, 0xacb8e076b009e825, 0x3737e9db6477bd9d, - 0xe7ea5e344cd688ed, 0x90dee4a009214640, 0xd1b1edf7c77e74af, 0x0b65481bab42158e, - 0x99ad1aab4b4fe3e7, 0x438a7c91f1a360cd, 0xb60de3bd159088bf, 0xc99cab6b47a3e3bb, - 0x69a5ed92d5677cef, 0x5e7b329c482a9396, 0x5fc0ac0829f893c9, 0x32db82924fb757ea, - 0x0ade699c5cf24145, 0x7cc5583b46d7b5bb, 0x85df9ed31bf8abcb, 0x6604df501ad4de64, - 0xeb84f60941611aec, 0xda60883523989bd4, 0x8f97fe40bf3470bf, 0xa93f485ce0ff2b32, - 0x6704e8eebc2afb4b, 0xcee3e9ac788ad755, 0x510d0e66062a270d, 0xf6323f48d74634a0, - 0x0b508cdf04990c90, 0xf241708a4ef7ddf9, 0x60e75c28bb368f82, 0xa6217d8c3f0f9989, - 0x7159cd30f5435b53, 0x839b4e8fe97ec79f, 0x0d3f3e5e885db625, 0x8f7d83be1daea54b, - 0x780f22441e8dbc04, -]; +pub(crate) enum HashFamily { + GMiMC, + Poseidon, +} /// Hash the vector if necessary to reduce its length to ~256 bits. If it already fits, this is a /// no-op. @@ -121,11 +95,7 @@ pub fn compress(x: HashOut, y: HashOut) -> HashOut { /// If `pad` is enabled, the message is padded using the pad10*1 rule. In general this is required /// for the hash to be secure, but it can safely be disabled in certain cases, like if the input /// length is fixed. -pub fn hash_n_to_m>( - mut inputs: Vec, - num_outputs: usize, - pad: bool, -) -> Vec { +pub fn hash_n_to_m(mut inputs: Vec, num_outputs: usize, pad: bool) -> Vec { if pad { inputs.push(F::ZERO); while (inputs.len() + 1) % SPONGE_WIDTH != 0 { @@ -141,7 +111,7 @@ pub fn hash_n_to_m>( for i in 0..input_chunk.len() { state[i] = input_chunk[i]; } - state = F::gmimc_permute(state); + state = permute(state); } // Squeeze until we have the desired number of outputs. @@ -153,7 +123,7 @@ pub fn hash_n_to_m>( return outputs; } } - state = F::gmimc_permute(state); + state = permute(state); } } @@ -164,3 +134,10 @@ pub fn hash_n_to_hash(inputs: Vec, pad: bool) -> HashOut { pub fn hash_n_to_1(inputs: Vec, pad: bool) -> F { hash_n_to_m(inputs, 1, pad)[0] } + +pub(crate) fn permute(inputs: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] { + match HASH_FAMILY { + HashFamily::GMiMC => F::gmimc_permute(inputs), + HashFamily::Poseidon => F::poseidon(inputs), + } +} diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index 5aad9193..22b6f318 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -70,41 +70,12 @@ impl, const D: usize> CircuitBuilder { let mut state: HashOutTarget = self.hash_or_noop(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { - let gate_type = GMiMCGate::::new(); - let gate = self.add_gate(gate_type, vec![]); - - let swap_wire = GMiMCGate::::WIRE_SWAP; - let swap_wire = Target::Wire(Wire { - gate, - input: swap_wire, - }); - self.connect(bit.target, swap_wire); - - let input_wires = (0..12) - .map(|i| { - Target::Wire(Wire { - gate, - input: GMiMCGate::::wire_input(i), - }) - }) - .collect::>(); - - for i in 0..4 { - self.connect(state.elements[i], input_wires[i]); - self.connect(sibling.elements[i], input_wires[4 + i]); - self.connect(zero, input_wires[8 + i]); - } - - state = HashOutTarget::from_vec( - (0..4) - .map(|i| { - Target::Wire(Wire { - gate, - input: GMiMCGate::::wire_output(i), - }) - }) - .collect(), - ) + let inputs = [state.elements, sibling.elements, [zero; 4]] + .concat() + .try_into() + .unwrap(); + let outputs = self.gmimc_permute_swapped(inputs, bit); + state = HashOutTarget::from_vec(outputs[0..4].to_vec()); } let index = self.le_sum(leaf_index_bits[proof.siblings.len()..].to_vec().into_iter());