From 246b0ea709b68ce5e390d4680bd8a383a90639c9 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 11 Dec 2024 17:24:29 +0800 Subject: [PATCH 1/6] generic poseidon2 impl --- Cargo.toml | 4 +- poseidon2/CHANGELOG.md | 9 +++ poseidon2/Cargo.toml | 15 +++++ poseidon2/src/external.rs | 96 ++++++++++++++++++++++++++++++ poseidon2/src/internal.rs | 33 +++++++++++ poseidon2/src/lib.rs | 122 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 poseidon2/CHANGELOG.md create mode 100644 poseidon2/Cargo.toml create mode 100644 poseidon2/src/external.rs create mode 100644 poseidon2/src/internal.rs create mode 100644 poseidon2/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 06d1c8d11..7174f780f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["aead", "commitment", "crhf", "elgamal", "merkle_tree", "pcs", "plonk", "prf", "relation", "rescue", "signature", "utilities", "vid", "vrf"] +members = ["aead", "commitment", "crhf", "elgamal", "merkle_tree", "pcs", "plonk", "poseidon2", "prf", "relation", "rescue", "signature", "utilities", "vid", "vrf"] resolver = "2" [workspace.package] @@ -22,7 +22,7 @@ ark-poly = { version = "0.4.0", default-features = false } ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] } ark-std = { version = "0.4.0", default-features = false } derivative = { version = "2", features = ["use_core"] } -digest = { version = "0.10.1", default-features = false, features = [ "alloc" ] } +digest = { version = "0.10.7", default-features = false, features = [ "alloc" ] } displaydoc = { version = "0.2", default-features = false } hashbrown = "0.14.3" merlin = { version = "3.0.0", default-features = false } diff --git a/poseidon2/CHANGELOG.md b/poseidon2/CHANGELOG.md new file mode 100644 index 000000000..52a92de8d --- /dev/null +++ b/poseidon2/CHANGELOG.md @@ -0,0 +1,9 @@ +# CHANGELOG + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## 0.1.0 + +- Initial release. diff --git a/poseidon2/Cargo.toml b/poseidon2/Cargo.toml new file mode 100644 index 000000000..bb0f71fb2 --- /dev/null +++ b/poseidon2/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "jf-poseidon2" +version = "0.1.0" +description = "Poseidon2 algebraic hash functions implementation." +authors = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +rust-version = { workspace = true } +homepage = { workspace = true } +documentation = { workspace = true } +repository = { workspace = true } + +[dependencies] +ark-ff = { workspace = true } +ark-std = { workspace = true } diff --git a/poseidon2/src/external.rs b/poseidon2/src/external.rs new file mode 100644 index 000000000..bd79c0dc3 --- /dev/null +++ b/poseidon2/src/external.rs @@ -0,0 +1,96 @@ +//! Generic implementation for external layers + +use ark_ff::PrimeField; + +use crate::add_rc_and_sbox; + +/// The fastest 4x4 MDS matrix. +/// [ 2 3 1 1 ] +/// [ 1 2 3 1 ] +/// [ 1 1 2 3 ] +/// [ 3 1 1 2 ] +/// +/// This requires 7 additions and 2 doubles to compute. +/// credit: Plonky3 +#[derive(Clone, Default)] +struct MDSMat4; + +impl MDSMat4 { + /// x := M4 * x where M4 is the 4x4 MDS matrix + #[inline(always)] + fn matmul(x: &mut [F; 4]) { + let t01 = x[0] + x[1]; + let t23 = x[2] + x[3]; + let t0123 = t01 + t23; + let t01123 = t0123 + x[1]; + let t01233 = t0123 + x[3]; + // The order here is important. Need to overwrite x[0] and x[2] after x[1] and + // x[3]. + x[3] = t01233 + x[0].double(); // 3*x[0] + x[1] + x[2] + 2*x[3] + x[1] = t01123 + x[2].double(); // x[0] + 2*x[1] + 3*x[2] + x[3] + x[0] = t01123 + t01; // 2*x[0] + 3*x[1] + x[2] + x[3] + x[2] = t01233 + t23; // x[0] + x[1] + 2*x[2] + 3*x[3] + } +} + +#[inline(always)] +/// Matrix multiplication in the external layers +// @credit: `matmul_external` in zkhash, `mds_light_permutation` in plonky3 +pub(super) fn matmul_external(state: &mut [F; T]) { + match T { + 2 => { + let sum = state[0] + state[1]; + state[0] += sum; + state[1] += sum; + }, + + 3 => { + let sum = state[0] + state[1] + state[2]; + state[0] += sum; + state[1] += sum; + state[2] += sum; + }, + + // Given a 4x4 MDS matrix M, we multiply by the `4N x 4N` matrix + // `[[2M M ... M], [M 2M ... M], ..., [M M ... 2M]]`. + 4 | 8 | 12 | 16 | 20 | 24 => { + // First, we apply M_4 to each consecutive four elements of the state. + // In Appendix B's terminology, this replaces each x_i with x_i'. + for chunk in state.chunks_exact_mut(4) { + MDSMat4::matmul(chunk.try_into().unwrap()); + } + // Now, we apply the outer circulant matrix (to compute the y_i values). + + // We first precompute the four sums of every four elements. + let sums: [F; 4] = + core::array::from_fn(|k| (0..T).step_by(4).map(|j| state[j + k]).sum::()); + + // The formula for each y_i involves 2x_i' term and x_j' terms for each j that + // equals i mod 4. In other words, we can add a single copy of x_i' + // to the appropriate one of our precomputed sums + state + .iter_mut() + .enumerate() + .for_each(|(i, elem)| *elem += sums[i % 4]); + }, + + _ => { + panic!("Unsupported state size"); + }, + } +} + +#[inline(always)] +/// One external round +// @credit `external_terminal_permute_state` in plonky3 +pub(crate) fn permute_state( + state: &mut [F; T], + rc: &'static [F; T], + d: usize, +) { + state + .iter_mut() + .zip(rc.iter()) + .for_each(|(s, &rc)| add_rc_and_sbox(s, rc, d)); + matmul_external(state); +} diff --git a/poseidon2/src/internal.rs b/poseidon2/src/internal.rs new file mode 100644 index 000000000..c51fb7869 --- /dev/null +++ b/poseidon2/src/internal.rs @@ -0,0 +1,33 @@ +//! Generic implementation for internal layers + +use ark_ff::PrimeField; + +use crate::add_rc_and_sbox; + +/// Matrix multiplication in the internal layers +/// Given a vector v compute the matrix vector product (1 + diag(v))*state +/// with 1 denoting the constant matrix of ones. +// @credit: `matmul_internal()` in zkhash and in plonky3 +#[inline(always)] +fn matmul_internal( + state: &mut [F; T], + mat_diag_minus_1: &'static [F; T], +) { + let sum: F = state.iter().sum(); + for i in 0..T { + state[i] *= mat_diag_minus_1[i]; + state[i] += sum; + } +} + +/// One internal round +// @credit `internal_permute_state()` in plonky3 +pub(crate) fn permute_state( + state: &mut [F; T], + rc: F, + d: usize, + mat_diag_minus_1: &'static [F; T], +) { + add_rc_and_sbox(&mut state[0], rc, d); + matmul_internal(state, mat_diag_minus_1); +} diff --git a/poseidon2/src/lib.rs b/poseidon2/src/lib.rs new file mode 100644 index 000000000..17547b881 --- /dev/null +++ b/poseidon2/src/lib.rs @@ -0,0 +1,122 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the Jellyfish library. + +// You should have received a copy of the MIT License +// along with the Jellyfish library. If not, see . + +//! The Poseidon2 permutation. +//! +//! This implementation was based upon the following resources: +//! - https://github.com/HorizenLabs/poseidon2/blob/main/plain_implementations/src/poseidon2/poseidon2.rs +//! - https://eprint.iacr.org/2023/323.pdf +//! - https://github.com/Plonky3/Plonky3/blob/main/poseidon2/ + +#![no_std] +#![deny(missing_docs)] + +use ark_ff::PrimeField; +use ark_std::{borrow::ToOwned, marker::PhantomData}; + +mod external; +mod internal; + +/// Parameters required for a Poseidon2 permutation instance. +/// +/// # Generic parameters +/// - `F`: field choice +/// - `T`: state size = rate + capacity, `T` is made generic for easy trait +/// bound on `permute(input: [F; N])`. +pub trait Poseidon2Params { + /// d: sbox degree + const D: usize; + /// round_F: number of external rounds (incl. initial and terminal) + /// round_F = 2 * round_f + const EXT_ROUNDS: usize; + /// round_P: number of internal rounds + const INT_ROUNDS: usize; + + /// round constants for all external rounds + fn external_rc(&self) -> &'static [&'static [F; T]]; + /// round constants for internal rounds + fn internal_rc(&self) -> &'static [F]; + /// diffusion (diagonal) matrix minus one used in internal rounds + fn internal_mat_diag_m_1(&self) -> &'static [F; T]; + + /// A default sanity check on the parameters and constant getters + /// + /// State size only supports: 2, 3, 4, 8, 12, 16, 20, 24 for now + /// S-box size only supports: 3, 5, 7, 11 + /// + /// # Round constants + /// Rust doesn't permit generic param to be used in const operations, thus + /// leveraging type system to ensure sanity such as `const INT_RC: &'static + /// [F; Self::INT_ROUNDS]` is not allowed. + fn sanity_check(&self) -> bool { + let ext_rc = self.external_rc(); + let int_rc = self.internal_rc(); + + // TODO: consider adding more security-related check, incl. number of internal + // rounds in terms of field size to achieve 128-bit security. see + // `poseidon2_round_numbers_128` in plonky3, we skip for now as GCD is not + // implemented in arkworks, and params are trusted. + [2, 3, 4, 8, 12, 16, 20, 24].contains(&T) + && [3, 5, 7, 11].contains(&Self::D) + && ext_rc.len() == Self::EXT_ROUNDS + && int_rc.len() == Self::INT_ROUNDS + && Self::EXT_ROUNDS % 2 == 0 + } +} + +/// A Poseidon2 permutation family +pub struct Poseidon2(PhantomData); + +impl Poseidon2 { + /// Apply Poseidon2 permutation on `input` and return the permuted result + pub fn permute(param: &P, input: &[F; T]) -> [F; T] + where + P: Poseidon2Params, + { + let mut input = input.to_owned(); + Self::permute_mut(param, &mut input); + input + } + + /// Apply Poseidon2 permutation on `input` in place + pub fn permute_mut(param: &P, input: &mut [F; T]) + where + P: Poseidon2Params, + { + assert!(param.sanity_check(), "Unexpected: Invalid Poseidon2 param!"); + // M_e * x + external::matmul_external(input); + + // Initial external rounds (first EXT_ROUNDS/2 rounds) + let ext_rc = param.external_rc(); + for rc in ext_rc.iter().take(P::EXT_ROUNDS / 2) { + external::permute_state(input, rc, P::D); + } + + // Internal rounds + let int_rc = param.internal_rc(); + let mat_diag_minus_1 = param.internal_mat_diag_m_1(); + for rc in int_rc.iter() { + internal::permute_state(input, *rc, P::D, mat_diag_minus_1); + } + + // Terminal external rounds (second EXT_ROUNDS/2 rounds) + for rc in ext_rc.iter().take(P::EXT_ROUNDS).skip(P::EXT_ROUNDS / 2) { + external::permute_state(input, rc, P::D); + } + } +} + +/// A generic method performing the transformation, used both in external and +/// internal layers: +/// +/// `s -> (s + rc)^d` +// @credit: `add_rc_and_sbox_generic()` in plonky3 +#[inline(always)] +pub(crate) fn add_rc_and_sbox(val: &mut F, rc: F, d: usize) { + *val += rc; + *val = val.pow([d as u64]); +} From 33d0c4a5f39c51ce2a52e142cd2757663697e35c Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 11 Dec 2024 21:50:42 +0800 Subject: [PATCH 2/6] add bls12 s=2 param and tests --- poseidon2/Cargo.toml | 10 ++ poseidon2/src/constants.rs | 14 +++ poseidon2/src/constants/bls12_381.rs | 177 +++++++++++++++++++++++++++ poseidon2/src/constants/bn254.rs | 1 + poseidon2/src/lib.rs | 32 ++--- 5 files changed, 220 insertions(+), 14 deletions(-) create mode 100644 poseidon2/src/constants.rs create mode 100644 poseidon2/src/constants/bls12_381.rs create mode 100644 poseidon2/src/constants/bn254.rs diff --git a/poseidon2/Cargo.toml b/poseidon2/Cargo.toml index bb0f71fb2..95c91a7ba 100644 --- a/poseidon2/Cargo.toml +++ b/poseidon2/Cargo.toml @@ -11,5 +11,15 @@ documentation = { workspace = true } repository = { workspace = true } [dependencies] +# ark-bls12-381 = { workspace = true, optional = true } +ark-bls12-381 = { workspace = true } +ark-bn254 = { workspace = true, optional = true } ark-ff = { workspace = true } ark-std = { workspace = true } +hex = "0.4.3" +lazy_static = "1.5.0" + +[features] +# curve-named features contains constants for scalar fields of that curve +# bls12-381 = ["dep:ark-bls12-381"] +bn254 = ["dep:ark-bn254"] diff --git a/poseidon2/src/constants.rs b/poseidon2/src/constants.rs new file mode 100644 index 000000000..e4598fcfa --- /dev/null +++ b/poseidon2/src/constants.rs @@ -0,0 +1,14 @@ +//! Poseidon2 Constants copied from + +use ark_ff::PrimeField; +use hex::FromHex; + +// #[cfg(feature = "bls12-381")] +pub mod bls12_381; +// #[cfg(feature = "bn254")] +// pub mod bn254; + +#[inline] +pub(crate) fn from_hex(s: &str) -> F { + F::from_be_bytes_mod_order(&<[u8; 32]>::from_hex(s).expect("Invalid HexStr")) +} diff --git a/poseidon2/src/constants/bls12_381.rs b/poseidon2/src/constants/bls12_381.rs new file mode 100644 index 000000000..7ac7a2554 --- /dev/null +++ b/poseidon2/src/constants/bls12_381.rs @@ -0,0 +1,177 @@ +//! Poseidon2 constants for the scalar field of BLS12-381 + +use super::from_hex; +use crate::Poseidon2Params; +use ark_bls12_381::Fr; +use lazy_static::lazy_static; + +/// Poseidon parameters for Bls12-381 scalar field, with +/// - state size = 2 +/// - sbox size = 5 +/// - external rounds = 8 +/// - internal rounds = 56 +pub struct Poseidon2ParamsBls2; + +impl Poseidon2Params for Poseidon2ParamsBls2 { + const T: usize = 2; + const D: usize = 5; + const EXT_ROUNDS: usize = 8; + const INT_ROUNDS: usize = 56; + fn external_rc() -> &'static [[Fr; 2]] { + &*RC2_EXT + } + fn internal_rc() -> &'static [Fr] { + &*RC2_INT + } + fn internal_mat_diag_m_1() -> &'static [Fr; 2] { + &MAT_DIAG2_M_1 + } +} + +// adapted from +lazy_static! { + /// internal diagonal matrix, state size = 2 + pub static ref MAT_DIAG2_M_1: [Fr; 2] = [ + from_hex("0000000000000000000000000000000000000000000000000000000000000001"), + from_hex("0000000000000000000000000000000000000000000000000000000000000002"), + ]; + + /// internal round constants, state size = 2 + pub static ref RC2_INT: [Fr; 56] = [ + from_hex("6c0dc9eb332b5d968bec8ad68fe24ce34087ea54093f153618434475bce402f8"), + from_hex("0af5bafd335dae5c86967b11d5dcefb986a54c9d60d35eb06dc7a3fd779b3906"), + from_hex("6e12847918f030f2626c150ab69e4be0f13d202ae1f8bc87ea74323e93372e3b"), + from_hex("5565d40e21d059a26db241ca125d9316283eadf144b1318e604e253eeae1fe9a"), + from_hex("608e01b42d3dca09fed9b54eadaaba3e4ce6aefe92b0dc954a0fa4683a9678f2"), + from_hex("16bbe434b24f94e2c40ed1f4f9bd7d17e5be96c3aec15579b35fd80f0f80de9e"), + from_hex("0d1be811a8e73220cab01ce981d475522c3d7dd9e2716c3a2cf4ddd541546890"), + from_hex("5997a3affb18f942868b86f8ee10a68966e90bac7bbd8c65ede7e6e5ef1f6320"), + from_hex("4d92e86d270041061eec80278079fca771499dea5ccdc99682a953bb3a038b8e"), + from_hex("616c8c5ce232b9314f694fc6a968446ea9daf7a4079ce1a75fcc950741d680bb"), + from_hex("677e31e7846d9131bdc350eaf11a8ff918dd258ddd800444424afab34dfdfe3d"), + from_hex("4e7d7f85aefc110b233525ee3e53851aee7d3241e2a132585e0e25005eee0b0e"), + from_hex("06a8b4539488b7dddc48c3a226dbda313f906e106f844196d55013d321244f13"), + from_hex("5091517b6a85783108999f8e6bda3c793bef3f2e9589641d260bdfde8bdef00d"), + from_hex("0d2703e5b30f54d7f414e901802d54f8c14cd6355415df6e0f063d16bef9c43a"), + from_hex("56f69096811148eb38eec143d32565c077b3d1a4a4351f2b458f43b1659d4495"), + from_hex("622d94d38d1ded428afd062008c5709b43a678f6ba518ec56383e8ffba473504"), + from_hex("2730c607bba7333723a4a44577819b7db82a24574f6d13eee4c856c1ca3de9c7"), + from_hex("01ac5f59256c5004dc1043c53b23800a3fbab53eb1a83f551056f227b514b9f6"), + from_hex("0790b92523c973f1c95b94937afbb5796d89481e7a56328b44bab5ba81ae42f3"), + from_hex("1d63b59d97bc269d13964fb3e8771d0acc749bc83eb2f0372484e266142bb8c0"), + from_hex("1a52d04e5f14a3a05f7a01262df9e68c77fdf7e2bfb56c8b252d2140efdf0914"), + from_hex("5aa9b3b808812b284857e8622843a8717fa5cb49b217017f31d79e8d0f963fc0"), + from_hex("6a3d18fdbeb1d77ec1304539b00e6188786dbbc4435269b4c6281367f42656e3"), + from_hex("4743e860df269a85dd76fb99dbe9d840eb669dc859754b3f74805e57ba288b00"), + from_hex("6c32cac3946825f80a434c5ab397fc1a1c6a9bdfaab53175d4cf3d29ddb6cbc6"), + from_hex("333b0eea5da7ed1e3959d16280a361aa77dd24ecbfb28e1b2583ac4e9894305c"), + from_hex("3b503fc333b795ccc0c5bb3ae26b077dc3742cb745ec8821648c5ce7ebd9df18"), + from_hex("4fa5853188d9f728a17532d94bee6fb28fee510380a5d50927c6c5b1ce283444"), + from_hex("5d2ed8a6603a905bac490ebfb9e6c18f0bc9da1bbc2173291b18de6b6186118f"), + from_hex("2d830a53584c5556264852f075c78f7f9eb068016ae88af9cda933d6ae52eca7"), + from_hex("0250f4d6780ad29ae60e55f135b9ac80ccc7c81e3add37db276c26f1a2b1b86e"), + from_hex("6e3e9595f59220599e23e830728d4a0c4d62515ec1ed10b72446cf4df5b4c308"), + from_hex("2cd3314555d6faf23ee90cdb884f1c4697ebe98e3a450a624c4d896233b93cd5"), + from_hex("584a408d0f370543b8413fee70a060a394e561f504d8679f7bece4bf222e4108"), + from_hex("499cd53437b9fcbf7479c00fcc21295759074ce9bd1bb1fbd3460237aef4759e"), + from_hex("56a9b567bd0646effd0608d74d537991136098d9a06af6cb3ff8f010efb57578"), + from_hex("6a5fae2b00d968b931441b374e27ba4d03b306bd602d48731677169e75a67e8c"), + from_hex("2e1cc28e390e64aa1d60edb99c0aeda7c8c32bdb01ba11abbad5026b46eccb27"), + from_hex("2d4820000675df7c276beac408fe2e851e734a7008ae09bbcb3c96c70024f71b"), + from_hex("0c2fe101a2b52b538b902c6b2dc992cb266f7636e05b0c068385b5fa19e97142"), + from_hex("209b790b78c0e7927c6a178ef2f00b8687fc7bd4f21a9e02578551535002bc95"), + from_hex("2dd0926cf56bbaaec6491513d08a9983f94a910852a7b4ea4bd4222b93e14c10"), + from_hex("4316b39dd7d65b1bb575198104d409b169236a7ade371f7ab176fcbae75a5f0d"), + from_hex("540276d61041b91f6ea3068ec260a9338b6e3da15d934e648c24f35aee04e535"), + from_hex("37af612900b839977b146324c84772c58a4ccc0f6494cc054571827e74bfd2d3"), + from_hex("2af00c93d59ed14c9911e5cb3781d772371e83228e4267bbce11d065c1955338"), + from_hex("62b48779b0cf7ff2c10fd9b91a6ff7b7a99f935e961a5a94aa38f9d4f71c8b4c"), + from_hex("540bf5bbe01f28563bcbe11a2ce346d8231a2cdd0fe07641f9fa89e5c21978e3"), + from_hex("232b6c847a6d23912cb10ecbe50b53491f67f71e9b87a4a30446f2218017874b"), + from_hex("0ab34adbe77b8f1e57a370e4fd626071eea74b3f0b66644a629efaa0e96456c0"), + from_hex("1a83e43ef118c90046b1bdbeab8dd5cdcab632807c2cd0dc9147cbc5b7084be8"), + from_hex("1ec6fa41b41b672d9005468720918130b642567462a3d557a595d4dc6c56f2f9"), + from_hex("01f81a153199a751a111b8f5212cfc5bf82aacf0287d03e1864f8e5713fe4a17"), + from_hex("2617307587a675f4ecd73a54a7b206162d751cabf3d9fd007bcca4de2c6f0649"), + from_hex("1647be94c515178c7974a245624b642bb1ae6e2d4e1682087e362d7f98bc953f"), + ]; + + /// external round constants, state size = 2 + pub static ref RC2_EXT: [[Fr; 2]; 8] = [ + [ + from_hex("6267f5556c88257324c1c8b00d5871b2eba13cc39d72aa10dde6b69bc44c41c7"), + from_hex("30347723511438a085118166c68bf0c4f4ab5c10a2c55adb5cf87cc9e030f60f"), + ], + [ + from_hex("10db856965e40038eb6427303181e7b7439f1a051aa4630c26cf86d0a0451a4b"), + from_hex("5a3d2dcd541e4faaae7eb143eec847a0f652b6dc1b92e3f39ec23c808b3a5d63"), + ], + [ + from_hex("3b07f0ff7edcf93b1dd0487bc9fab1c6905f9ceee38dcce83efeb3a320398526"), + from_hex("40c73c524b9fd0fab63128175befe07b5c63ccdde9ca10e1a37205c9607fdf8a"), + ], + [ + from_hex("3a933861cf23752376d94dbb24b0f3c61630787928875c07672b68abfb9191e0"), + from_hex("71cc165e208570b2d5ef81db84e3c5e714ea4edfb36fc7fb11ef65a64b2d9755"), + ], + [ + from_hex("6e690b956e00b9e339dec49d675586f661f9b081ee3fa7696d73977658aa6fea"), + from_hex("660b85bc22de06d476c47bf084ad436f59874f1d630c0f5c91fbef51d5e738c5"), + ], + [ + from_hex("32bf3d451b69dde075fc370eaa8c1b77b5c0bc2aab1c7b46da7ef9d1840b0419"), + from_hex("73924b40beaa9c1ce4074c2154d1af4d658c09395a568b99b2fbcc3b5685e810"), + ], + [ + from_hex("17cbb3ee0adcb9d977e96e9152b36042925244fdd0aa184c7a89a58a2dc40097"), + from_hex("29d76a821e3220775c552f6b5977ab94956e52b8dac36ef88ace050d553766a3"), + ], + [ + from_hex("62b1a6c06ab26881a1fe57eceac56b5aec0b96da7211557f4e27ec24296d7db6"), + from_hex("0dfc474151e5c605a693a51ae8227cc0a99fdc4524fc2810c6eda9035d04334d"), + ], + ]; +} + +#[cfg(test)] +mod tests { + use ark_std::{test_rng, UniformRand}; + + use super::*; + use crate::Poseidon2; + + #[test] + fn consistent_perm() { + let rng = &mut test_rng(); + for _ in 0..10 { + let input1 = [Fr::rand(rng), Fr::rand(rng)]; + let input2 = [Fr::rand(rng), Fr::rand(rng)]; + + // same input get the same permutated output + assert_eq!( + Poseidon2::permute::(&input1), + Poseidon2::permute::(&input1) + ); + // diff input get diff permutated output + assert_ne!( + Poseidon2::permute::(&input1), + Poseidon2::permute::(&input2) + ); + } + } + + // copied from + #[test] + fn fixed_test_vector() { + let mut input = [Fr::from(0), Fr::from(1)]; + Poseidon2::permute_mut::(&mut input); + assert_eq!( + input[0], + from_hex("73c46dd530e248a87b61d19e67fa1b4ed30fc3d09f16531fe189fb945a15ce4e") + ); + assert_eq!( + input[1], + from_hex("1f0e305ee21c9366d5793b80251405032a3fee32b9dd0b5f4578262891b043b4") + ); + } +} diff --git a/poseidon2/src/constants/bn254.rs b/poseidon2/src/constants/bn254.rs new file mode 100644 index 000000000..c460bf30b --- /dev/null +++ b/poseidon2/src/constants/bn254.rs @@ -0,0 +1 @@ +//! Poseidon2 constants for the scalar field of BN254 diff --git a/poseidon2/src/lib.rs b/poseidon2/src/lib.rs index 17547b881..fc77c3a36 100644 --- a/poseidon2/src/lib.rs +++ b/poseidon2/src/lib.rs @@ -17,6 +17,7 @@ use ark_ff::PrimeField; use ark_std::{borrow::ToOwned, marker::PhantomData}; +pub mod constants; mod external; mod internal; @@ -25,8 +26,11 @@ mod internal; /// # Generic parameters /// - `F`: field choice /// - `T`: state size = rate + capacity, `T` is made generic for easy trait -/// bound on `permute(input: [F; N])`. +/// bound on `permute(input: [F; N])` and type safety on `external_rc()` +/// return type. pub trait Poseidon2Params { + /// t: state size = rate + capacity + const T: usize = T; /// d: sbox degree const D: usize; /// round_F: number of external rounds (incl. initial and terminal) @@ -36,11 +40,11 @@ pub trait Poseidon2Params { const INT_ROUNDS: usize; /// round constants for all external rounds - fn external_rc(&self) -> &'static [&'static [F; T]]; + fn external_rc() -> &'static [[F; T]]; /// round constants for internal rounds - fn internal_rc(&self) -> &'static [F]; + fn internal_rc() -> &'static [F]; /// diffusion (diagonal) matrix minus one used in internal rounds - fn internal_mat_diag_m_1(&self) -> &'static [F; T]; + fn internal_mat_diag_m_1() -> &'static [F; T]; /// A default sanity check on the parameters and constant getters /// @@ -51,9 +55,9 @@ pub trait Poseidon2Params { /// Rust doesn't permit generic param to be used in const operations, thus /// leveraging type system to ensure sanity such as `const INT_RC: &'static /// [F; Self::INT_ROUNDS]` is not allowed. - fn sanity_check(&self) -> bool { - let ext_rc = self.external_rc(); - let int_rc = self.internal_rc(); + fn sanity_check() -> bool { + let ext_rc = Self::external_rc(); + let int_rc = Self::internal_rc(); // TODO: consider adding more security-related check, incl. number of internal // rounds in terms of field size to achieve 128-bit security. see @@ -72,33 +76,33 @@ pub struct Poseidon2(PhantomData); impl Poseidon2 { /// Apply Poseidon2 permutation on `input` and return the permuted result - pub fn permute(param: &P, input: &[F; T]) -> [F; T] + pub fn permute(input: &[F; T]) -> [F; T] where P: Poseidon2Params, { let mut input = input.to_owned(); - Self::permute_mut(param, &mut input); + Self::permute_mut::(&mut input); input } /// Apply Poseidon2 permutation on `input` in place - pub fn permute_mut(param: &P, input: &mut [F; T]) + pub fn permute_mut(input: &mut [F; T]) where P: Poseidon2Params, { - assert!(param.sanity_check(), "Unexpected: Invalid Poseidon2 param!"); + assert!(P::sanity_check(), "Unexpected: Invalid Poseidon2 param!"); // M_e * x external::matmul_external(input); // Initial external rounds (first EXT_ROUNDS/2 rounds) - let ext_rc = param.external_rc(); + let ext_rc = P::external_rc(); for rc in ext_rc.iter().take(P::EXT_ROUNDS / 2) { external::permute_state(input, rc, P::D); } // Internal rounds - let int_rc = param.internal_rc(); - let mat_diag_minus_1 = param.internal_mat_diag_m_1(); + let int_rc = P::internal_rc(); + let mat_diag_minus_1 = P::internal_mat_diag_m_1(); for rc in int_rc.iter() { internal::permute_state(input, *rc, P::D, mat_diag_minus_1); } From 4f3f784ae1b21a199694c1c0213caf81597ac987 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 11 Dec 2024 22:03:57 +0800 Subject: [PATCH 3/6] use macro to derive instance --- poseidon2/src/constants.rs | 41 ++++++++++++++++++++++++++++ poseidon2/src/constants/bls12_381.rs | 34 ++++++++--------------- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/poseidon2/src/constants.rs b/poseidon2/src/constants.rs index e4598fcfa..aa76503f4 100644 --- a/poseidon2/src/constants.rs +++ b/poseidon2/src/constants.rs @@ -12,3 +12,44 @@ pub mod bls12_381; pub(crate) fn from_hex(s: &str) -> F { F::from_be_bytes_mod_order(&<[u8; 32]>::from_hex(s).expect("Invalid HexStr")) } + +/// macros to derive instances that implements `trait Poseidon2Params` +#[macro_export] +macro_rules! define_poseidon2_params { + ( + $struct_name:ident, + $state_size:expr, + $sbox_size:expr, + $ext_rounds:expr, + $int_rounds:expr, + $rc_ext:ident, + $rc_int:ident, + $mat_diag_m_1:ident + ) => { + /// Poseidon parameters for Bls12-381 scalar field, with + /// - state size = $state_size + /// - sbox size = $sbox_size + /// - external rounds = $ext_rounds + /// - internal rounds = $int_rounds + pub struct $struct_name; + + impl Poseidon2Params for $struct_name { + const T: usize = $state_size; + const D: usize = $sbox_size; + const EXT_ROUNDS: usize = $ext_rounds; + const INT_ROUNDS: usize = $int_rounds; + + fn external_rc() -> &'static [[Fr; $state_size]] { + &*$rc_ext + } + + fn internal_rc() -> &'static [Fr] { + &*$rc_int + } + + fn internal_mat_diag_m_1() -> &'static [Fr; $state_size] { + &$mat_diag_m_1 + } + } + }; +} diff --git a/poseidon2/src/constants/bls12_381.rs b/poseidon2/src/constants/bls12_381.rs index 7ac7a2554..6c05da94d 100644 --- a/poseidon2/src/constants/bls12_381.rs +++ b/poseidon2/src/constants/bls12_381.rs @@ -1,32 +1,20 @@ //! Poseidon2 constants for the scalar field of BLS12-381 use super::from_hex; -use crate::Poseidon2Params; +use crate::{define_poseidon2_params, Poseidon2Params}; use ark_bls12_381::Fr; use lazy_static::lazy_static; -/// Poseidon parameters for Bls12-381 scalar field, with -/// - state size = 2 -/// - sbox size = 5 -/// - external rounds = 8 -/// - internal rounds = 56 -pub struct Poseidon2ParamsBls2; - -impl Poseidon2Params for Poseidon2ParamsBls2 { - const T: usize = 2; - const D: usize = 5; - const EXT_ROUNDS: usize = 8; - const INT_ROUNDS: usize = 56; - fn external_rc() -> &'static [[Fr; 2]] { - &*RC2_EXT - } - fn internal_rc() -> &'static [Fr] { - &*RC2_INT - } - fn internal_mat_diag_m_1() -> &'static [Fr; 2] { - &MAT_DIAG2_M_1 - } -} +define_poseidon2_params!( + Poseidon2ParamsBls2, + 2, // State size + 5, // S-box size + 8, // External rounds + 56, // Internal rounds + RC2_EXT, // External round constants + RC2_INT, // Internal round constants + MAT_DIAG2_M_1 // Diagonal matrix constant +); // adapted from lazy_static! { From 8fa8817fc400d577a9c35b2f22fa8dd4a16debcc Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 11 Dec 2024 22:50:52 +0800 Subject: [PATCH 4/6] add more parameters --- poseidon2/Cargo.toml | 6 +- poseidon2/src/constants.rs | 6 +- poseidon2/src/constants/bls12_381.rs | 204 +++++++++++++++++++++++---- poseidon2/src/constants/bn254.rs | 160 +++++++++++++++++++++ 4 files changed, 341 insertions(+), 35 deletions(-) diff --git a/poseidon2/Cargo.toml b/poseidon2/Cargo.toml index 95c91a7ba..4a2797150 100644 --- a/poseidon2/Cargo.toml +++ b/poseidon2/Cargo.toml @@ -11,8 +11,7 @@ documentation = { workspace = true } repository = { workspace = true } [dependencies] -# ark-bls12-381 = { workspace = true, optional = true } -ark-bls12-381 = { workspace = true } +ark-bls12-381 = { workspace = true, optional = true } ark-bn254 = { workspace = true, optional = true } ark-ff = { workspace = true } ark-std = { workspace = true } @@ -20,6 +19,7 @@ hex = "0.4.3" lazy_static = "1.5.0" [features] +default = ["bls12-381", "bn254"] # curve-named features contains constants for scalar fields of that curve -# bls12-381 = ["dep:ark-bls12-381"] +bls12-381 = ["dep:ark-bls12-381"] bn254 = ["dep:ark-bn254"] diff --git a/poseidon2/src/constants.rs b/poseidon2/src/constants.rs index aa76503f4..6cfe191bc 100644 --- a/poseidon2/src/constants.rs +++ b/poseidon2/src/constants.rs @@ -3,10 +3,10 @@ use ark_ff::PrimeField; use hex::FromHex; -// #[cfg(feature = "bls12-381")] +#[cfg(feature = "bls12-381")] pub mod bls12_381; -// #[cfg(feature = "bn254")] -// pub mod bn254; +#[cfg(feature = "bn254")] +pub mod bn254; #[inline] pub(crate) fn from_hex(s: &str) -> F { diff --git a/poseidon2/src/constants/bls12_381.rs b/poseidon2/src/constants/bls12_381.rs index 6c05da94d..5966ac42f 100644 --- a/poseidon2/src/constants/bls12_381.rs +++ b/poseidon2/src/constants/bls12_381.rs @@ -16,6 +16,17 @@ define_poseidon2_params!( MAT_DIAG2_M_1 // Diagonal matrix constant ); +define_poseidon2_params!( + Poseidon2ParamsBls3, + 3, // State size + 5, // S-box size + 8, // External rounds + 56, // Internal rounds + RC3_EXT, // External round constants + RC3_INT, // Internal round constants + MAT_DIAG3_M_1 // Diagonal matrix constant +); + // adapted from lazy_static! { /// internal diagonal matrix, state size = 2 @@ -24,6 +35,42 @@ lazy_static! { from_hex("0000000000000000000000000000000000000000000000000000000000000002"), ]; + /// external round constants, state size = 2 + pub static ref RC2_EXT: [[Fr; 2]; 8] = [ + [ + from_hex("6267f5556c88257324c1c8b00d5871b2eba13cc39d72aa10dde6b69bc44c41c7"), + from_hex("30347723511438a085118166c68bf0c4f4ab5c10a2c55adb5cf87cc9e030f60f"), + ], + [ + from_hex("10db856965e40038eb6427303181e7b7439f1a051aa4630c26cf86d0a0451a4b"), + from_hex("5a3d2dcd541e4faaae7eb143eec847a0f652b6dc1b92e3f39ec23c808b3a5d63"), + ], + [ + from_hex("3b07f0ff7edcf93b1dd0487bc9fab1c6905f9ceee38dcce83efeb3a320398526"), + from_hex("40c73c524b9fd0fab63128175befe07b5c63ccdde9ca10e1a37205c9607fdf8a"), + ], + [ + from_hex("3a933861cf23752376d94dbb24b0f3c61630787928875c07672b68abfb9191e0"), + from_hex("71cc165e208570b2d5ef81db84e3c5e714ea4edfb36fc7fb11ef65a64b2d9755"), + ], + [ + from_hex("6e690b956e00b9e339dec49d675586f661f9b081ee3fa7696d73977658aa6fea"), + from_hex("660b85bc22de06d476c47bf084ad436f59874f1d630c0f5c91fbef51d5e738c5"), + ], + [ + from_hex("32bf3d451b69dde075fc370eaa8c1b77b5c0bc2aab1c7b46da7ef9d1840b0419"), + from_hex("73924b40beaa9c1ce4074c2154d1af4d658c09395a568b99b2fbcc3b5685e810"), + ], + [ + from_hex("17cbb3ee0adcb9d977e96e9152b36042925244fdd0aa184c7a89a58a2dc40097"), + from_hex("29d76a821e3220775c552f6b5977ab94956e52b8dac36ef88ace050d553766a3"), + ], + [ + from_hex("62b1a6c06ab26881a1fe57eceac56b5aec0b96da7211557f4e27ec24296d7db6"), + from_hex("0dfc474151e5c605a693a51ae8227cc0a99fdc4524fc2810c6eda9035d04334d"), + ], + ]; + /// internal round constants, state size = 2 pub static ref RC2_INT: [Fr; 56] = [ from_hex("6c0dc9eb332b5d968bec8ad68fe24ce34087ea54093f153618434475bce402f8"), @@ -84,69 +131,153 @@ lazy_static! { from_hex("1647be94c515178c7974a245624b642bb1ae6e2d4e1682087e362d7f98bc953f"), ]; - /// external round constants, state size = 2 - pub static ref RC2_EXT: [[Fr; 2]; 8] = [ + /// internal diagonal matrix, state size = 3 + pub static ref MAT_DIAG3_M_1: [Fr; 3] = [ + from_hex("0000000000000000000000000000000000000000000000000000000000000001"), + from_hex("0000000000000000000000000000000000000000000000000000000000000001"), + from_hex("0000000000000000000000000000000000000000000000000000000000000002"), + ]; + + /// external round constants, state size = 3 + pub static ref RC3_EXT: [[Fr; 3]; 8] = [ [ - from_hex("6267f5556c88257324c1c8b00d5871b2eba13cc39d72aa10dde6b69bc44c41c7"), - from_hex("30347723511438a085118166c68bf0c4f4ab5c10a2c55adb5cf87cc9e030f60f"), + from_hex("6f007a551156b3a449e44936b7c093644a0ed33f33eaccc628e942e836c1a875"), + from_hex("360d7470611e473d353f628f76d110f34e71162f31003b7057538c2596426303"), + from_hex("4b5fec3aa073df44019091f007a44ca996484965f7036dce3e9d0977edcdc0f6"), ], [ - from_hex("10db856965e40038eb6427303181e7b7439f1a051aa4630c26cf86d0a0451a4b"), - from_hex("5a3d2dcd541e4faaae7eb143eec847a0f652b6dc1b92e3f39ec23c808b3a5d63"), + from_hex("67cf1868af6396c0b84cce715e539f849e06cd1c383ac5b06100c76bcc973a11"), + from_hex("555db4d1dced819f5d3de70fde83f1c7d3e8c98968e516a23a771a5c9c8257aa"), + from_hex("2bab94d7ae222d135dc3c6c5febfaa314908ac2f12ebe06fbdb74213bf63188b"), ], [ - from_hex("3b07f0ff7edcf93b1dd0487bc9fab1c6905f9ceee38dcce83efeb3a320398526"), - from_hex("40c73c524b9fd0fab63128175befe07b5c63ccdde9ca10e1a37205c9607fdf8a"), + from_hex("66f44be5296682c4fa7882799d6dd049b6d7d2c950ccf98cf2e50d6d1ebb77c2"), + from_hex("150c93fef652fb1c2bf03e1a29aa871fef77e7d736766c5d0939d92753cc5dc8"), + from_hex("3270661e68928b3a955d55db56dc57c103cc0a60141e894e14259dce537782b2"), ], [ - from_hex("3a933861cf23752376d94dbb24b0f3c61630787928875c07672b68abfb9191e0"), - from_hex("71cc165e208570b2d5ef81db84e3c5e714ea4edfb36fc7fb11ef65a64b2d9755"), + from_hex("073f116f04122e25a0b7afe4e2057299b407c370f2b5a1ccce9fb9ffc345afb3"), + from_hex("409fda22558cfe4d3dd8dce24f69e76f8c2aaeb1dd0f09d65e654c71f32aa23f"), + from_hex("2a32ec5c4ee5b1837affd09c1f53f5fd55c9cd2061ae93ca8ebad76fc71554d8"), ], [ - from_hex("6e690b956e00b9e339dec49d675586f661f9b081ee3fa7696d73977658aa6fea"), - from_hex("660b85bc22de06d476c47bf084ad436f59874f1d630c0f5c91fbef51d5e738c5"), + from_hex("6cbac5e1700984ebc32da15b4bb9683faabab55f67ccc4f71d9560b3475a77eb"), + from_hex("4603c403bbfa9a17738a5c6278eaab1c37ec30b0737aa2409fc4898069eb983c"), + from_hex("6894e7e22b2c1d5c70a712a6345ae6b192a9c833a9234c31c56aacd16bc2f100"), ], [ - from_hex("32bf3d451b69dde075fc370eaa8c1b77b5c0bc2aab1c7b46da7ef9d1840b0419"), - from_hex("73924b40beaa9c1ce4074c2154d1af4d658c09395a568b99b2fbcc3b5685e810"), + from_hex("5be2cbbc44053ad08afa4d1eabc7f3d231eea799b93f226e905b7d4d65c58ebb"), + from_hex("58e55f287b453a9808624a8c2a353d528da0f7e713a5c6d0d7711e47063fa611"), + from_hex("366ebfafa3ad381c0ee258c9b8fdfccdb868a7d7e1f1f69a2b5dfcc5572555df"), ], [ - from_hex("17cbb3ee0adcb9d977e96e9152b36042925244fdd0aa184c7a89a58a2dc40097"), - from_hex("29d76a821e3220775c552f6b5977ab94956e52b8dac36ef88ace050d553766a3"), + from_hex("45766ab728968c642f90d97ccf5504ddc10518a819ebbcc4d09c3f5d784d67ce"), + from_hex("39678f65512f1ee404db3024f41d3f567ef66d89d044d022e6bc229e95bc76b1"), + from_hex("463aed1d2f1f955e3078be5bf7bfc46fc0eb8c51551906a8868f18ffae30cf4f"), ], [ - from_hex("62b1a6c06ab26881a1fe57eceac56b5aec0b96da7211557f4e27ec24296d7db6"), - from_hex("0dfc474151e5c605a693a51ae8227cc0a99fdc4524fc2810c6eda9035d04334d"), - ], + from_hex("21668f016a8063c0d58b7750a3bc2fe1cf82c25f99dc01a4e534c88fe53d85fe"), + from_hex("39d00994a8a5046a1bc749363e98a768e34dea56439fe1954bef429bc5331608"), + from_hex("4d7f5dcd78ece9a933984de32c0b48fac2bba91f261996b8e9d1021773bd07cc"), + ] + ]; + + /// internal round constants, state size = 3 + pub static ref RC3_INT: [Fr; 56] = [ + from_hex("5848ebeb5923e92555b7124fffba5d6bd571c6f984195eb9cfd3a3e8eb55b1d4"), + from_hex("270326ee039df19e651e2cfc740628ca634d24fc6e2559f22d8ccbe292efeead"), + from_hex("27c6642ac633bc66dc100fe7fcfa54918af895bce012f182a068fc37c182e274"), + from_hex("1bdfd8b01401c70ad27f57396989129d710e1fb6ab976a459ca18682e26d7ff9"), + from_hex("491b9ba6983bcf9f05fe4794adb44a30879bf8289662e1f57d90f672414e8a4a"), + from_hex("162a14c62f9a89b814b9d6a9c84dd678f4f6fb3f9054d373c832d824261a35ea"), + from_hex("2d193e0f76de586b2af6f79e3127feeaac0a1fc71e2cf0c0f79824667b5b6bec"), + from_hex("46efd8a9a262d6d8fdc9ca5c04b0982f24ddcc6e9863885a6a732a3906a07b95"), + from_hex("509717e0c200e3c92d8dca2973b3db45f0788294351ad07ae75cbb780693a798"), + from_hex("7299b28464a8c94fb9d4df61380f39c0dca9c2c014118789e227252820f01bfc"), + from_hex("044ca3cc4a85d73b81696ef1104e674f4feff82984990ff85d0bf58dc8a4aa94"), + from_hex("1cbaf2b371dac6a81d0453416d3e235cb8d9e2d4f314f46f6198785f0cd6b9af"), + from_hex("1d5b2777692c205b0e6c49d061b6b5f4293c4ab038fdbbdc343e07610f3fede5"), + from_hex("56ae7c7a5293bdc23e85e1698c81c77f8ad88c4b33a5780437ad047c6edb59ba"), + from_hex("2e9bdbba3dd34bffaa30535bdd749a7e06a9adb0c1e6f962f60e971b8d73b04f"), + from_hex("2de11886b18011ca8bd5bae36969299fde40fbe26d047b05035a13661f22418b"), + from_hex("2e07de1780b8a70d0d5b4a3f1841dcd82ab9395c449be947bc998884ba96a721"), + from_hex("0f69f1854d20ca0cbbdb63dbd52dad16250440a99d6b8af3825e4c2bb74925ca"), + from_hex("5dc987318e6e59c1afb87b655dd58cc1d22e513a05838cd4585d04b135b957ca"), + from_hex("48b725758571c9df6c01dc639a85f07297696b1bb678633a29dc91de95ef53f6"), + from_hex("5e565e08c0821099256b56490eaee1d573afd10bb6d17d13ca4e5c611b2a3718"), + from_hex("2eb1b25417fe17670d135dc639fb09a46ce5113507f96de9816c059422dc705e"), + from_hex("115cd0a0643cfb988c24cb44c3fab48aff36c661d26cc42db8b1bdf4953bd82c"), + from_hex("26ca293f7b2c462d066d7378b999868bbb57ddf14e0f958ade801612311d04cd"), + from_hex("4147400d8e1aaccf311a6b5b762011ab3e45326e4d4b9de26992816b99c528ac"), + from_hex("6b0db7dccc4ba1b268f6bdcc4d372848d4a72976c268ea30519a2f73e6db4d55"), + from_hex("17bf1b93c4c7e01a2a830aa162412cd90f160bf9f71e967ff5209d14b24820ca"), + from_hex("4b431cd9efedbc94cf1eca6f9e9c1839d0e66a8bffa8c8464cac81a39d3cf8f1"), + from_hex("35b41a7ac4f3c571a24f8456369c85dfe03c0354bd8cfd3805c86f2e7dc293c5"), + from_hex("3b1480080523c439435927994849bea964e14d3beb2dddde72ac156af435d09e"), + from_hex("2cc6810031dc1b0d4950856dc907d57508e286442a2d3eb2271618d874b14c6d"), + from_hex("6f4141c8401c5a395ba6790efd71c70c04afea06c3c92826bcabdd5cb5477d51"), + from_hex("25bdbbeda1bde8c1059618e2afd2ef999e517aa93b78341d91f318c09f0cb566"), + from_hex("392a4a8758e06ee8b95f33c25dde8ac02a5ed0a27b61926cc6313487073f7f7b"), + from_hex("272a55878a08442b9aa6111f4de009485e6a6fd15db89365e7bbcef02eb5866c"), + from_hex("631ec1d6d28dd9e824ee89a30730aef7ab463acfc9d184b355aa05fd6938eab5"), + from_hex("4eb6fda10fd0fbde02c7449bfbddc35bcd8225e7e5c3833a0818a100409dc6f2"), + from_hex("2d5b308b0cf02cdfefa13c4e60e26239a6ebba011694dd129b925b3c5b21e0e2"), + from_hex("16549fc6af2f3b72dd5d293d72e2e5f244dff42f18b46c56ef38c57c311673ac"), + from_hex("42332677ff359c5e8db836d9f5fb54822e39bd5e22340bb9ba975ba1a92be382"), + from_hex("49d7d2c0b449e5179bc5ccc3b44c6075d9849b5610465f09ea725ddc97723a94"), + from_hex("64c20fb90d7a003831757cc4c6226f6e4985fc9ecb416b9f684ca0351d967904"), + from_hex("59cff40de83b52b41bc443d7979510d771c940b9758ca820fe73b5c8d5580934"), + from_hex("53db2731730c39b04edd875fe3b7c882808285cdbc621d7af4f80dd53ebb71b0"), + from_hex("1b10bb7a82afce39fa69c3a2ad52f76d76398265344203119b7126d9b46860df"), + from_hex("561b6012d666bfe179c4dd7f84cdd1531596d3aac7c5700ceb319f91046a63c9"), + from_hex("0f1e7505ebd91d2fc79c2df7dc98a3bed1b36968ba0405c090d27f6a00b7dfc8"), + from_hex("2f313faf0d3f6187537a7497a3b43f46797fd6e3f18eb1caff457756b819bb20"), + from_hex("3a5cbb6de450b481fa3ca61c0ed15bc55cad11ebf0f7ceb8f0bc3e732ecb26f6"), + from_hex("681d93411bf8ce63f6716aefbd0e24506454c0348ee38fabeb264702714ccf94"), + from_hex("5178e940f50004312646b436727f0e80a7b8f2e9ee1fdc677c4831a7672777fb"), + from_hex("3dab54bc9bef688dd92086e253b439d651baa6e20f892b62865527cbca915982"), + from_hex("4b3ce75311218f9ae905f84eaa5b2b3818448bbf3972e1aad69de321009015d0"), + from_hex("06dbfb42b979884de280d31670123f744c24b33b410fefd4368045acf2b71ae3"), + from_hex("068d6b4608aae810c6f039ea1973a63eb8d2de72e3d2c9eca7fc32d22f18b9d3"), + from_hex("4c5c254589a92a36084a57d3b1d964278acc7e4fe8f69f2955954f27a79cebef"), ]; } #[cfg(test)] -mod tests { - use ark_std::{test_rng, UniformRand}; +pub(crate) mod tests { + use ark_ff::PrimeField; + use ark_std::test_rng; use super::*; use crate::Poseidon2; - #[test] - fn consistent_perm() { + pub(crate) fn consistent_perm_helper< + F: PrimeField, + const N: usize, + P: Poseidon2Params, + >() { let rng = &mut test_rng(); for _ in 0..10 { - let input1 = [Fr::rand(rng), Fr::rand(rng)]; - let input2 = [Fr::rand(rng), Fr::rand(rng)]; + let input1 = [F::rand(rng); N]; + let input2 = [F::rand(rng); N]; // same input get the same permutated output assert_eq!( - Poseidon2::permute::(&input1), - Poseidon2::permute::(&input1) + Poseidon2::permute::(&input1), + Poseidon2::permute::(&input1) ); // diff input get diff permutated output assert_ne!( - Poseidon2::permute::(&input1), - Poseidon2::permute::(&input2) + Poseidon2::permute::(&input1), + Poseidon2::permute::(&input2) ); } } + #[test] + fn consistent_perm() { + consistent_perm_helper::(); + consistent_perm_helper::(); + } // copied from #[test] @@ -161,5 +292,20 @@ mod tests { input[1], from_hex("1f0e305ee21c9366d5793b80251405032a3fee32b9dd0b5f4578262891b043b4") ); + + let mut input = [Fr::from(0), Fr::from(1), Fr::from(2)]; + Poseidon2::permute_mut::(&mut input); + assert_eq!( + input[0], + from_hex("1b152349b1950b6a8ca75ee4407b6e26ca5cca5650534e56ef3fd45761fbf5f0") + ); + assert_eq!( + input[1], + from_hex("4c5793c87d51bdc2c08a32108437dc0000bd0275868f09ebc5f36919af5b3891") + ); + assert_eq!( + input[2], + from_hex("1fc8ed171e67902ca49863159fe5ba6325318843d13976143b8125f08b50dc6b") + ); } } diff --git a/poseidon2/src/constants/bn254.rs b/poseidon2/src/constants/bn254.rs index c460bf30b..7cb28fa57 100644 --- a/poseidon2/src/constants/bn254.rs +++ b/poseidon2/src/constants/bn254.rs @@ -1 +1,161 @@ //! Poseidon2 constants for the scalar field of BN254 + +use super::from_hex; +use crate::{define_poseidon2_params, Poseidon2Params}; +use ark_bn254::Fr; +use lazy_static::lazy_static; + +define_poseidon2_params!( + Poseidon2ParamsBn3, + 3, // State size + 5, // S-box size + 8, // External rounds + 56, // Internal rounds + RC3_EXT, // External round constants + RC3_INT, // Internal round constants + MAT_DIAG3_M_1 // Diagonal matrix constant +); + +// adapted from +lazy_static! { + /// internal diagonal matrix, state size = 3 + pub static ref MAT_DIAG3_M_1: [Fr; 3] = [ + from_hex("0000000000000000000000000000000000000000000000000000000000000001"), + from_hex("0000000000000000000000000000000000000000000000000000000000000001"), + from_hex("0000000000000000000000000000000000000000000000000000000000000002"), + ]; + + /// external round constants, state size = 3 + pub static ref RC3_EXT: [[Fr; 3]; 8] = [ + [ + from_hex("1d066a255517b7fd8bddd3a93f7804ef7f8fcde48bb4c37a59a09a1a97052816"), + from_hex("29daefb55f6f2dc6ac3f089cebcc6120b7c6fef31367b68eb7238547d32c1610"), + from_hex("1f2cb1624a78ee001ecbd88ad959d7012572d76f08ec5c4f9e8b7ad7b0b4e1d1"), + ], + [ + from_hex("0aad2e79f15735f2bd77c0ed3d14aa27b11f092a53bbc6e1db0672ded84f31e5"), + from_hex("2252624f8617738cd6f661dd4094375f37028a98f1dece66091ccf1595b43f28"), + from_hex("1a24913a928b38485a65a84a291da1ff91c20626524b2b87d49f4f2c9018d735"), + ], + [ + from_hex("22fc468f1759b74d7bfc427b5f11ebb10a41515ddff497b14fd6dae1508fc47a"), + from_hex("1059ca787f1f89ed9cd026e9c9ca107ae61956ff0b4121d5efd65515617f6e4d"), + from_hex("02be9473358461d8f61f3536d877de982123011f0bf6f155a45cbbfae8b981ce"), + ], + [ + from_hex("0ec96c8e32962d462778a749c82ed623aba9b669ac5b8736a1ff3a441a5084a4"), + from_hex("292f906e073677405442d9553c45fa3f5a47a7cdb8c99f9648fb2e4d814df57e"), + from_hex("274982444157b86726c11b9a0f5e39a5cc611160a394ea460c63f0b2ffe5657e"), + ], + [ + from_hex("1acd63c67fbc9ab1626ed93491bda32e5da18ea9d8e4f10178d04aa6f8747ad0"), + from_hex("19f8a5d670e8ab66c4e3144be58ef6901bf93375e2323ec3ca8c86cd2a28b5a5"), + from_hex("1c0dc443519ad7a86efa40d2df10a011068193ea51f6c92ae1cfbb5f7b9b6893"), + ], + [ + from_hex("14b39e7aa4068dbe50fe7190e421dc19fbeab33cb4f6a2c4180e4c3224987d3d"), + from_hex("1d449b71bd826ec58f28c63ea6c561b7b820fc519f01f021afb1e35e28b0795e"), + from_hex("1ea2c9a89baaddbb60fa97fe60fe9d8e89de141689d1252276524dc0a9e987fc"), + ], + [ + from_hex("0478d66d43535a8cb57e9c1c3d6a2bd7591f9a46a0e9c058134d5cefdb3c7ff1"), + from_hex("19272db71eece6a6f608f3b2717f9cd2662e26ad86c400b21cde5e4a7b00bebe"), + from_hex("14226537335cab33c749c746f09208abb2dd1bd66a87ef75039be846af134166"), + ], + [ + from_hex("01fd6af15956294f9dfe38c0d976a088b21c21e4a1c2e823f912f44961f9a9ce"), + from_hex("18e5abedd626ec307bca190b8b2cab1aaee2e62ed229ba5a5ad8518d4e5f2a57"), + from_hex("0fc1bbceba0590f5abbdffa6d3b35e3297c021a3a409926d0e2d54dc1c84fda6"), + ], + ]; + + /// internal round constants, state size = 3 + pub static ref RC3_INT: [Fr; 56] = [ + from_hex("1a1d063e54b1e764b63e1855bff015b8cedd192f47308731499573f23597d4b5"), + from_hex("26abc66f3fdf8e68839d10956259063708235dccc1aa3793b91b002c5b257c37"), + from_hex("0c7c64a9d887385381a578cfed5aed370754427aabca92a70b3c2b12ff4d7be8"), + from_hex("1cf5998769e9fab79e17f0b6d08b2d1eba2ebac30dc386b0edd383831354b495"), + from_hex("0f5e3a8566be31b7564ca60461e9e08b19828764a9669bc17aba0b97e66b0109"), + from_hex("18df6a9d19ea90d895e60e4db0794a01f359a53a180b7d4b42bf3d7a531c976e"), + from_hex("04f7bf2c5c0538ac6e4b782c3c6e601ad0ea1d3a3b9d25ef4e324055fa3123dc"), + from_hex("29c76ce22255206e3c40058523748531e770c0584aa2328ce55d54628b89ebe6"), + from_hex("198d425a45b78e85c053659ab4347f5d65b1b8e9c6108dbe00e0e945dbc5ff15"), + from_hex("25ee27ab6296cd5e6af3cc79c598a1daa7ff7f6878b3c49d49d3a9a90c3fdf74"), + from_hex("138ea8e0af41a1e024561001c0b6eb1505845d7d0c55b1b2c0f88687a96d1381"), + from_hex("306197fb3fab671ef6e7c2cba2eefd0e42851b5b9811f2ca4013370a01d95687"), + from_hex("1a0c7d52dc32a4432b66f0b4894d4f1a21db7565e5b4250486419eaf00e8f620"), + from_hex("2b46b418de80915f3ff86a8e5c8bdfccebfbe5f55163cd6caa52997da2c54a9f"), + from_hex("12d3e0dc0085873701f8b777b9673af9613a1af5db48e05bfb46e312b5829f64"), + from_hex("263390cf74dc3a8870f5002ed21d089ffb2bf768230f648dba338a5cb19b3a1f"), + from_hex("0a14f33a5fe668a60ac884b4ca607ad0f8abb5af40f96f1d7d543db52b003dcd"), + from_hex("28ead9c586513eab1a5e86509d68b2da27be3a4f01171a1dd847df829bc683b9"), + from_hex("1c6ab1c328c3c6430972031f1bdb2ac9888f0ea1abe71cffea16cda6e1a7416c"), + from_hex("1fc7e71bc0b819792b2500239f7f8de04f6decd608cb98a932346015c5b42c94"), + from_hex("03e107eb3a42b2ece380e0d860298f17c0c1e197c952650ee6dd85b93a0ddaa8"), + from_hex("2d354a251f381a4669c0d52bf88b772c46452ca57c08697f454505f6941d78cd"), + from_hex("094af88ab05d94baf687ef14bc566d1c522551d61606eda3d14b4606826f794b"), + from_hex("19705b783bf3d2dc19bcaeabf02f8ca5e1ab5b6f2e3195a9d52b2d249d1396f7"), + from_hex("09bf4acc3a8bce3f1fcc33fee54fc5b28723b16b7d740a3e60cef6852271200e"), + from_hex("1803f8200db6013c50f83c0c8fab62843413732f301f7058543a073f3f3b5e4e"), + from_hex("0f80afb5046244de30595b160b8d1f38bf6fb02d4454c0add41f7fef2faf3e5c"), + from_hex("126ee1f8504f15c3d77f0088c1cfc964abcfcf643f4a6fea7dc3f98219529d78"), + from_hex("23c203d10cfcc60f69bfb3d919552ca10ffb4ee63175ddf8ef86f991d7d0a591"), + from_hex("2a2ae15d8b143709ec0d09705fa3a6303dec1ee4eec2cf747c5a339f7744fb94"), + from_hex("07b60dee586ed6ef47e5c381ab6343ecc3d3b3006cb461bbb6b5d89081970b2b"), + from_hex("27316b559be3edfd885d95c494c1ae3d8a98a320baa7d152132cfe583c9311bd"), + from_hex("1d5c49ba157c32b8d8937cb2d3f84311ef834cc2a743ed662f5f9af0c0342e76"), + from_hex("2f8b124e78163b2f332774e0b850b5ec09c01bf6979938f67c24bd5940968488"), + from_hex("1e6843a5457416b6dc5b7aa09a9ce21b1d4cba6554e51d84665f75260113b3d5"), + from_hex("11cdf00a35f650c55fca25c9929c8ad9a68daf9ac6a189ab1f5bc79f21641d4b"), + from_hex("21632de3d3bbc5e42ef36e588158d6d4608b2815c77355b7e82b5b9b7eb560bc"), + from_hex("0de625758452efbd97b27025fbd245e0255ae48ef2a329e449d7b5c51c18498a"), + from_hex("2ad253c053e75213e2febfd4d976cc01dd9e1e1c6f0fb6b09b09546ba0838098"), + from_hex("1d6b169ed63872dc6ec7681ec39b3be93dd49cdd13c813b7d35702e38d60b077"), + from_hex("1660b740a143664bb9127c4941b67fed0be3ea70a24d5568c3a54e706cfef7fe"), + from_hex("0065a92d1de81f34114f4ca2deef76e0ceacdddb12cf879096a29f10376ccbfe"), + from_hex("1f11f065202535987367f823da7d672c353ebe2ccbc4869bcf30d50a5871040d"), + from_hex("26596f5c5dd5a5d1b437ce7b14a2c3dd3bd1d1a39b6759ba110852d17df0693e"), + from_hex("16f49bc727e45a2f7bf3056efcf8b6d38539c4163a5f1e706743db15af91860f"), + from_hex("1abe1deb45b3e3119954175efb331bf4568feaf7ea8b3dc5e1a4e7438dd39e5f"), + from_hex("0e426ccab66984d1d8993a74ca548b779f5db92aaec5f102020d34aea15fba59"), + from_hex("0e7c30c2e2e8957f4933bd1942053f1f0071684b902d534fa841924303f6a6c6"), + from_hex("0812a017ca92cf0a1622708fc7edff1d6166ded6e3528ead4c76e1f31d3fc69d"), + from_hex("21a5ade3df2bc1b5bba949d1db96040068afe5026edd7a9c2e276b47cf010d54"), + from_hex("01f3035463816c84ad711bf1a058c6c6bd101945f50e5afe72b1a5233f8749ce"), + from_hex("0b115572f038c0e2028c2aafc2d06a5e8bf2f9398dbd0fdf4dcaa82b0f0c1c8b"), + from_hex("1c38ec0b99b62fd4f0ef255543f50d2e27fc24db42bc910a3460613b6ef59e2f"), + from_hex("1c89c6d9666272e8425c3ff1f4ac737b2f5d314606a297d4b1d0b254d880c53e"), + from_hex("03326e643580356bf6d44008ae4c042a21ad4880097a5eb38b71e2311bb88f8f"), + from_hex("268076b0054fb73f67cee9ea0e51e3ad50f27a6434b5dceb5bdde2299910a4c9"), + ]; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{constants::bls12_381::tests::consistent_perm_helper, Poseidon2}; + + #[test] + fn consistent_perm() { + consistent_perm_helper::(); + } + + // copied from + #[test] + fn fixed_test_vector() { + let mut input = [Fr::from(0), Fr::from(1), Fr::from(2)]; + Poseidon2::permute_mut::(&mut input); + assert_eq!( + input[0], + from_hex("0bb61d24daca55eebcb1929a82650f328134334da98ea4f847f760054f4a3033") + ); + assert_eq!( + input[1], + from_hex("303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570") + ); + assert_eq!( + input[2], + from_hex("1ed25194542b12eef8617361c3ba7c52e660b145994427cc86296242cf766ec8") + ); + } +} From a698a0f370d728d4cb08112f5b0f646fdca877c4 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Wed, 11 Dec 2024 23:45:27 +0800 Subject: [PATCH 5/6] impl HasherAlgorithm for Poseidon2 --- merkle_tree/Cargo.toml | 1 + merkle_tree/src/hasher.rs | 16 ++++++++-------- merkle_tree/src/prelude.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/merkle_tree/Cargo.toml b/merkle_tree/Cargo.toml index 7679ce5b1..49ea399e3 100644 --- a/merkle_tree/Cargo.toml +++ b/merkle_tree/Cargo.toml @@ -24,6 +24,7 @@ displaydoc = { workspace = true } hashbrown = { workspace = true } hex = "0.4.3" itertools = { workspace = true, features = ["use_alloc"] } +jf-poseidon2 = { path = "../poseidon2" } jf-relation = { version = "0.4.4", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", optional = true, default-features = false } jf-rescue = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", default-features = false } jf-utils = { version = "0.4.4", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", default-features = false } diff --git a/merkle_tree/src/hasher.rs b/merkle_tree/src/hasher.rs index 44b2bb1a3..61e3b1993 100644 --- a/merkle_tree/src/hasher.rs +++ b/merkle_tree/src/hasher.rs @@ -73,7 +73,7 @@ pub type GenericHasherMerkleTree = /// Convenience trait and blanket impl for downstream trait bounds. /// -/// Useful for downstream code that's generic offer [`Digest`] hasher `H`. +/// Useful for downstream code that's generic over [`Digest`] hasher `H`. /// /// # Example /// @@ -120,19 +120,19 @@ pub type GenericHasherMerkleTree = /// let mt = HasherMerkleTree::::from_elems(None, &my_data).unwrap(); /// } /// ``` -pub trait HasherDigest: Digest + Write + Send + Sync { - /// Associated type needed to express trait bounds. - type Foo: ArrayLength; - /// Associated type needed to express trait bounds. - type Bar: Copy; +pub trait HasherDigest: Digest + Write + Send + Sync { + /// Type for the output size + type OutSize: ArrayLength; + /// Type for the array + type ArrayType: Copy; } impl HasherDigest for T where T: Digest + Write + Send + Sync, >::ArrayType: Copy, { - type Foo = T::OutputSize; - type Bar = <::Foo as ArrayLength>::ArrayType; + type OutSize = T::OutputSize; + type ArrayType = <::OutSize as ArrayLength>::ArrayType; } /// A struct that impls [`DigestAlgorithm`] for use with [`MerkleTree`]. diff --git a/merkle_tree/src/prelude.rs b/merkle_tree/src/prelude.rs index 495c38f33..f1bfe2cdb 100644 --- a/merkle_tree/src/prelude.rs +++ b/merkle_tree/src/prelude.rs @@ -18,11 +18,13 @@ pub use crate::{ use super::light_weight::LightWeightMerkleTree; use crate::errors::MerkleTreeError; +use ark_ff::PrimeField; use ark_serialize::{ CanonicalDeserialize, CanonicalSerialize, Compress, Read, SerializationError, Valid, Validate, Write, }; use ark_std::{fmt, marker::PhantomData, vec::Vec}; +use jf_poseidon2::{Poseidon2, Poseidon2Params}; use jf_rescue::{crhf::RescueCRHF, RescueParameter}; use sha3::{Digest, Keccak256, Sha3_256}; @@ -52,6 +54,36 @@ pub type RescueLightWeightMerkleTree = LightWeightMerkleTree /// Example instantiation of a SparseMerkleTree indexed by I pub type RescueSparseMerkleTree = UniversalMerkleTree, I, 3, F>; +// TODO: (alex) move this compression to CRHF and wrap with better API? +/// Wrapper for Poseidon2 compression function +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Poseidon2Compression( + (PhantomData, PhantomData

