From 9ab46545726cfcd032cd274c8127903a487f9543 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 1 Sep 2019 16:03:57 +0200 Subject: [PATCH] hash arbitrary array size (chunks of 5), add hash_bytes --- README.md | 4 ++-- src/lib.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 005d79e..7d4cf13 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # poseidon-rs [![Build Status](https://travis-ci.org/arnaucube/poseidon-rs.svg?branch=master)](https://travis-ci.org/arnaucube/poseidon-rs) -Poseidon hash implementation in Rust +Poseidon hash implementation in Rust, a zkSNARK friendly hash function. https://eprint.iacr.org/2019/458.pdf -Compatible with the Poseidon Go implementation from https://github.com/iden3/go-iden3-crypto +Compatible with the Poseidon Go implementation done in https://github.com/iden3/go-iden3-crypto ## Warning Do not use in production diff --git a/src/lib.rs b/src/lib.rs index 8bc31d9..a4bd46e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,6 +203,46 @@ impl Poseidon { Ok(state[0].clone()) } + + pub fn hash(&self, inp: Vec) -> Result { + // check if arr elements are inside the finite field over R + if !check_bigint_array_in_field(&inp, &self.constants.r) { + return Err("elements not inside the finite field over R".to_string()); + } + let mut r: BigInt = Zero::zero(); + for i in (0..inp.len()).step_by(5) { + let mut five_elems: Vec = Vec::new(); + for j in 0..5 { + if i + j < inp.len() { + five_elems.push(inp[i + j].clone()); + } else { + five_elems.push(Zero::zero()); + } + } + let ph = &self.poseidon_hash(five_elems); + match ph { + Result::Err(err) => return Err(err.to_string()), + Result::Ok(res) => { + r = modulus(&(r + res), &self.constants.r); + } + } + } + Ok(r) + } + + pub fn hash_bytes(&self, b: Vec) -> Result { + let n = 31; + let mut ints: Vec = Vec::new(); + for i in 0..b.len() / n { + let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[n * i..n * (i + 1)]); + ints.push(v); + } + if b.len() % n != 0 { + let v: BigInt = BigInt::from_bytes_le(Sign::Plus, &b[(b.len() / n) * n..]); + ints.push(v); + } + self.hash(ints) + } } #[cfg(test)] @@ -246,4 +286,22 @@ mod tests { "17185195740979599334254027721507328033796809509313949281114643312710535000993" ); } + + #[test] + fn test_hash_bytes() { + let msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + let poseidon = Poseidon::new(); + let h = poseidon.hash_bytes(msg.as_bytes().to_vec()).unwrap(); + assert_eq!( + h.to_string(), + "11821124228916291136371255062457365369197326845706357273715164664419275913793" + ); + + let msg2 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet."; + let h2 = poseidon.hash_bytes(msg2.as_bytes().to_vec()).unwrap(); + assert_eq!( + h2.to_string(), + "10747013384255785702102976082726575658403084163954725275481577373644732938016" + ); + } }