Skip to main content

lib_q_poseidon/
lib.rs

1//! Poseidon hash function optimized for zero-knowledge proofs
2//!
3//! This crate provides a field-native implementation of the Poseidon hash function,
4//! specifically optimized for use in STARK proof systems with `Complex<Mersenne31>`.
5//!
6//! # Design
7//!
8//! Poseidon is an algebraic hash function designed for efficient implementation in
9//! zero-knowledge proof systems. Unlike traditional hashes like SHA-3, Poseidon
10//! operates directly on field elements, making it orders of magnitude more efficient
11//! in circuit constraints.
12//!
13//! # Security
14//!
15//! - Uses round counts and an MDS construction inspired by the Poseidon design.
16//! - MDS matrices use a Cauchy construction (every square submatrix is invertible).
17//!
18//! WARNING: the round counts and sponge parameters in this crate have NOT been
19//! independently verified for the `Complex<Mersenne31>` extension field GF(p²).
20//! The standard Poseidon security analysis is stated over a prime field and does
21//! not directly cover this exact field and state. Do NOT rely on a specific
22//! bit-security level (e.g. 128-bit or 256-bit) for these parameters until they
23//! have been regenerated and analyzed for GF(p²).
24//!
25//! ## Parameter sets and the "Top Gun" degree-annihilation attacks (2026-08-09)
26//!
27//! This crate ships three parameter sets: **Poseidon-128** (original Poseidon,
28//! `GF(p²)` over Mersenne31, t=5, alpha=5, R_F=8, R_P=56), **Poseidon-256** (same
29//! field, t=7, alpha=5, R_F=8, R_P=60), and **Poseidon2-BabyBear** (the
30//! Plonky3/SP1 instance, t=16, alpha=7, R_F=8, R_P=13).
31//!
32//! Sanso & Vitto, "Top Gun: Degree Annihilation Attacks on Poseidon" (eprint
33//! preliminary, 2026), do **not** apply to any of the three sets, each for a
34//! reason the paper states in its own words:
35//! - Poseidon-128 / Poseidon-256: alpha=5, and the paper says larger exponents
36//!   "such as alpha = 5 or alpha = 7 ... increase the local degree that must be
37//!   annihilated" and are "expected to make the strategy less effective";
38//!   separately, R_F=8 for both sets, and the paper's own R_F=8 experiment
39//!   "did not yield a solution, suggesting that this direction should be
40//!   revisited with different families of controls".
41//! - Poseidon2-BabyBear: it is Poseidon2, and the paper states "the initial
42//!   linear transformation prevents the same two-round skip" that the attack's
43//!   construction is built on; it also uses alpha=7 and R_F=8, the same two
44//!   unfavourable conditions as above.
45//!
46//! Two caveats that matter and must not be dropped:
47//! 1. For Poseidon2-BabyBear, the paper's own (prior-work, classical
48//!    one-round-skip) degree formula alpha^(R_F+R_P-1) gives 7^20 ≈ 2^56.1,
49//!    against a generic CICO-2 cost on BabyBear of roughly 2^62 for the bare
50//!    permutation. This is **not** a Top Gun contribution — Top Gun demonstrates
51//!    no Poseidon2 annihilation anywhere in the paper. Whether a CICO-2 solve on
52//!    the bare permutation reduces to a collision or preimage attack on our
53//!    actual construction (a sponge with rate 7 / capacity 9 field elements,
54//!    used for Merkle hashing and Fiat-Shamir) is **undetermined** — no such
55//!    reduction was written or found. This is not a break; it is an open
56//!    question worth tracking, not something to bury.
57//! 2. Poseidon-128 and Poseidon-256 are **not** reference Poseidon parameter
58//!    sets: their MDS matrices are a locally-built Cauchy construction and
59//!    their round constants come from a local SHAKE256 seed string (no
60//!    Grain-LFSR, no external provenance — see the WARNING above and
61//!    `constants.rs`). Top Gun §4.1 says exactly this category of deployment
62//!    needs "parameter by parameter" analysis. That gap pre-dates and is
63//!    independent of Top Gun; Top Gun does not create it and does not close it.
64//!
65//! Five related papers were sought but could not be obtained at assessment
66//! time, so their content is not reflected above: Merz & Rodriguez Garcia,
67//! "Skipping Class" (ePrint 2026/306) — the actual Poseidon2/Poseidon2b attack
68//! paper, and the largest open gap for the Poseidon2-BabyBear set; Zhao,
69//! Sanso, Vitto & Ding, "Graeffe-based attacks on Poseidon and NTT lower
70//! bounds" (ePrint 2025/1916); Bak et al. (ePrint 2025/2040); Bak et al.
71//! (ePrint 2026/150); and a Grassi et al. survey referenced by Top Gun.
72//!
73//! # Example
74//!
75//! ```rust,ignore
76//! use lib_q_poseidon::{Poseidon, Poseidon128};
77//! use lib_q_stark_field::extension::Complex;
78//! use lib_q_stark_mersenne31::Mersenne31;
79//!
80//! type Val = Complex<Mersenne31>;
81//!
82//! let hasher = Poseidon128::permutation();
83//! let input = vec![Val::from(1u32), Val::from(2u32)];
84//! let hash = hasher.hash(&input);
85//! ```
86
87#![cfg_attr(not(feature = "std"), no_std)]
88#![deny(unsafe_code)]
89#![deny(unused_qualifications)]
90
91#[cfg(feature = "alloc")]
92extern crate alloc;
93
94#[cfg(feature = "alloc")]
95use alloc::string::String;
96#[cfg(all(feature = "alloc", feature = "std"))]
97use alloc::string::ToString;
98
99mod constants;
100#[cfg(feature = "alloc")]
101mod params;
102#[cfg(feature = "alloc")]
103mod permutation;
104/// Value-level Poseidon2 permutation over BabyBear (width 16, the deployed
105/// Plonky3/SP1 instance). `no_std`/`alloc`-free; used by the Arm B membership AIR.
106pub mod poseidon2_baby_bear;
107#[cfg(feature = "alloc")]
108mod sponge;
109
110// Export constants for AIR constraint generation
111pub use constants::sbox;
112#[cfg(feature = "alloc")]
113pub use constants::{
114    mds_matrix_5x5,
115    mds_matrix_7x7,
116};
117#[cfg(feature = "alloc")]
118pub use constants::{
119    round_constants_128,
120    round_constants_256,
121};
122#[cfg(feature = "alloc")]
123pub use params::{
124    Poseidon128,
125    Poseidon256,
126    PoseidonField,
127    PoseidonParams,
128};
129#[cfg(feature = "alloc")]
130pub use permutation::{
131    PoseidonPermutation,
132    PoseidonState,
133};
134#[cfg(feature = "alloc")]
135pub use sponge::{
136    Poseidon,
137    PoseidonSponge,
138    PoseidonSpongeSqueeze,
139};
140
141#[cfg(feature = "wasm")]
142pub mod wasm;
143
144/// Error types for Poseidon operations
145#[derive(Debug, Clone, PartialEq, Eq)]
146pub enum PoseidonError {
147    /// Input size exceeds maximum allowed
148    InputTooLarge { max: usize, actual: usize },
149    /// Invalid parameter configuration
150    #[cfg(feature = "alloc")]
151    InvalidParams { reason: String },
152    /// Internal error during hashing
153    #[cfg(feature = "alloc")]
154    InternalError { reason: String },
155}
156
157impl core::fmt::Display for PoseidonError {
158    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
159        match self {
160            PoseidonError::InputTooLarge { max, actual } => {
161                write!(f, "Input size {} exceeds maximum {}", actual, max)
162            }
163            #[cfg(feature = "alloc")]
164            PoseidonError::InvalidParams { reason } => {
165                write!(f, "Invalid Poseidon parameters: {}", reason)
166            }
167            #[cfg(feature = "alloc")]
168            PoseidonError::InternalError { reason } => {
169                write!(f, "Internal Poseidon error: {}", reason)
170            }
171        }
172    }
173}
174
175#[cfg(all(feature = "alloc", feature = "std"))]
176impl From<PoseidonError> for lib_q_core::Error {
177    fn from(err: PoseidonError) -> Self {
178        lib_q_core::Error::InternalError {
179            operation: "Poseidon hash".into(),
180            details: err.to_string(),
181        }
182    }
183}
184
185#[cfg(all(not(feature = "alloc"), feature = "std"))]
186impl From<PoseidonError> for lib_q_core::Error {
187    fn from(err: PoseidonError) -> Self {
188        match err {
189            PoseidonError::InputTooLarge { .. } => lib_q_core::Error::InternalError {
190                operation: "Poseidon hash",
191                details: "input too large",
192            },
193        }
194    }
195}