Initial implementation of rs-poseidon

This commit is contained in:
Dmitriy Ryajov 2023-04-14 19:12:55 -06:00
commit eec31489c7
No known key found for this signature in database
GPG Key ID: DA8C680CE7C657A4
8 changed files with 25514 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

438
Cargo.lock generated Normal file
View File

@ -0,0 +1,438 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ark-bn254"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea691771ebbb28aea556c044e2e5c5227398d840cee0c34d4d20fa8eb2689e8c"
dependencies = [
"ark-ec",
"ark-ff",
"ark-std",
]
[[package]]
name = "ark-ec"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dea978406c4b1ca13c2db2373b05cc55429c3575b8b21f1b9ee859aa5b03dd42"
dependencies = [
"ark-ff",
"ark-serialize",
"ark-std",
"derivative",
"num-traits",
"zeroize",
]
[[package]]
name = "ark-ff"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6"
dependencies = [
"ark-ff-asm",
"ark-ff-macros",
"ark-serialize",
"ark-std",
"derivative",
"num-bigint",
"num-traits",
"paste",
"rustc_version 0.3.3",
"zeroize",
]
[[package]]
name = "ark-ff-asm"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
name = "ark-ff-macros"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20"
dependencies = [
"num-bigint",
"num-traits",
"quote",
"syn 1.0.109",
]
[[package]]
name = "ark-serialize"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671"
dependencies = [
"ark-std",
"digest",
]
[[package]]
name = "ark-std"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c"
dependencies = [
"num-traits",
"rand",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "convert_case"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version 0.4.0",
"syn 1.0.109",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"rand",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "paste"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
[[package]]
name = "pest"
version = "2.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rs-poseidon"
version = "0.1.0"
dependencies = [
"ark-bn254",
"ark-ff",
"num-bigint",
"num-traits",
"once_cell",
"ruint",
"serde",
"serde_json",
]
[[package]]
name = "ruint"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad3a104dc8c3867f653b0fec89c65e00b0ceb752718ad282177a7e0f33257ac"
dependencies = [
"ark-ff",
"derive_more",
"num-bigint",
"ruint-macro",
"rustc_version 0.4.0",
"serde",
"thiserror",
]
[[package]]
name = "ruint-macro"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62cc5760263ea229d367e7dff3c0cbf09e4797a125bd87059a6c095804f3b2d1"
[[package]]
name = "rustc_version"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
"semver 0.11.0",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.17",
]
[[package]]
name = "ryu"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.160"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
[[package]]
name = "serde_json"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.14",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "zeroize"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.14",
]

