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//! # Example
26//!
27//! ```rust,ignore
28//! use lib_q_poseidon::{Poseidon, Poseidon128};
29//! use lib_q_stark_field::extension::Complex;
30//! use lib_q_stark_mersenne31::Mersenne31;
31//!
32//! type Val = Complex<Mersenne31>;
33//!
34//! let hasher = Poseidon128::permutation();
35//! let input = vec![Val::from(1u32), Val::from(2u32)];
36//! let hash = hasher.hash(&input);
37//! ```
38
39#![cfg_attr(not(feature = "std"), no_std)]
40#![deny(unsafe_code)]
41#![deny(unused_qualifications)]
42
43#[cfg(feature = "alloc")]
44extern crate alloc;
45
46#[cfg(feature = "alloc")]
47use alloc::string::String;
48#[cfg(all(feature = "alloc", feature = "std"))]
49use alloc::string::ToString;
50
51mod constants;
52#[cfg(feature = "alloc")]
53mod params;
54#[cfg(feature = "alloc")]
55mod permutation;
56/// Value-level Poseidon2 permutation over BabyBear (width 16, the deployed
57/// Plonky3/SP1 instance). `no_std`/`alloc`-free; used by the Arm B membership AIR.
58pub mod poseidon2_baby_bear;
59#[cfg(feature = "alloc")]
60mod sponge;
61
62// Export constants for AIR constraint generation
63pub use constants::sbox;
64#[cfg(feature = "alloc")]
65pub use constants::{
66    mds_matrix_5x5,
67    mds_matrix_7x7,
68};
69#[cfg(feature = "alloc")]
70pub use constants::{
71    round_constants_128,
72    round_constants_256,
73};
74#[cfg(feature = "alloc")]
75pub use params::{
76    Poseidon128,
77    Poseidon256,
78    PoseidonField,
79    PoseidonParams,
80};
81#[cfg(feature = "alloc")]
82pub use permutation::{
83    PoseidonPermutation,
84    PoseidonState,
85};
86#[cfg(feature = "alloc")]
87pub use sponge::{
88    Poseidon,
89    PoseidonSponge,
90    PoseidonSpongeSqueeze,
91};
92
93#[cfg(feature = "wasm")]
94pub mod wasm;
95
96/// Error types for Poseidon operations
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub enum PoseidonError {
99    /// Input size exceeds maximum allowed
100    InputTooLarge { max: usize, actual: usize },
101    /// Invalid parameter configuration
102    #[cfg(feature = "alloc")]
103    InvalidParams { reason: String },
104    /// Internal error during hashing
105    #[cfg(feature = "alloc")]
106    InternalError { reason: String },
107}
108
109impl core::fmt::Display for PoseidonError {
110    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111        match self {
112            PoseidonError::InputTooLarge { max, actual } => {
113                write!(f, "Input size {} exceeds maximum {}", actual, max)
114            }
115            #[cfg(feature = "alloc")]
116            PoseidonError::InvalidParams { reason } => {
117                write!(f, "Invalid Poseidon parameters: {}", reason)
118            }
119            #[cfg(feature = "alloc")]
120            PoseidonError::InternalError { reason } => {
121                write!(f, "Internal Poseidon error: {}", reason)
122            }
123        }
124    }
125}
126
127#[cfg(all(feature = "alloc", feature = "std"))]
128impl From<PoseidonError> for lib_q_core::Error {
129    fn from(err: PoseidonError) -> Self {
130        lib_q_core::Error::InternalError {
131            operation: "Poseidon hash".into(),
132            details: err.to_string(),
133        }
134    }
135}
136
137#[cfg(all(not(feature = "alloc"), feature = "std"))]
138impl From<PoseidonError> for lib_q_core::Error {
139    fn from(err: PoseidonError) -> Self {
140        match err {
141            PoseidonError::InputTooLarge { .. } => lib_q_core::Error::InternalError {
142                operation: "Poseidon hash",
143                details: "input too large",
144            },
145        }
146    }
147}