From f1204dbd87b7d09ccce8ef59848abf634688641d Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 19 Oct 2021 18:27:05 -0700 Subject: [PATCH] Rework API based on split-sponge refactor in our fork. This uses the API changes from: - https://github.com/arkworks-rs/sponge/issues/29 - https://github.com/arkworks-rs/sponge/pull/30 to avoid working through the Arkworks sponge interface, and do hashing using the permutation directly. --- Cargo.toml | 3 +- src/hash.rs | 57 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 55 ++++++++++--------------------------- src/params.rs | 18 ++++++------ src/sponge.rs | 59 ---------------------------------------- vendor/generate_mds.sage | 6 ++-- 6 files changed, 86 insertions(+), 112 deletions(-) create mode 100644 src/hash.rs delete mode 100644 src/sponge.rs diff --git a/Cargo.toml b/Cargo.toml index 4ae104f..9fb3f1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +once_cell = "1.8" ark-ff = "0.3" -ark-sponge = { git = "https://github.com/arkworks-rs/sponge", rev = "51d6fc9aac1fa69f44a04839202b5de828584ed8" } +ark-sponge = { git = "https://github.com/penumbra-zone/sponge", branch = "split-sponge" } ark-ed-on-bls12-377 = "0.3" diff --git a/src/hash.rs b/src/hash.rs new file mode 100644 index 0000000..883dc4e --- /dev/null +++ b/src/hash.rs @@ -0,0 +1,57 @@ +use crate::{Fq, State}; + +/// Hash a single [`Fq`] element with the provided `domain_separator`. +pub fn hash_1(domain_separator: &Fq, value: Fq) -> Fq { + let mut state = State::from(crate::RATE_1_PARAMS.clone()); + + // Use the domain separator as the sponge's capacity element + state[0] = domain_separator.clone(); + state[1] = value; + + state.permute(); + state[1] +} + +/// Hash two [`Fq`] elements with the provided `domain_separator`. +pub fn hash_2(domain_separator: &Fq, value: (Fq, Fq)) -> Fq { + let mut state = State::from(crate::RATE_2_PARAMS.clone()); + + // Use the domain separator as the sponge's capacity element + state[0] = domain_separator.clone(); + state[1] = value.0; + state[2] = value.1; + + state.permute(); + state[1] +} + +/// Hash four [`Fq`] elements with the provided `domain_separator`. +pub fn hash_4(domain_separator: &Fq, value: (Fq, Fq, Fq, Fq)) -> Fq { + let mut state = State::from(crate::RATE_4_PARAMS.clone()); + + // Use the domain separator as the sponge's capacity element + state[0] = domain_separator.clone(); + state[1] = value.0; + state[2] = value.1; + state[3] = value.2; + state[4] = value.3; + + state.permute(); + state[1] +} + +/// Hash five [`Fq`] elements with the provided `domain_separator`. +pub fn hash_5(domain_separator: &Fq, value: (Fq, Fq, Fq, Fq, Fq)) -> Fq { + let mut state = State::from(crate::RATE_5_PARAMS.clone()); + + // Use the domain separator as the sponge's capacity element + state[0] = domain_separator.clone(); + state[1] = value.0; + state[2] = value.1; + state[3] = value.2; + state[4] = value.3; + state[5] = value.4; + + state.permute(); + state[1] +} diff --git a/src/lib.rs b/src/lib.rs index def84ee..8bec289 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,45 +1,20 @@ -mod sponge; +//! An instantiation of Poseidon for the BLS12-377 scalar field. -pub mod params; +use once_cell::sync::Lazy; -// Since we depend on a git version of ark-sponge, re-exporting it here means -// our deps can access it without having to keep git revisions in sync. -// -// Going forward, this re-export should be removed and the functionality our -// deps need from direct use of ark-sponge should be folded into this crate. -// However, it's faster to iterate on required functionality without imposing -// hard compartmentalization boundaries from the start. -pub use ark_sponge; +mod hash; +mod params; -#[cfg(test)] -mod tests { - use super::*; +pub use hash::{hash_1, hash_2, hash_4, hash_5}; - #[test] - fn it_works() { - use ark_ed_on_bls12_377::Fq; // lazy import, fix - use ark_ff::{One, Zero}; - use ark_sponge::{ - poseidon::PoseidonSponge, CryptographicSponge, DuplexSpongeMode, - FieldBasedCryptographicSponge, - }; +/// Parameters for the rate-1 instance of Poseidon. +pub const RATE_1_PARAMS: Lazy> = Lazy::new(params::rate_1); +/// Parameters for the rate-2 instance of Poseidon. +pub const RATE_2_PARAMS: Lazy> = Lazy::new(params::rate_2); +/// Parameters for the rate-4 instance of Poseidon. +pub const RATE_4_PARAMS: Lazy> = Lazy::new(params::rate_4); +/// Parameters for the rate-5 instance of Poseidon. +pub const RATE_5_PARAMS: Lazy> = Lazy::new(params::rate_5); - // Current API has a `new()` method as part of the `CryptographicSponge` - // trait, but this method doesn't allow setting the initial state - // manually. Instead, the fields can be set manually. - // Slightly inconvenient that we have to initialize the mode. - let mut sponge = PoseidonSponge { - parameters: params::rate_2(), - state: vec![Fq::zero(); 3], - mode: DuplexSpongeMode::Absorbing { - next_absorb_index: 0, - }, - }; - - sponge.absorb(&Fq::one()); - sponge.absorb(&Fq::one()); - - let output = sponge.squeeze_native_field_elements(1); - dbg!(output); - } -} +pub use ark_ed_on_bls12_377::Fq; +pub use ark_sponge::poseidon::{Parameters, State}; diff --git a/src/params.rs b/src/params.rs index 23faac4..0a9e60c 100644 --- a/src/params.rs +++ b/src/params.rs @@ -6,13 +6,13 @@ // Generated with `generate_mds.sage`. Do not edit manually. // Regenerate with: `sage vendor/generate_mds.sage > src/params.rs` +use crate::Parameters; use ark_ff::PrimeField; -use ark_sponge::poseidon::PoseidonParameters; /// Parameters for the rate-1 instance of Poseidon. /// /// Note: `F` must be the BLS12-377 scalar field. -pub fn rate_1() -> PoseidonParameters { +pub fn rate_1() -> Parameters { let mds = vec![ vec![ F::from_str( @@ -498,7 +498,7 @@ pub fn rate_1() -> PoseidonParameters { ], ]; - PoseidonParameters { + Parameters { full_rounds: 8, partial_rounds: 30, alpha: 17, @@ -512,7 +512,7 @@ pub fn rate_1() -> PoseidonParameters { /// Parameters for the rate-2 instance of Poseidon. /// /// Note: `F` must be the BLS12-377 scalar field. -pub fn rate_2() -> PoseidonParameters { +pub fn rate_2() -> Parameters { let mds = vec![ vec![ F::from_str( @@ -1232,7 +1232,7 @@ pub fn rate_2() -> PoseidonParameters { ], ]; - PoseidonParameters { + Parameters { full_rounds: 8, partial_rounds: 31, alpha: 17, @@ -1246,7 +1246,7 @@ pub fn rate_2() -> PoseidonParameters { /// Parameters for the rate-4 instance of Poseidon. /// /// Note: `F` must be the BLS12-377 scalar field. -pub fn rate_4() -> PoseidonParameters { +pub fn rate_4() -> Parameters { let mds = vec![ vec![ F::from_str( @@ -2305,7 +2305,7 @@ pub fn rate_4() -> PoseidonParameters { ], ]; - PoseidonParameters { + Parameters { full_rounds: 8, partial_rounds: 26, alpha: 17, @@ -2319,7 +2319,7 @@ pub fn rate_4() -> PoseidonParameters { /// Parameters for the rate-5 instance of Poseidon. /// /// Note: `F` must be the BLS12-377 scalar field. -pub fn rate_5() -> PoseidonParameters { +pub fn rate_5() -> Parameters { let mds = vec![ vec![ F::from_str( @@ -3509,7 +3509,7 @@ pub fn rate_5() -> PoseidonParameters { ], ]; - PoseidonParameters { + Parameters { full_rounds: 8, partial_rounds: 23, alpha: 17, diff --git a/src/sponge.rs b/src/sponge.rs deleted file mode 100644 index ab7223b..0000000 --- a/src/sponge.rs +++ /dev/null @@ -1,59 +0,0 @@ -use ark_ed_on_bls12_377::Fq; -use ark_ff::One; -use ark_sponge::{poseidon::PoseidonSponge, CryptographicSponge, FieldBasedCryptographicSponge}; - -use crate::params; - -// This struct will let us replace the implementation of the inner -// PoseidonSponge if we later choose to do so. -struct Sponge { - inner: PoseidonSponge, - // TODOs: Domain separation, mode variable, padding fcn, cache? -} - -impl Sponge { - fn new() -> Self { - let mut sponge = PoseidonSponge::::new(¶ms::rate_2()); - Sponge { inner: sponge } - } - - /// Take a single field element into the sponge. - fn absorb(&mut self, element: Fq) { - self.inner.absorb(&element) - } - - /// Produce a single field element. - fn squeeze(&mut self) -> Fq { - self.inner.squeeze_native_field_elements(1)[0] - } - - /// Hash variable-length input into a hash. - pub fn hash(&mut self, message: Vec, out_len: usize) -> Vec { - for i in 0..message.len() { - self.absorb(message[i]); - } - - // Domain separation - self.absorb(Fq::one()); - - let mut output = Vec::::new(); - for _i in 0..out_len { - output.push(self.squeeze()); - } - output - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_variable_len_hash() { - let out_len = 1; - let mut sponge = Sponge::new(); - let message = vec![Fq::one(), Fq::one()]; - let result = sponge.hash(message, out_len); - assert_eq!(result.len(), out_len); - } -} diff --git a/vendor/generate_mds.sage b/vendor/generate_mds.sage index f9b02bb..eb452e3 100644 --- a/vendor/generate_mds.sage +++ b/vendor/generate_mds.sage @@ -330,11 +330,11 @@ def generate_poseidon_param_code( /// Parameters for the rate-{rate} instance of Poseidon. /// /// Note: `F` must be the BLS12-377 scalar field. -pub fn rate_{rate}() -> PoseidonParameters {{ +pub fn rate_{rate}() -> Parameters {{ """ closing = f""" - PoseidonParameters {{ + Parameters {{ full_rounds: {num_rounds - R_p}, partial_rounds: {R_p}, alpha: {alpha}, @@ -396,7 +396,7 @@ print("""//! Parameters for various Poseidon instances over the BLS12-377 scalar // Regenerate with: `sage vendor/generate_mds.sage > src/params.rs` use ark_ff::PrimeField; -use ark_sponge::poseidon::PoseidonParameters; +use crate::Parameters; """)