, PhantomData<[(); N]>), +) +where + F: PrimeField, + P: Poseidon2Params; + +impl DigestAlgorithm for Poseidon2Compression +where + I: Index, + F: PrimeField + From, + P: Poseidon2Params, +{ + fn digest(data: &[F]) -> Result { + let mut input = [F::default(); N]; + input.copy_from_slice(&data[..]); + Ok(Poseidon2::permute::(&input)[0]) + } + + fn digest_leaf(pos: &I, elem: &F) -> Result { + let mut input = [F::default(); N]; + input[N - 1] = F::from(pos.clone()); + input[N - 2] = *elem; + Ok(Poseidon2::permute::(&input)[0]) + } +} + /// Implement Internal node type and implement DigestAlgorithm for a hash /// function with 32 bytes output size /// From 6f1678a8afd66248c625168e07e0595472f71c6b Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Thu, 12 Dec 2024 12:23:51 +0800 Subject: [PATCH 6/6] add Poseidon2 benchmark --- .gitignore | 2 +- poseidon2/CHANGELOG.md | 2 +- poseidon2/Cargo.toml | 7 +++ poseidon2/benches/p2_native.rs | 98 ++++++++++++++++++++++++++++++++++ poseidon2/src/lib.rs | 5 ++ 5 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 poseidon2/benches/p2_native.rs diff --git a/.gitignore b/.gitignore index c1e4d1003..27b105ae8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ .*.sw* .DS_Store .idea -/target +**/target cargo-system-config.toml Cargo.lock *.org diff --git a/poseidon2/CHANGELOG.md b/poseidon2/CHANGELOG.md index 52a92de8d..f733c7092 100644 --- a/poseidon2/CHANGELOG.md +++ b/poseidon2/CHANGELOG.md @@ -6,4 +6,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.1.0 -- Initial release. +- Initial release with Poseidon2 Permutation (w/ BLS12-381, BN254 instances) diff --git a/poseidon2/Cargo.toml b/poseidon2/Cargo.toml index 4a2797150..3f88081ba 100644 --- a/poseidon2/Cargo.toml +++ b/poseidon2/Cargo.toml @@ -18,8 +18,15 @@ ark-std = { workspace = true } hex = "0.4.3" lazy_static = "1.5.0" +[dev-dependencies] +criterion = "0.5.1" + [features] default = ["bls12-381", "bn254"] # curve-named features contains constants for scalar fields of that curve bls12-381 = ["dep:ark-bls12-381"] bn254 = ["dep:ark-bn254"] + +[[bench]] +name = "p2_native" +harness = false diff --git a/poseidon2/benches/p2_native.rs b/poseidon2/benches/p2_native.rs new file mode 100644 index 000000000..d25f68546 --- /dev/null +++ b/poseidon2/benches/p2_native.rs @@ -0,0 +1,98 @@ +//! Benchmark for native speed of Poseidon2 +//! `cargo bench --bench p2_native` +#[macro_use] +extern crate criterion; +use std::time::Duration; + +use ark_std::{test_rng, UniformRand}; +use criterion::Criterion; +use jf_poseidon2::{ + constants::{ + bls12_381::{Poseidon2ParamsBls2, Poseidon2ParamsBls3}, + bn254::Poseidon2ParamsBn3, + }, + Poseidon2, +}; + +// BLS12-381 scalar field, state size = 2 +fn bls2(c: &mut Criterion) { + let mut group = c.benchmark_group("Poseidon2 over (Bls12_381::Fr, t=2)"); + group.sample_size(10).measurement_time(Duration::new(20, 0)); + type Fr = ark_bls12_381::Fr; + let rng = &mut test_rng(); + + group.bench_function("1k iter", |b| { + b.iter(|| { + let mut input = [Fr::rand(rng), Fr::rand(rng)]; + for _ in 0..1000 { + Poseidon2::permute_mut::(&mut input); + } + }) + }); + group.bench_function("100k iter", |b| { + b.iter(|| { + let mut input = [Fr::rand(rng), Fr::rand(rng)]; + for _ in 0..100_000 { + Poseidon2::permute_mut::(&mut input); + } + }) + }); + group.finish(); +} + +// BLS12-381 scalar field, state size = 3 +fn bls3(c: &mut Criterion) { + let mut group = c.benchmark_group("Poseidon2 over (Bls12_381::Fr, t=3)"); + group.sample_size(10).measurement_time(Duration::new(20, 0)); + type Fr = ark_bls12_381::Fr; + let rng = &mut test_rng(); + + group.bench_function("1k iter", |b| { + b.iter(|| { + let mut input = [Fr::rand(rng), Fr::rand(rng), Fr::rand(rng)]; + for _ in 0..1000 { + Poseidon2::permute_mut::(&mut input); + } + }) + }); + group.bench_function("100k iter", |b| { + b.iter(|| { + let mut input = [Fr::rand(rng), Fr::rand(rng), Fr::rand(rng)]; + for _ in 0..100_000 { + Poseidon2::permute_mut::(&mut input); + } + }) + }); + group.finish(); +} + +// BN254 scalar field, state size = 3 +fn bn3(c: &mut Criterion) { + let mut group = c.benchmark_group("Poseidon2 over (Bn254::Fr, t=3)"); + group.sample_size(10).measurement_time(Duration::new(20, 0)); + type Fr = ark_bn254::Fr; + let rng = &mut test_rng(); + + group.bench_function("1k iter", |b| { + b.iter(|| { + let mut input = [Fr::rand(rng), Fr::rand(rng), Fr::rand(rng)]; + for _ in 0..1000 { + Poseidon2::permute_mut::(&mut input); + } + }) + }); + group.bench_function("100k iter", |b| { + b.iter(|| { + let mut input = [Fr::rand(rng), Fr::rand(rng), Fr::rand(rng)]; + for _ in 0..100_000 { + Poseidon2::permute_mut::(&mut input); + } + }) + }); + + group.finish(); +} + +criterion_group!(benches, bls2, bls3, bn3); + +criterion_main!(benches); diff --git a/poseidon2/src/lib.rs b/poseidon2/src/lib.rs index fc77c3a36..9670991fe 100644 --- a/poseidon2/src/lib.rs +++ b/poseidon2/src/lib.rs @@ -6,6 +6,11 @@ //! The Poseidon2 permutation. //! +//! # Available instances +//! We have implemented Poseidon2 instances: (field, state_size) +//! - (Bls12_381::Fr, 2), (Bls12_381::Fr, 3) +//! - (Bn254::Fr, 3) +//! //! This implementation was based upon the following resources: //! - https://github.com/HorizenLabs/poseidon2/blob/main/plain_implementations/src/poseidon2/poseidon2.rs //! - https://eprint.iacr.org/2023/323.pdf