diff --git a/poseidon/src/lib.rs b/poseidon/src/lib.rs index e2ff0f1e60..5b023d0ba2 100644 --- a/poseidon/src/lib.rs +++ b/poseidon/src/lib.rs @@ -1,3 +1,28 @@ +//! This crate provides a generic implementation of the Poseidon hash function. +//! It provides a [Sponge](crate::sponge::FqSponge) trait that can be +//! implemented for any field. +//! +//! Some parameters for the Pasta fields are provided in the sub-crate +//! [crate::pasta]. +//! +//! To instantiate an object that can be used to generate challenges for the +//! Fiat-Shamir transformation, use the +//! [DefaultFqSponge](crate::sponge::DefaultFqSponge) struct. For instance, to +//! instantiate with the parameters used by the Mina hard-fork called Berkeley, +//! use: +//! ```rust +//! use mina_curves::pasta::{VestaParameters}; +//! use mina_poseidon::sponge::DefaultFqSponge; +//! use mina_poseidon::FqSponge; +//! use mina_poseidon::constants::PlonkSpongeConstantsKimchi; +//! use mina_poseidon::pasta::fq_kimchi; +//! +//! let mut sponge = DefaultFqSponge::::new( +//! fq_kimchi::static_params(), +//! ); +//! let challenge = sponge.challenge(); +//! ``` + pub mod constants; pub mod dummy_values; pub mod pasta; diff --git a/poseidon/tests/poseidon_tests.rs b/poseidon/tests/poseidon_tests.rs index 61345b2298..37cafe940f 100644 --- a/poseidon/tests/poseidon_tests.rs +++ b/poseidon/tests/poseidon_tests.rs @@ -1,10 +1,14 @@ -use mina_curves::pasta::Fp; +use ark_ff::{Field, UniformRand}; +use mina_curves::pasta::{Fp, Fq, PallasParameters, VestaParameters}; use mina_poseidon::{ constants::{PlonkSpongeConstantsKimchi, PlonkSpongeConstantsLegacy}, - pasta::{fp_kimchi as SpongeParametersKimchi, fp_legacy as SpongeParametersLegacy}, + pasta::{fp_kimchi, fp_legacy, fq_kimchi}, poseidon::{ArithmeticSponge as Poseidon, Sponge as _}, + sponge::DefaultFqSponge, + FqSponge as _, }; use o1_utils::FieldHelpers; +use rand::Rng; use serde::Deserialize; use std::{fs::File, path::PathBuf}; // needed for ::new() sponge @@ -58,9 +62,7 @@ where #[test] fn poseidon_test_vectors_legacy() { fn hash(input: &[Fp]) -> Fp { - let mut hash = Poseidon::::new( - SpongeParametersLegacy::static_params(), - ); + let mut hash = Poseidon::::new(fp_legacy::static_params()); hash.absorb(input); hash.squeeze() } @@ -70,11 +72,67 @@ fn poseidon_test_vectors_legacy() { #[test] fn poseidon_test_vectors_kimchi() { fn hash(input: &[Fp]) -> Fp { - let mut hash = Poseidon::::new( - SpongeParametersKimchi::static_params(), - ); + let mut hash = Poseidon::::new(fp_kimchi::static_params()); hash.absorb(input); hash.squeeze() } test_vectors("kimchi.json", hash); } + +#[test] +fn test_regression_challenge_empty_vesta_kimchi() { + let mut sponge = DefaultFqSponge::::new( + fq_kimchi::static_params(), + ); + let output = sponge.challenge(); + let exp_output = + Fp::from_hex("c1e504c0184cce70a605d2f942d579c500000000000000000000000000000000").unwrap(); + assert_eq!(output, exp_output); +} + +#[test] +fn test_regression_challenge_empty_pallas_kimchi() { + let mut sponge = DefaultFqSponge::::new( + fp_kimchi::static_params(), + ); + let output = sponge.challenge(); + let exp_output = + Fq::from_hex("a8eb9ee0f30046308abbfa5d20af73c800000000000000000000000000000000").unwrap(); + assert_eq!(output, exp_output); +} + +#[test] +fn test_poseidon_vesta_kimchi_challenge_is_squeezed_to_128_bits() { + // Test that the challenge is less than 2^128, i.e. the sponge state is + // squeezed to 128 bits + let mut sponge = DefaultFqSponge::::new( + fq_kimchi::static_params(), + ); + let mut rng = o1_utils::tests::make_test_rng(None); + let random_n = rng.gen_range(1..50); + let random_fq_vec = (0..random_n) + .map(|_| Fq::rand(&mut rng)) + .collect::>(); + sponge.absorb_fq(&random_fq_vec); + let challenge = sponge.challenge(); + let two_128 = Fp::from(2).pow([128]); + assert!(challenge < two_128); +} + +#[test] +fn test_poseidon_pallas_kimchi_challenge_is_squeezed_to_128_bits() { + // Test that the challenge is less than 2^128, i.e. the sponge state is + // squeezed to 128 bits + let mut sponge = DefaultFqSponge::::new( + fp_kimchi::static_params(), + ); + let mut rng = o1_utils::tests::make_test_rng(None); + let random_n = rng.gen_range(1..50); + let random_fp_vec = (0..random_n) + .map(|_| Fp::rand(&mut rng)) + .collect::>(); + sponge.absorb_fq(&random_fp_vec); + let challenge = sponge.challenge(); + let two_128 = Fq::from(2).pow([128]); + assert!(challenge < two_128); +}