Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 39 additions & 20 deletions soroban-sdk/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ pub(crate) mod poseidon_params;
pub mod poseidon_sponge;
pub(crate) mod utils;
pub use bn254::Fr as BnScalar;
pub use poseidon2_sponge::Poseidon2Sponge;
pub use poseidon_sponge::PoseidonSponge;
pub use poseidon2_sponge::{Poseidon2Config, Poseidon2Sponge};
pub use poseidon_sponge::{PoseidonConfig, PoseidonSponge};

/// A `BytesN<N>` generated by a cryptographic hash function.
///
Expand Down Expand Up @@ -199,26 +199,45 @@ impl Crypto {
bn254::Bn254::new(self.env())
}

/// Performs a Poseidon hash using a sponge construction
pub fn poseidon_hash(&self, inputs: &Vec<U256>, field: Symbol) -> U256 {
// The initial value for the capacity element initialized with 0 for standard Poseidon
let iv = U256::from_u32(&self.env, 0);
let mut sponge = PoseidonSponge::new(&self.env, iv, field);
for input in inputs.iter() {
sponge.absorb(input);
}
sponge.squeeze()
/// Computes a Poseidon hash matching circom's
/// [implementation](https://github.com/iden3/circomlib/blob/35e54ea21da3e8762557234298dbb553c175ea8d/circuits/poseidon.circom)
/// for input lengths up to 5 (`t ≤ 6`).
///
/// Internally it picks the state size `t` to match the input length, i.e.
/// `t = N + 1` (rate = N, capacity = 1). For example, hashing 2 elements
/// uses t=3.
///
/// Note: use [`poseidon_sponge::hash`] with a pre-constructed
/// [`PoseidonConfig`] directly if:
/// - You want to repeatedly hash with the same input size. Pre-constructing
/// the config saves the cost of re-initialization.
/// - You want to hash larger input sizes. The sponge will repeatedly
/// permute and absorb until the entire input is consumed. This is a valid
/// (and secure) sponge operation, even though it may not match circom's
/// output, which always picks a larger state size (N+1) to hash inputs in
/// one shot (up to t=17). If you need parameter support for larger `t`,
/// please file an issue.
pub fn poseidon_hash(&self, field_type: Symbol, inputs: &Vec<U256>) -> U256 {
let config = PoseidonConfig::new(&self.env, field_type, inputs.len() as u32);
poseidon_sponge::hash(&self.env, inputs, config)
}

/// Performs a poseidon2 hash with a sponge construction equivalent to the one in the Barretenberg proving system
pub fn poseidon2_hash(&self, inputs: &Vec<U256>, field: Symbol) -> U256 {
// The initial value for the capacity element initialized with `input.len() * 2^24` for Poseidon2
let iv = U256::from_u128(&self.env, (inputs.len() as u128) << 64);
let mut sponge = Poseidon2Sponge::new(&self.env, iv, field);
for input in inputs.iter() {
sponge.absorb(input);
}
sponge.squeeze()
/// Computes a Poseidon2 hash matching noir's
/// [implementation](https://github.com/noir-lang/noir/blob/abfee1f54b20984172ba23482f4af160395cfba5/noir_stdlib/src/hash/poseidon2.nr).
///
/// Internally it always initializes the state with `t = 4`, regardless of
/// input length. It alternates between absorbing and permuting until all
/// input elements are consumed.
///
/// Note: use [`poseidon2_sponge::hash`] with a pre-constructed
/// [`Poseidon2Config`] directly if:
/// - You need to hash multiple times. Pre-constructing the config saves the
/// cost of re-initialization.
/// - You want to use a different state size (`t ≤ 4`).
pub fn poseidon2_hash(&self, field_type: Symbol, inputs: &Vec<U256>) -> U256 {
const INTERNAL_RATE: u32 = 3;
let config = Poseidon2Config::new(&self.env, field_type, INTERNAL_RATE);
poseidon2_sponge::hash(&self.env, inputs, config)
}
}

Expand Down
Loading
Loading