Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaucube committed May 4, 2023
0 parents commit 91d0a63
Show file tree
Hide file tree
Showing 8 changed files with 4,441 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/test.yml
@@ -0,0 +1,13 @@
name: Test
on: [push, pull_request]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
21 changes: 21 additions & 0 deletions Cargo.toml
@@ -0,0 +1,21 @@
[package]
name = "poseidon-ark"
version = "0.0.1"
authors = ["arnaucube <root@arnaucube.com>"]
edition = "2021"
license = "GPL-3.0"
description = "Poseidon hash implementation"
repository = "https://github.com/arnaucube/poseidon-ark"
readme = "README.md"

[dependencies]
ark-ff = "0.4.0"
ark-bn254 = { version = "0.4.0" }
ark-std = { version = "0.4.0" }

[dev-dependencies]
criterion = "0.3"

[[bench]]
name = "bench_poseidon_hash"
harness = false
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions README.md
@@ -0,0 +1,16 @@
# poseidon-ark [![Test](https://github.com/arnaucube/poseidon-ark/workflows/Test/badge.svg)](https://github.com/arnaucube/poseidon-ark/actions?query=workflow%3ATest)

> **Note**: this repo is a fork from https://github.com/arnaucube/poseidon-rs , porting it to arkworks [ff](https://github.com/arkworks-rs/algebra/tree/master/ff).
Poseidon hash implementation in Rust, a zkSNARK friendly hash function.

https://eprint.iacr.org/2019/458.pdf

Compatible with the Poseidon implementations:
- Sage (reference implementation): https://extgit.iaik.tugraz.at/krypto/hadeshash
- Go: https://github.com/iden3/go-iden3-crypto
- Js & circom: https://github.com/iden3/circomlib

## Warning
Do not use in production

28 changes: 28 additions & 0 deletions benches/bench_poseidon_hash.rs
@@ -0,0 +1,28 @@
use criterion::{criterion_group, criterion_main, Criterion};

use ark_bn254::Fr;
use poseidon_rs::Poseidon;

use ark_std::str::FromStr;

fn criterion_benchmark(c: &mut Criterion) {
let b1: Fr = Fr::from_str(
"12242166908188651009877250812424843524687801523336557272219921456462821518061",
)
.unwrap();
let b2: Fr = Fr::from_str(
"12242166908188651009877250812424843524687801523336557272219921456462821518061",
)
.unwrap();
let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b1.clone());
big_arr.push(b2.clone());
let poseidon = Poseidon::new();

c.bench_function("hash", |b| {
b.iter(|| poseidon.hash(big_arr.clone()).unwrap())
});
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
3,452 changes: 3,452 additions & 0 deletions src/constants.rs

Large diffs are not rendered by default.

234 changes: 234 additions & 0 deletions src/lib.rs
@@ -0,0 +1,234 @@
use ark_bn254::Fr;
use ark_ff::fields::Field;
use ark_std::str::FromStr;
use ark_std::Zero;
use core::ops::{AddAssign, MulAssign};

mod constants;

#[derive(Debug)]
pub struct Constants {
pub c: Vec<Vec<Fr>>,
pub m: Vec<Vec<Vec<Fr>>>,
pub n_rounds_f: usize,
pub n_rounds_p: Vec<usize>,
}

pub fn load_constants() -> Constants {
let (c_str, m_str) = constants::constants();
let mut c: Vec<Vec<Fr>> = Vec::new();
for i in 0..c_str.len() {
let mut cci: Vec<Fr> = Vec::new();
for j in 0..c_str[i].len() {
let b: Fr = Fr::from_str(c_str[i][j]).unwrap();
cci.push(b);
}
c.push(cci);
}
let mut m: Vec<Vec<Vec<Fr>>> = Vec::new();
for i in 0..m_str.len() {
let mut mi: Vec<Vec<Fr>> = Vec::new();
for j in 0..m_str[i].len() {
let mut mij: Vec<Fr> = Vec::new();
for k in 0..m_str[i][j].len() {
let b: Fr = Fr::from_str(m_str[i][j][k]).unwrap();
mij.push(b);
}
mi.push(mij);
}
m.push(mi);
}
Constants {
c,
m,
n_rounds_f: 8,
n_rounds_p: vec![56, 57, 56, 60, 60, 63, 64, 63],
}
}

