2021-03-21 19:50:05 -07:00
|
|
|
//! Concrete instantiation of a hash function.
|
|
|
|
|
|
2021-04-21 22:31:45 +02:00
|
|
|
use crate::circuit_builder::CircuitBuilder;
|
2021-03-21 19:50:05 -07:00
|
|
|
use crate::field::field::Field;
|
2021-03-30 20:16:20 -07:00
|
|
|
use crate::gmimc::gmimc_permute_array;
|
2021-04-12 10:38:07 +02:00
|
|
|
use crate::proof::{Hash, HashTarget};
|
|
|
|
|
use crate::target::Target;
|
2021-03-21 19:50:05 -07:00
|
|
|
|
2021-03-31 21:15:24 -07:00
|
|
|
pub(crate) const SPONGE_RATE: usize = 8;
|
|
|
|
|
pub(crate) const SPONGE_CAPACITY: usize = 4;
|
|
|
|
|
pub(crate) const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY;
|
2021-03-21 19:50:05 -07:00
|
|
|
|
2021-04-06 13:14:59 -07:00
|
|
|
pub const GMIMC_ROUNDS: usize = 101;
|
2021-04-02 15:29:21 -07:00
|
|
|
/// This is the result of `gmimc_automatic_constants`; i.e. it's from ChaCha20 seeded with 0.
|
2021-04-21 22:31:45 +02:00
|
|
|
pub const GMIMC_CONSTANTS: [u64; GMIMC_ROUNDS] = [
|
|
|
|
|
13080132715619999810,
|
|
|
|
|
8594738768332784433,
|
|
|
|
|
12896916466795114362,
|
|
|
|
|
1109962092924985887,
|
|
|
|
|
16216730424513838303,
|
|
|
|
|
10137062674532189451,
|
|
|
|
|
15292064468290167604,
|
|
|
|
|
17255573296743700660,
|
|
|
|
|
14827154243383347999,
|
|
|
|
|
2846171648262623971,
|
|
|
|
|
16246264665335217464,
|
|
|
|
|
14214208089399786945,
|
|
|
|
|
9667108688411000080,
|
|
|
|
|
6470857421371427314,
|
|
|
|
|
14103331941574951088,
|
|
|
|
|
11854816474757864855,
|
|
|
|
|
3498097497657653643,
|
|
|
|
|
7947235693333396721,
|
|
|
|
|
11110078702363612411,
|
|
|
|
|
16384314114341783099,
|
|
|
|
|
15404405914224921002,
|
|
|
|
|
14077880832148466479,
|
|
|
|
|
9555554663682579629,
|
|
|
|
|
13859595359622389547,
|
|
|
|
|
16859897326779206643,
|
|
|
|
|
17685474422023725021,
|
|
|
|
|
17858764736437889563,
|
|
|
|
|
9410011023624402450,
|
|
|
|
|
12495243630852222748,
|
|
|
|
|
12416945299436348089,
|
|
|
|
|
5776666812952701944,
|
|
|
|
|
6314421663507268983,
|
|
|
|
|
7402742472177291738,
|
|
|
|
|
982536713292517255,
|
|
|
|
|
17321168867539521172,
|
|
|
|
|
2934354895304883596,
|
|
|
|
|
10567510599683852824,
|
|
|
|
|
8135543734546633309,
|
|
|
|
|
116353493093565855,
|
|
|
|
|
8029688164312877009,
|
|
|
|
|
9003846638141970076,
|
|
|
|
|
7052445133185619935,
|
|
|
|
|
9645665433271393194,
|
|
|
|
|
5446430061585660707,
|
|
|
|
|
16770910636054378912,
|
|
|
|
|
17708360573237778662,
|
|
|
|
|
4661556288797079635,
|
|
|
|
|
11977051900536351292,
|
|
|
|
|
4378616569536950472,
|
|
|
|
|
3334807503157233344,
|
|
|
|
|
8019184736760206441,
|
|
|
|
|
2395043909056213726,
|
|
|
|
|
6558421058999795722,
|
|
|
|
|
11735894061922784518,
|
|
|
|
|
8143540539718733269,
|
|
|
|
|
5991753490174091591,
|
|
|
|
|
12235918792748480378,
|
|
|
|
|
2880312033996085535,
|
|
|
|
|
18224748117164817283,
|
|
|
|
|
18070411014966027790,
|
|
|
|
|
8156487614951798795,
|
|
|
|
|
10615269511128318233,
|
|
|
|
|
12489426406026437595,
|
|
|
|
|
5055279340584943685,
|
|
|
|
|
7231927320516917417,
|
|
|
|
|
2602078848371820415,
|
|
|
|
|
12445944370602567717,
|
|
|
|
|
3978905924297801117,
|
|
|
|
|
16711272946032085229,
|
|
|
|
|
10439032362290464320,
|
|
|
|
|
15110119873264383151,
|
|
|
|
|
821141790739535246,
|
|
|
|
|
11073536381779174375,
|
|
|
|
|
4866839313593360589,
|
|
|
|
|
13118391690850240703,
|
|
|
|
|
14527674975242150843,
|
|
|
|
|
7612751960041028847,
|
|
|
|
|
6808090908507673494,
|
|
|
|
|
6899703780195472329,
|
|
|
|
|
3664666286710282218,
|
|
|
|
|
783179505504239941,
|
|
|
|
|
8990689242729919931,
|
|
|
|
|
9646603556395461579,
|
|
|
|
|
7351246026916028004,
|
|
|
|
|
16970959815450893036,
|
|
|
|
|
15735726859844361172,
|
|
|
|
|
10347018222946250943,
|
|
|
|
|
12195545879691602738,
|
|
|
|
|
7423314197870213963,
|
|
|
|
|
14908016118492485461,
|
|
|
|
|
5840340123122280205,
|
|
|
|
|
17740311464247702688,
|
|
|
|
|
815306422036794512,
|
|
|
|
|
17456357369997417977,
|
|
|
|
|
6982651077270605698,
|
|
|
|
|
11970987325834369417,
|
|
|
|
|
8167785009370061651,
|
|
|
|
|
9483259820363401119,
|
|
|
|
|
954550221761525285,
|
|
|
|
|
10339565172077536587,
|
|
|
|
|
8651171085167737860,
|
|
|
|
|
];
|
2021-03-21 19:50:05 -07:00
|
|
|
|
2021-04-01 12:49:31 -07:00
|
|
|
/// Controls the granularity of parallelization when building Merkle trees. I.e., we will try to
|
|
|
|
|
/// split up the task into units of work, such that each unit involves hashing roughly this many
|
|
|
|
|
/// elements. If this is too small, there may be too much synchronization overhead; if it's too
|
|
|
|
|
/// large, some threads may spend significant time idle.
|
2021-03-31 21:15:24 -07:00
|
|
|
const ELEMS_PER_CHUNK: usize = 1 << 8;
|
|
|
|
|
|
2021-03-25 15:20:14 -07:00
|
|
|
/// Hash the vector if necessary to reduce its length to ~256 bits. If it already fits, this is a
|
|
|
|
|
/// no-op.
|
2021-04-12 10:38:07 +02:00
|
|
|
pub fn hash_or_noop<F: Field>(inputs: Vec<F>) -> Hash<F> {
|
2021-03-25 15:20:14 -07:00
|
|
|
if inputs.len() <= 4 {
|
|
|
|
|
Hash::from_partial(inputs)
|
|
|
|
|
} else {
|
|
|
|
|
hash_n_to_hash(inputs, false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
impl<F: Field> CircuitBuilder<F> {
|
|
|
|
|
pub fn hash_or_noop(&mut self, inputs: Vec<Target>) -> HashTarget {
|
|
|
|
|
let zero = self.zero();
|
|
|
|
|
if inputs.len() <= 4 {
|
|
|
|
|
HashTarget::from_partial(inputs, zero)
|
|
|
|
|
} else {
|
|
|
|
|
self.hash_n_to_hash(inputs, false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn hash_n_to_hash(&mut self, inputs: Vec<Target>, pad: bool) -> HashTarget {
|
|
|
|
|
HashTarget::from_vec(self.hash_n_to_m(inputs, 4, pad))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn hash_n_to_m(
|
|
|
|
|
&mut self,
|
|
|
|
|
mut inputs: Vec<Target>,
|
|
|
|
|
num_outputs: usize,
|
|
|
|
|
pad: bool,
|
|
|
|
|
) -> Vec<Target> {
|
|
|
|
|
let zero = self.zero();
|
|
|
|
|
let one = self.one();
|
|
|
|
|
|
|
|
|
|
if pad {
|
|
|
|
|
inputs.push(zero);
|
|
|
|
|
while (inputs.len() + 1) % SPONGE_WIDTH != 0 {
|
|
|
|
|
inputs.push(one);
|
|
|
|
|
}
|
|
|
|
|
inputs.push(zero);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut state = [zero; SPONGE_WIDTH];
|
|
|
|
|
|
|
|
|
|
// Absorb all input chunks.
|
|
|
|
|
for input_chunk in inputs.chunks(SPONGE_RATE) {
|
|
|
|
|
// Overwrite the first r elements with the inputs. This differs from a standard sponge,
|
|
|
|
|
// where we would xor or add in the inputs. This is a well-known variant, though,
|
|
|
|
|
// sometimes called "overwrite mode".
|
2021-04-23 12:35:19 -07:00
|
|
|
state[..input_chunk.len()].copy_from_slice(input_chunk);
|
2021-04-12 10:38:07 +02:00
|
|
|
state = self.permute(state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Squeeze until we have the desired number of outputs.
|
|
|
|
|
let mut outputs = Vec::new();
|
|
|
|
|
loop {
|
|
|
|
|
for i in 0..SPONGE_RATE {
|
|
|
|
|
outputs.push(state[i]);
|
|
|
|
|
if outputs.len() == num_outputs {
|
|
|
|
|
return outputs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
state = self.permute(state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 15:20:14 -07:00
|
|
|
/// A one-way compression function which takes two ~256 bit inputs and returns a ~256 bit output.
|
|
|
|
|
pub fn compress<F: Field>(x: Hash<F>, y: Hash<F>) -> Hash<F> {
|
|
|
|
|
let mut inputs = Vec::with_capacity(8);
|
|
|
|
|
inputs.extend(&x.elements);
|
|
|
|
|
inputs.extend(&y.elements);
|
|
|
|
|
hash_n_to_hash(inputs, false)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 21:15:24 -07:00
|
|
|
pub fn permute<F: Field>(xs: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] {
|
|
|
|
|
gmimc_permute_array(xs, GMIMC_CONSTANTS)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 19:50:05 -07:00
|
|
|
/// 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<F: Field>(mut inputs: Vec<F>, num_outputs: usize, pad: bool) -> Vec<F> {
|
|
|
|
|
if pad {
|
|
|
|
|
inputs.push(F::ZERO);
|
2021-03-31 21:15:24 -07:00
|
|
|
while (inputs.len() + 1) % SPONGE_WIDTH != 0 {
|
2021-03-21 19:50:05 -07:00
|
|
|
inputs.push(F::ONE);
|
|
|
|
|
}
|
|
|
|
|
inputs.push(F::ZERO);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 21:15:24 -07:00
|
|
|
let mut state = [F::ZERO; SPONGE_WIDTH];
|
2021-03-21 19:50:05 -07:00
|
|
|
|
|
|
|
|
// Absorb all input chunks.
|
2021-04-12 10:38:07 +02:00
|
|
|
for input_chunk in inputs.chunks(SPONGE_RATE) {
|
2021-03-21 19:50:05 -07:00
|
|
|
for i in 0..input_chunk.len() {
|
2021-03-31 21:15:24 -07:00
|
|
|
state[i] += input_chunk[i];
|
2021-03-21 19:50:05 -07:00
|
|
|
}
|
2021-03-31 21:15:24 -07:00
|
|
|
state = permute(state);
|
2021-03-21 19:50:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Squeeze until we have the desired number of outputs.
|
|
|
|
|
let mut outputs = Vec::new();
|
|
|
|
|
loop {
|
2021-04-12 10:38:07 +02:00
|
|
|
for i in 0..SPONGE_RATE {
|
2021-03-21 19:50:05 -07:00
|
|
|
outputs.push(state[i]);
|
|
|
|
|
if outputs.len() == num_outputs {
|
|
|
|
|
return outputs;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-31 21:15:24 -07:00
|
|
|
state = permute(state);
|
2021-03-21 19:50:05 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn hash_n_to_hash<F: Field>(inputs: Vec<F>, pad: bool) -> Hash<F> {
|
2021-04-12 10:38:07 +02:00
|
|
|
Hash::from_vec(hash_n_to_m(inputs, 4, pad))
|
2021-03-21 19:50:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn hash_n_to_1<F: Field>(inputs: Vec<F>, pad: bool) -> F {
|
|
|
|
|
hash_n_to_m(inputs, 1, pad)[0]
|
|
|
|
|
}
|