From 5825dacce288ca30d83ff5edbef4b97ffa3366c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michele=20Orr=C3=B9?= Date: Tue, 30 Jan 2024 00:48:37 +0100 Subject: [PATCH] Simplifying the hash interface; wrap up Poseidon. --- Cargo.lock | 104 ++++-------------------------------- Cargo.toml | 5 +- src/hash/anemoi.rs | 103 ----------------------------------- src/hash/index.rs | 29 ++++++++++ src/hash/keccak.rs | 66 +++-------------------- src/hash/mod.rs | 5 +- src/plugins/ark/anemoi.rs | 49 +++++++++++++++++ src/plugins/ark/mod.rs | 3 ++ src/plugins/ark/poseidon.rs | 85 +++++------------------------ 9 files changed, 116 insertions(+), 333 deletions(-) delete mode 100644 src/hash/anemoi.rs create mode 100644 src/hash/index.rs create mode 100644 src/plugins/ark/anemoi.rs diff --git a/Cargo.lock b/Cargo.lock index 6d13bf3..99290f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ dependencies = [ [[package]] name = "ark-bls12-381" version = "0.4.0" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "ark-ec", "ark-ff", @@ -55,24 +55,6 @@ dependencies = [ "ark-std", ] -[[package]] -name = "ark-crypto-primitives" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "blake2", - "derivative", - "digest", - "sha2", -] - [[package]] name = "ark-curve25519" version = "0.4.0" @@ -87,7 +69,7 @@ dependencies = [ [[package]] name = "ark-ec" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "ark-ff", "ark-poly", @@ -104,7 +86,7 @@ dependencies = [ [[package]] name = "ark-ff" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "ark-ff-asm", "ark-ff-macros", @@ -123,7 +105,7 @@ dependencies = [ [[package]] name = "ark-ff-asm" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "quote", "syn 2.0.48", @@ -132,7 +114,7 @@ dependencies = [ [[package]] name = "ark-ff-macros" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "num-bigint", "num-traits", @@ -144,7 +126,7 @@ dependencies = [ [[package]] name = "ark-poly" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "ark-ff", "ark-serialize", @@ -153,22 +135,10 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "ark-relations" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" -dependencies = [ - "ark-ff", - "ark-std", - "tracing", - "tracing-subscriber", -] - [[package]] name = "ark-serialize" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "ark-serialize-derive", "ark-std", @@ -179,25 +149,13 @@ dependencies = [ [[package]] name = "ark-serialize-derive" version = "0.4.2" -source = "git+https://github.com/arkworks-rs/algebra#bf96a5b2873e69f3c378c7b25d0901a6701efcc4" +source = "git+https://github.com/arkworks-rs/algebra#228787b5ab87139dc2a79359d2f6b25237f46dac" dependencies = [ "proc-macro2", "quote", "syn 2.0.48", ] -[[package]] -name = "ark-snark" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" -dependencies = [ - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-std", -] - [[package]] name = "ark-std" version = "0.4.0" @@ -415,9 +373,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -464,7 +422,6 @@ version = "0.0.1-beta5" dependencies = [ "anyhow", "ark-bls12-381", - "ark-crypto-primitives", "ark-curve25519", "ark-ec", "ark-ff", @@ -534,12 +491,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - [[package]] name = "platforms" version = "3.3.0" @@ -660,35 +611,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - [[package]] name = "typenum" version = "1.17.0" @@ -701,12 +623,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 691720b..b3df277 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,8 +26,7 @@ log = "0.4.20" # optional dependencies ark-ff = {version="0.4.0", optional=true} ark-ec = {version="0.4.0", optional=true} -ark-serialize = {version="0.4.2", optional=true} -ark-crypto-primitives = {version="0.4.0", optional=true} +ark-serialize = {version="0.4.2", optional=true, features=["std"]} curve25519-dalek = {version="4.0.0", optional=true, features=["group"]} # anemoi = {git = "https://github.com/anemoi-hash/anemoi-rust", optional=true} group = {version="0.13.0", optional=true} @@ -35,7 +34,7 @@ ark-bls12-381 = {version="0.4.0", optional=true} [features] default = [] -ark = ["dep:ark-ff", "dep:ark-ec", "dep:ark-serialize", "dep:ark-crypto-primitives", "dep:ark-bls12-381"] +ark = ["dep:ark-ff", "dep:ark-ec", "dep:ark-serialize", "dep:ark-bls12-381"] group = ["dep:group", "dep:curve25519-dalek"] # anemoi = ["dep:anemoi"] diff --git a/src/hash/anemoi.rs b/src/hash/anemoi.rs deleted file mode 100644 index 9d7f5b9..0000000 --- a/src/hash/anemoi.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Work-in-progress (but working) implementation of the Anemoi hash function. -//! -//! The main reason for this code not being deployed is that [anemoi](https://anemoi-hash.github.io/)'s Rust implementation -//! is not published as a crate and thus `nimue` cannot publish it along with a new release. - -use ark_ff::Field; -use std::ops::{Index, IndexMut, Range, RangeFrom, RangeTo}; -use zeroize::Zeroize; - -use super::sponge::Sponge; - -#[derive(Clone, Zeroize)] -pub struct AnemoiState([F; N]); - -impl Default for AnemoiState { - fn default() -> Self { - Self([F::zero(); N]) - } -} - -impl Index for AnemoiState { - type Output = F; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for AnemoiState { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Index> for AnemoiState { - type Output = [F]; - - fn index(&self, index: RangeFrom) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut> for AnemoiState { - fn index_mut(&mut self, index: RangeFrom) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Index> for AnemoiState { - type Output = [F]; - - fn index(&self, index: RangeTo) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut> for AnemoiState { - fn index_mut(&mut self, index: RangeTo) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Index> for AnemoiState { - type Output = [F]; - - fn index(&self, index: Range) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut> for AnemoiState { - fn index_mut(&mut self, index: Range) -> &mut Self::Output { - &mut self.0[index] - } -} - -pub type AnemoiBls12_381_2_1 = AnemoiState; -use anemoi::bls12_381::anemoi_2_1::AnemoiBls12_381_2_1 as _AnemoiBls12_381_2_1; -use anemoi::Anemoi; - -impl Sponge - for AnemoiState< - anemoi::bls12_381::Felt, - { _AnemoiBls12_381_2_1::RATE }, - { _AnemoiBls12_381_2_1::WIDTH }, - > -{ - type U = anemoi::bls12_381::Felt; - - const CAPACITY: usize = _AnemoiBls12_381_2_1::WIDTH - _AnemoiBls12_381_2_1::RATE; - - const RATE: usize = _AnemoiBls12_381_2_1::RATE; - - fn new(tag: [u8; 32]) -> Self { - let mut state = Self::default(); - state[0] = anemoi::bls12_381::Felt::from_le_bytes_mod_order(&tag); - state - } - - fn permute(&mut self) { - _AnemoiBls12_381_2_1::permutation(&mut self.0) - } -} diff --git a/src/hash/index.rs b/src/hash/index.rs new file mode 100644 index 0000000..1003c5e --- /dev/null +++ b/src/hash/index.rs @@ -0,0 +1,29 @@ +macro_rules! impl_index { + ($idx: ty, $struct: ident, $i: tt, Output = $output: ty, Params = [$($type:ident : $trait:ident),*], Constants = $($constgen:ident),*) => { + impl<$($type: $trait,)* $(const $constgen: usize,)*> core::ops::Index<$idx> for $struct<$($type,)* $($constgen,)*> { + type Output = $output; + + fn index(&self, index: $idx) -> &Self::Output { + &self.$i[index] + } + } + + impl<$($type: $trait,)* $(const $constgen: usize,)*> core::ops::IndexMut<$idx> for $struct<$($type,)* $($constgen,)*> { + + fn index_mut(&mut self, index: $idx) -> &mut Self::Output { + &mut self.$i[index] + } + } + }; +} + +macro_rules! impl_indexing { + ($struct: ident, $field: tt, Output = $output: ty, Params = [$($type:ident : $trait:ident),*], Constants = [$($constgen:ident),*]) => { + crate::hash::index::impl_index!(usize, $struct, $field, Output = $output, Params = [$($type : $trait),*], Constants = $($constgen),*); + crate::hash::index::impl_index!(core::ops::RangeTo, $struct, $field, Output = [$output], Params = [$($type : $trait),*], Constants = $($constgen),*); + crate::hash::index::impl_index!(core::ops::Range, $struct, $field, Output = [$output], Params = [$($type : $trait),*], Constants = $($constgen),*); + crate::hash::index::impl_index!(core::ops::RangeFrom, $struct, $field, Output = [$output], Params = [$($type : $trait),*], Constants = $($constgen),*); + } +} + +pub(crate) use {impl_index, impl_indexing}; diff --git a/src/hash/keccak.rs b/src/hash/keccak.rs index e8866f9..eab886f 100644 --- a/src/hash/keccak.rs +++ b/src/hash/keccak.rs @@ -2,10 +2,8 @@ //! Despite internally we use the same permutation, //! we build a duplex sponge in overwrite mode //! on the top of it using the `DuplexSponge` trait. -use core::ops::{Index, IndexMut, Range, RangeFrom, RangeTo}; -use zeroize::{Zeroize, ZeroizeOnDrop}; - use super::sponge::{DuplexSponge, Sponge}; +use zeroize::{Zeroize, ZeroizeOnDrop}; /// A duplex sponge based on the permutation [`keccak::f1600`] /// using [`DuplexSponge`]. @@ -44,58 +42,10 @@ impl Default for AlignedKeccakState { } } -impl Index for AlignedKeccakState { - type Output = u8; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for AlignedKeccakState { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Index> for AlignedKeccakState { - type Output = [u8]; - - fn index(&self, index: Range) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut> for AlignedKeccakState { - fn index_mut(&mut self, index: Range) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Index> for AlignedKeccakState { - type Output = [u8]; - - fn index(&self, index: RangeFrom) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut> for AlignedKeccakState { - fn index_mut(&mut self, index: RangeFrom) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Index> for AlignedKeccakState { - type Output = [u8]; - - fn index(&self, index: RangeTo) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut> for AlignedKeccakState { - fn index_mut(&mut self, index: RangeTo) -> &mut Self::Output { - &mut self.0[index] - } -} +super::index::impl_indexing!( + AlignedKeccakState, + 0, + Output = u8, + Params = [], + Constants = [] +); diff --git a/src/hash/mod.rs b/src/hash/mod.rs index d2d76fd..a9824f8 100644 --- a/src/hash/mod.rs +++ b/src/hash/mod.rs @@ -8,6 +8,8 @@ //! This is done using the standard duplex sponge cosntruction in overwrite mode (cf. [Wikipedia](https://en.wikipedia.org/wiki/Sponge_function#Duplex_construction)). //! - [`hash::legacy::DigestBridge`] takes as input any hash function implementing the NIST API via the standard [`digest::Digest`] trait and makes it suitable for usage in duplex mode for continuous absorb/squeeze. +/// Automate implementation of Index and IndexMut. +pub(crate) mod index; /// A wrapper around the Keccak-f\[1600\] permutation. pub mod keccak; /// Legacy hash functions support (e.g. [`sha2`](https://crates.io/crates/sha2), [`blake2`](https://crates.io/crates/blake2)). @@ -15,9 +17,6 @@ pub mod legacy; /// Sponge functions. pub mod sponge; -#[cfg(feature = "anemoi")] -pub mod anemoi; - // Re-export the supported hash functions. pub use keccak::Keccak; diff --git a/src/plugins/ark/anemoi.rs b/src/plugins/ark/anemoi.rs new file mode 100644 index 0000000..a398f84 --- /dev/null +++ b/src/plugins/ark/anemoi.rs @@ -0,0 +1,49 @@ +//! Work-in-progress (but working) implementation of the Anemoi hash function. +//! +//! The main reason for this code not being deployed is that [anemoi](https://anemoi-hash.github.io/)'s Rust implementation +//! is not published as a crate and thus `nimue` cannot publish it along with a new release. + +use ark_ff::Field; +use std::ops::{Index, IndexMut, Range, RangeFrom, RangeTo}; +use zeroize::Zeroize; + +use super::sponge::Sponge; + +#[derive(Clone, Zeroize)] +pub struct AnemoiState([F; N]); + +impl Default for AnemoiState { + fn default() -> Self { + Self([F::zero(); N]) + } +} + +crate::hash::index::impl_indexing!(AnemoiState, 0, Output = F, Params = [F: Field], Constants = [R, N]); + +pub type AnemoiBls12_381_2_1 = AnemoiState; +use anemoi::bls12_381::anemoi_2_1::AnemoiBls12_381_2_1 as _AnemoiBls12_381_2_1; +use anemoi::Anemoi; + +impl Sponge + for AnemoiState< + anemoi::bls12_381::Felt, + { _AnemoiBls12_381_2_1::RATE }, + { _AnemoiBls12_381_2_1::WIDTH }, + > +{ + type U = anemoi::bls12_381::Felt; + + const CAPACITY: usize = _AnemoiBls12_381_2_1::WIDTH - _AnemoiBls12_381_2_1::RATE; + + const RATE: usize = _AnemoiBls12_381_2_1::RATE; + + fn new(tag: [u8; 32]) -> Self { + let mut state = Self::default(); + state[0] = anemoi::bls12_381::Felt::from_le_bytes_mod_order(&tag); + state + } + + fn permute(&mut self) { + _AnemoiBls12_381_2_1::permutation(&mut self.0) + } +} diff --git a/src/plugins/ark/mod.rs b/src/plugins/ark/mod.rs index 770ecb1..bfdbb7f 100644 --- a/src/plugins/ark/mod.rs +++ b/src/plugins/ark/mod.rs @@ -5,6 +5,9 @@ mod writer; // poseidon support pub mod poseidon; +#[cfg(feature = "anemoi")] +pub mod anemoi; + pub use crate::traits::*; pub use crate::{hash::Unit, Arthur, DuplexHash, IOPattern, Merlin, ProofError, ProofResult, Safe}; diff --git a/src/plugins/ark/poseidon.rs b/src/plugins/ark/poseidon.rs index dce3c01..041d2df 100644 --- a/src/plugins/ark/poseidon.rs +++ b/src/plugins/ark/poseidon.rs @@ -1,10 +1,9 @@ use crate::{hash::sponge::DuplexSponge, Unit}; use ark_bls12_381::Fq; use ark_ff::{PrimeField, Zero}; -use std::ops::RangeTo; type FF = Fq; -pub type PoseidonHash = DuplexSponge>; +pub type PoseidonHash = DuplexSponge>; #[derive(Clone, Debug)] pub struct PoseidonConfig { @@ -89,83 +88,25 @@ impl Default for PoseidonSponge { } } -macro_rules! impl_index { - ($trait: ty, $struct: ident, Output = $output: ident, Params = [$($type:ident : $trait:ident),*], Constants = $($constgen:ident),*) => { - impl<$($type: $trait,)* $(const $constgen: usize,)*> $trait for $struct<$($type,)* $($constgen,)*> { - type Output = $output; +crate::hash::index::impl_indexing!(PoseidonSponge, state, Output = F, Params = [F: PrimeField], Constants = [RATE, CAPACITY]); - fn index(&self, index: usize) -> &Self::Output { - &self.state[index] - } - } - }; -} - -impl_index!(std::ops::Index, PoseidonSponge, Output = F, Params = [F: PrimeField], Constants = RATE, CAPACITY); - -impl std::ops::Index for PoseidonSponge { - type Output = F; - - fn index(&self, index: usize) -> &Self::Output { - &self.state[index] - } -} - - - -impl std::ops::Index> for PoseidonSponge { - type Output = [F]; - - fn index(&self, index: RangeTo) -> &Self::Output { - &self.state[index] - } -} - -impl std::ops::IndexMut> for PoseidonSponge { - fn index_mut(&mut self, index: RangeTo) -> &mut Self::Output { - &mut self.state[index] - } -} - -impl std::ops::Index> for PoseidonSponge { - type Output = [F]; - - fn index(&self, index: std::ops::Range) -> &Self::Output { - &self.state[index] - } -} - -impl std::ops::IndexMut> for PoseidonSponge { - fn index_mut(&mut self, index: std::ops::Range) -> &mut Self::Output { - &mut self.state[index] - } -} - -impl std::ops::Index> for PoseidonSponge { - type Output = [F]; - - fn index(&self, index: std::ops::RangeFrom) -> &Self::Output { - &self.state[index] - } -} - -impl std::ops::IndexMut> for PoseidonSponge { - fn index_mut(&mut self, index: std::ops::RangeFrom) -> &mut Self::Output { - &mut self.state[index] - } -} - -impl zeroize::Zeroize for PoseidonSponge { +impl zeroize::Zeroize + for PoseidonSponge +{ fn zeroize(&mut self) { self.state.zeroize(); } } -impl crate::hash::sponge::Sponge for PoseidonSponge - where PoseidonSponge: Default, F: Unit { +impl crate::hash::sponge::Sponge + for PoseidonSponge +where + PoseidonSponge: Default, + F: Unit, +{ type U = F; - const CAPACITY: usize = 1; - const RATE: usize = 2; + const CAPACITY: usize = CAPACITY; + const RATE: usize = RATE; fn new(iv: [u8; 32]) -> Self { assert!(Self::CAPACITY >= 1);