pub struct Poseidon {
constants: Constants,
}
impl Poseidon {
pub fn new() -> Poseidon {
Poseidon {
constants: load_constants(),
}
}
pub fn ark(&self, state: &mut Vec<Fr>, c: &[Fr], it: usize) {
for i in 0..state.len() {
state[i].add_assign(&c[it + i]);
}
}

pub fn sbox(&self, n_rounds_f: usize, n_rounds_p: usize, state: &mut Vec<Fr>, i: usize) {
if i < n_rounds_f / 2 || i >= n_rounds_f / 2 + n_rounds_p {
for j in 0..state.len() {
let aux = state[j];
state[j] = state[j].square();
state[j] = state[j].square();
state[j].mul_assign(&aux);
}
} else {
let aux = state[0];
state[0] = state[0].square();
state[0] = state[0].square();
state[0].mul_assign(&aux);
}
}

pub fn mix(&self, state: &Vec<Fr>, m: &[Vec<Fr>]) -> Vec<Fr> {
let mut new_state: Vec<Fr> = Vec::new();
for i in 0..state.len() {
new_state.push(Fr::zero());
for j in 0..state.len() {
let mut mij = m[i][j];
mij.mul_assign(&state[j]);
new_state[i].add_assign(&mij);
}
}
new_state.clone()
}

pub fn hash(&self, inp: Vec<Fr>) -> Result<Fr, String> {
let t = inp.len() + 1;
if inp.is_empty() || inp.len() >= self.constants.n_rounds_p.len() - 1 {
return Err("Wrong inputs length".to_string());
}
let n_rounds_f = self.constants.n_rounds_f.clone();
let n_rounds_p = self.constants.n_rounds_p[t - 2].clone();

let mut state = vec![Fr::zero(); t];
state[1..].clone_from_slice(&inp);

for i in 0..(n_rounds_f + n_rounds_p) {
self.ark(&mut state, &self.constants.c[t - 2], i * t);
self.sbox(n_rounds_f, n_rounds_p, &mut state, i);
state = self.mix(&state, &self.constants.m[t - 2]);
}

Ok(state[0])
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_load_constants() {
let cons = load_constants();
assert_eq!(
cons.c[0][0].to_string(),
"4417881134626180770308697923359573201005643519861877412381846989312604493735"
);
assert_eq!(
cons.c[cons.c.len() - 1][0].to_string(),
"14715728137766105031387583973733149375806784983272780095398485311648630967927"
);
assert_eq!(
cons.m[0][0][0].to_string(),
"2910766817845651019878574839501801340070030115151021261302834310722729507541"
);
assert_eq!(
cons.m[cons.m.len() - 1][0][0].to_string(),
"708458300293891745856425423607721463509413916954480913172999113933455141974"
);
}

#[test]
fn test_hash() {
let b0: Fr = Fr::from_str("0").unwrap();
let b1: Fr = Fr::from_str("1").unwrap();
let b2: Fr = Fr::from_str("2").unwrap();
let b3: Fr = Fr::from_str("3").unwrap();
let b4: Fr = Fr::from_str("4").unwrap();
let b5: Fr = Fr::from_str("5").unwrap();
let b6: Fr = Fr::from_str("6").unwrap();

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b1.clone());
let poseidon = Poseidon::new();
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"18586133768512220936620570745912940619677854269274689475585506675881198879027"
);

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b1.clone());
big_arr.push(b2.clone());
let poseidon = Poseidon::new();
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"7853200120776062878684798364095072458815029376092732009249414926327459813530"
);

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b1.clone());
big_arr.push(b2.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
let poseidon = Poseidon::new();
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"1018317224307729531995786483840663576608797660851238720571059489595066344487"
);

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b1.clone());
big_arr.push(b2.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
let poseidon = Poseidon::new();
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"15336558801450556532856248569924170992202208561737609669134139141992924267169"
);

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b3.clone());
big_arr.push(b4.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
let poseidon = Poseidon::new();
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"5811595552068139067952687508729883632420015185677766880877743348592482390548"
);

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b3.clone());
big_arr.push(b4.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
big_arr.push(b0.clone());
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"12263118664590987767234828103155242843640892839966517009184493198782366909018"
);

let mut big_arr: Vec<Fr> = Vec::new();
big_arr.push(b1.clone());
big_arr.push(b2.clone());
big_arr.push(b3.clone());
big_arr.push(b4.clone());
big_arr.push(b5.clone());
big_arr.push(b6.clone());
let h = poseidon.hash(big_arr.clone()).unwrap();
assert_eq!(
h.to_string(),
"20400040500897583745843009878988256314335038853985262692600694741116813247201"
);
}
}

0 comments on commit 91d0a63

Please sign in to comment.