23
Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
[package]
name = "rs-poseidon"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = [
"staticlib", # Ensure it gets compiled as a (static) C library
"cdylib", # If you want a shared/dynamic C library (advanced)
"lib", # For downstream Rust dependents: `examples/`, `tests/` etc.
]
[dependencies]
ark-ff = { version = "0.3.0", features = ["std"] }
ark-bn254 = { version = "0.3.0" }
ruint = { version = "1.7.0", features = ["serde", "num-bigint", "ark-ff"] }
serde = "1.0.156"
serde_json = "1.0.94"
once_cell = "1.17.1"
num-traits = "0.2.15"
num-bigint = { version = "0.4", default-features = false, features = ["rand"] }

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# Rust poseidon implementation
This package is a [circomlib](https://github.com/iden3/circomlib/) and [circomlibjs](https://github.com/iden3/circomlibjs) compatible rust poseidon implementation.

1
src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod poseidon;

124
src/poseidon.rs Normal file
View File

@ -0,0 +1,124 @@
mod constants;
use ark_bn254::Fr;
use ark_ff::{Field, Zero};
use ruint::aliases::U256;
const N_ROUNDS_F: u8 = 8;
const N_ROUNDS_P: [i32; 16] = [
56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68,
];
// Add round constants.
fn arc(state: &mut Vec<Fr>, c: &[Fr]) {
for (i, a) in state.iter_mut().enumerate() {
*a += c[i];
}
}
// Sbox function.
fn sbox(state: &mut Vec<Fr>) {
for a in state.iter_mut() {
*a = a.pow([5]);
}
}
// Mix layer.
fn mix(state: &mut Vec<Fr>, m: &[Vec<Fr>]) {
let mut state_new = vec![Fr::zero(); state.len()];
for i in 0..state.len() {
let mut lc = Fr::zero();
for j in 0..state.len() {
lc += m[j][i] * state[j];
}
state_new[i] = lc;
}
*state = state_new;
}
fn full_round(state: &mut Vec<Fr>, c: &[Fr], m: &[Vec<Fr>]) {
sbox(state);
arc(state, c);
mix(state, m);
}
// Compute a Poseidon hash function of the input vector.
//
// # Panics
//
// Panics if `input` is not a valid field element.
#[must_use]
pub fn hash(inputs: &[U256]) -> U256 {
assert!(!inputs.is_empty());
assert!(inputs.len() <= N_ROUNDS_P.len());
let t = inputs.len() + 1;
let n_rounds_f = N_ROUNDS_F as usize;
let n_rounds_p = N_ROUNDS_P[t - 2] as usize;
let c = constants::C_CONST[t - 2].clone();
let s = constants::S_CONST[t - 2].clone();
let m = constants::M_CONST[t - 2].clone();
let p = constants::P_CONST[t - 2].clone();
let mut state: Vec<Fr> = inputs.iter().map(|f| f.try_into().unwrap()).collect();
state.insert(0, Fr::zero());
arc(&mut state, &c[0..t]);
for r in 0..(n_rounds_f / 2) {
if r == (n_rounds_f / 2) - 1 {
full_round(
&mut state,
&c[((n_rounds_f / 2) - 1 + 1) * t..((n_rounds_f / 2) - 1 + 2) * t],
&p,
);
} else {
full_round(&mut state, &c[(r + 1) * t..(r + 2) * t], &m)
}
}
for r in 0..n_rounds_p {
state[0] = state[0].pow([5]);
state[0] += c[(n_rounds_f / 2 + 1) * t + r];
let mut s0 = Fr::zero();
for i in 0..t {
s0 += s[(t * 2 - 1) * r + i] * state[i];
}
for k in 1..t {
state[k] = state[k] + state[0] * s[(t * 2 - 1) * r + t + k - 1];
}
state[0] = s0;
}
for r in 0..(n_rounds_f / 2) - 1 {
full_round(
&mut state,
&c[(n_rounds_f / 2 + 1) * t + n_rounds_p + r * t
..(n_rounds_f / 2 + 1) * t + n_rounds_p + (r + 1) * t]
.to_vec(),
&m,
);
}
sbox(&mut state);
mix(&mut state, &m);
state[0].into()
}
#[cfg(test)]
mod tests {
use super::*;
use ruint::uint;
#[test]
fn test_hash_inputs() {
uint! {
assert_eq!(hash(&[0_U256]), 0x2a09a9fd93c590c26b91effbb2499f07e8f7aa12e2b4940a3aed2411cb65e11c_U256);
assert_eq!(hash(&[0_U256, 0_U256]), 0x2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864_U256);
assert_eq!(hash(&[0_U256, 0_U256, 0_U256]), 0xbc188d27dcceadc1dcfb6af0a7af08fe2864eecec96c5ae7cee6db31ba599aa_U256);
assert_eq!(hash(&[31213_U256, 132_U256]), 0x303f59cd0831b5633bcda50514521b33776b5d4280eb5868ba1dbbe2e4d76ab5_U256);
}
}
}

118
src/poseidon/constants.rs Normal file
View File

@ -0,0 +1,118 @@
use ark_bn254::Fr;
use num_bigint::BigUint;
use once_cell::sync::Lazy;
use num_traits::Num;
const CONSTANTS_STR: &str = include_str!("poseidon_constants_opt.json");
pub static CONSTANTS: Lazy<serde_json::Value> = Lazy::new(|| {
serde_json::from_str(CONSTANTS_STR).unwrap()
});
pub static C_CONST: Lazy<Vec<Vec<Fr>>> = Lazy::new(|| {
CONSTANTS["C"]
.as_array()
.unwrap()
.iter()
.map(|row| {
row.as_array()
.unwrap()
.iter()
.map(|c| {
Fr::try_from(
BigUint::from_str_radix(
c.as_str().unwrap().strip_prefix("0x").unwrap(),
16,
)
.unwrap(),
)
})
.collect::<Result<Vec<Fr>, _>>()
.unwrap()
})
.collect::<Vec<Vec<Fr>>>()
});
pub static S_CONST: Lazy<Vec<Vec<Fr>>> = Lazy::new(|| {
CONSTANTS["S"]
.as_array()
.unwrap()
.iter()
.map(|row| {
row.as_array()
.unwrap()
.iter()
.map(|c| {
Fr::try_from(
BigUint::from_str_radix(
c.as_str().unwrap().strip_prefix("0x").unwrap(),
16,
)
.unwrap(),
)
})
.collect::<Result<Vec<Fr>, _>>()
.unwrap()
})
.collect::<Vec<Vec<Fr>>>()
});
pub static M_CONST: Lazy<Vec<Vec<Vec<Fr>>>> = Lazy::new(|| {
CONSTANTS["M"]
.as_array()
.unwrap()
.iter()
.map(|row| {
row.as_array()
.unwrap()
.iter()
.map(|c| {
c.as_array()
.unwrap()
.iter()
.map(|c| {
Fr::try_from(
BigUint::from_str_radix(
c.as_str().unwrap().strip_prefix("0x").unwrap(),
16,
)
.unwrap(),
)
})
.collect::<Result<Vec<Fr>, _>>()
.unwrap()
})
.collect()
})
.collect::<Vec<Vec<Vec<Fr>>>>()
});
pub static P_CONST: Lazy<Vec<Vec<Vec<Fr>>>> = Lazy::new(|| {
CONSTANTS["P"]
.as_array()
.unwrap()
.iter()
.map(|row| {
row.as_array()
.unwrap()
.iter()
.map(|c| {
c.as_array()
.unwrap()
.iter()
.map(|c| {
Fr::try_from(
BigUint::from_str_radix(
c.as_str().unwrap().strip_prefix("0x").unwrap(),
16,
)
.unwrap(),
)
})
.collect::<Result<Vec<Fr>, _>>()
.unwrap()
})
.collect()
})
.collect::<Vec<Vec<Vec<Fr>>>>()
});

File diff suppressed because it is too large Load Diff