Skip to content

Commit

Permalink
Merge pull request #247 from dusk-network/mocello/246_constants
Browse files Browse the repository at this point in the history
Remove the hades-constants iterator and reduce the amount of constants to 335
  • Loading branch information
moCello authored Jan 31, 2024
2 parents 6d91b47 + de34dd9 commit 4a9697e
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 143 deletions.
24 changes: 19 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.34.0] - 2024-01-24

### Changed

- Restructure crate features [#184]
- Rename trait `hades::Strategy` to `hades::Permutation` [#243]
- Rename struct `hades::ScalarStrategy` to `hades::ScalarPermutation` [#243]
- Rename struct `hades::GadgetStrategy` to `hades::GadgetPermutaiton` [#243]
- Reduce the number of `ROUND_CONSTANTS` from 960 to 335 [#246]
- Remove the constants iterator in favor of indexing the constants array directly [#246]
- Change `ROUND_CONSTANTS` into a two-dimensional array [#246]
- Rename `TOTAL_FULL_ROUNDS` to `FULL_ROUNDS` [#246]

### Removed

- Remove `default` and `alloc` features [#184]
- Remove `hades::Strategy`, `hades::ScalarStrategy` and `hades::GadgetStrategy` from public API [#243]
- Remove `dusk-hades` dependency [#240]

### Added

- Add `zk` and `cipher` features [#184]
- Add the code for the hades permutation to crate [#240]
- Add internal `permute` and `permute_gadget` functions to `hades` module [#243]

## [0.34.0] - 2024-01-24

### Changed

- Restructure crate features [#184]

### Removed

- Remove `default` and `alloc` features [#184]

### Added

- Add `zk` and `cipher` features [#184]

## [0.33.0] - 2024-01-03

### Changed
Expand Down Expand Up @@ -436,6 +449,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Variants of sponge for `Scalar` & `Gadget(Variable/LC)`.

<!-- ISSUES -->
[#246]: https://github.com/dusk-network/poseidon252/issues/246
[#243]: https://github.com/dusk-network/poseidon252/issues/243
[#240]: https://github.com/dusk-network/poseidon252/issues/240
[#215]: https://github.com/dusk-network/poseidon252/issues/215
Expand Down
14 changes: 7 additions & 7 deletions assets/HOWTO.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@

# How to generate the assets

The `ark.bin` and `mds.bin` files in this folder are generated using the snippets below:
The `arc.bin` and `mds.bin` files in this folder are generated using the snippets below:

## Filename: ark.bin
## Generate round constants

```rust
use dusk_bls12_381::BlsScalar;
use sha2::{Digest, Sha512};
use std::fs;
use std::io::Write;

// The amount of constants generated, this needs to be the same number as in
// `dusk_poseidon::hades::CONSTANTS`.
const CONSTANTS: usize = 960;
// The amount of constants generated, this needs to be at least the total number
// of rounds (= 59 + 8) multiplied by the width of the permutaiton array (= 5).
const CONSTANTS: usize = (59 + 8) * 5;

fn constants() -> [BlsScalar; CONSTANTS] {
let mut cnst = [BlsScalar::zero(); CONSTANTS];
Expand All @@ -41,7 +41,7 @@ fn constants() -> [BlsScalar; CONSTANTS] {
}

fn write_constants() -> std::io::Result<()> {
let filename = "ark.bin";
let filename = "arc.bin";
let mut buf: Vec<u8> = vec![];

constants().iter().for_each(|c| {
Expand All @@ -56,7 +56,7 @@ fn write_constants() -> std::io::Result<()> {
}
```

## Filename: mds.bin
## Generate mds matrix

```rust
use dusk_bls12_381::BlsScalar;
Expand Down
Binary file added assets/arc.bin
Binary file not shown.
Binary file removed assets/ark.bin
Binary file not shown.
7 changes: 2 additions & 5 deletions src/hades.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
//! end, and each full round has `WIDTH` quintic S-Boxes.
//! - 59 partial rounds: each partial round has `WIDTH - 1` identity function
//! and one quintic S-Box.
//! - 960 round constants
//! - Round constants are generated using [this algorithm](https://extgit.iaik.tugraz.at/krypto/hadesmimc/blob/master/code/calc_round_numbers.py)
//! - 335 round constants which are generated using [this algorithm](https://extgit.iaik.tugraz.at/krypto/hadesmimc/blob/master/code/calc_round_numbers.py)
//! - The MDS matrix is a cauchy matrix, the method used to generate it, is
//! noted in section "Concrete Instantiations Poseidon and Starkad"
Expand All @@ -28,12 +27,10 @@ use mds_matrix::MDS_MATRIX;
use permutation::Permutation;
use round_constants::ROUND_CONSTANTS;

const TOTAL_FULL_ROUNDS: usize = 8;
const FULL_ROUNDS: usize = 8;

const PARTIAL_ROUNDS: usize = 59;

const CONSTANTS: usize = 960;

/// The amount of field elements that fit into the hades permutation container
pub const WIDTH: usize = 5;

Expand Down
109 changes: 44 additions & 65 deletions src/hades/permutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use dusk_bls12_381::BlsScalar;
#[cfg(feature = "zk")]
use dusk_plonk::prelude::{Composer, Witness};

use crate::hades::{PARTIAL_ROUNDS, ROUND_CONSTANTS, TOTAL_FULL_ROUNDS, WIDTH};
use crate::hades::{FULL_ROUNDS, PARTIAL_ROUNDS, WIDTH};

/// State for zero-knowledge plonk circuits
#[cfg(feature = "zk")]
Expand All @@ -35,11 +35,11 @@ use scalar::ScalarPermutation;
///
/// This permutation is a 3-step process that:
/// - Applies half of the `FULL_ROUNDS` (which can be understood as linear ops).
/// - Applies the `PARTIAL_ROUDS` (which can be understood as non-linear ops).
/// - Applies the `PARTIAL_ROUNDS` (which can be understood as non-linear ops).
/// - Applies the other half of the `FULL_ROUNDS`.
///
/// This structure allows to minimize the number of non-linear ops while
/// mantaining the security.
/// maintaining the security.
pub(crate) fn permute(state: &mut [BlsScalar; WIDTH]) {
let mut hades = ScalarPermutation::new();

Expand All @@ -50,11 +50,11 @@ pub(crate) fn permute(state: &mut [BlsScalar; WIDTH]) {
///
/// This permutation is a 3-step process that:
/// - Applies half of the `FULL_ROUNDS` (which can be understood as linear ops).
/// - Applies the `PARTIAL_ROUDS` (which can be understood as non-linear ops).
/// - Applies the `PARTIAL_ROUNDS` (which can be understood as non-linear ops).
/// - Applies the other half of the `FULL_ROUNDS`.
///
/// This structure allows to minimize the number of non-linear ops while
/// mantaining the security.
/// maintaining the security.
#[cfg(feature = "zk")]
pub(crate) fn permute_gadget(
composer: &mut Composer,
Expand All @@ -67,30 +67,19 @@ pub(crate) fn permute_gadget(

/// Defines the Hades252 permutation algorithm.
pub(crate) trait Permutation<T> {
/// Fetch the next round constant from an iterator
fn next_c<'b, I>(constants: &mut I) -> BlsScalar
where
I: Iterator<Item = &'b BlsScalar>,
{
constants
.next()
.copied()
.expect("Hades252 shouldn't be out of ARK constants")
}
/// Increment the inner rounds counter.
///
/// This counter is needed to index the `ROUND_CONSTANTS`.
fn increment_round(&mut self);

/// Add round keys to the state.
/// Add round constants to the state.
///
/// This round key addition, also known as `ARK`, is used to reach
/// This constants addition, also known as `ARC`, is used to reach
/// `Confusion and Diffusion` properties for the algorithm.
///
/// Basically it allows to destroy any connection between the inputs and the
/// outputs of the function.
fn add_round_key<'b, I>(
&mut self,
constants: &mut I,
state: &mut [T; WIDTH],
) where
I: Iterator<Item = &'b BlsScalar>;
fn add_round_constants(&mut self, state: &mut [T; WIDTH]);

/// Computes `input ^ 5 (mod p)`
///
Expand All @@ -100,94 +89,84 @@ pub(crate) trait Permutation<T> {
fn quintic_s_box(&mut self, value: &mut T);

/// Multiply the MDS matrix with the state.
fn mul_matrix<'b, I>(&mut self, constants: &mut I, state: &mut [T; WIDTH])
where
I: Iterator<Item = &'b BlsScalar>;
fn mul_matrix(&mut self, state: &mut [T; WIDTH]);

/// Applies a `Partial Round` also known as a `Partial S-Box layer` to a set
/// of inputs.
///
/// One partial round consists of 3 steps:
/// - ARK: Add round keys constants to each state element.
/// - Sub State: Apply `quintic S-Box` just to **the last element of the
/// - ARC: Add round constants to the elements of the state.
/// - Sub Words: Apply `quintic S-Box` just to **the last element of the
/// state** generated from the first step.
/// - Mix Layer: Multiplies the output state from the second step by the
/// `MDS_MATRIX`.
fn apply_partial_round<'b, I>(
&mut self,
constants: &mut I,
state: &mut [T; WIDTH],
) where
I: Iterator<Item = &'b BlsScalar>,
{
// Add round keys to each state element
self.add_round_key(constants, state);

// Then apply quintic s-box
fn apply_partial_round(&mut self, state: &mut [T; WIDTH]) {
// Increment the inner rounds counter
self.increment_round();

// Add round constants to each state element
self.add_round_constants(state);

// Then apply quintic s-box to the last element of the state
self.quintic_s_box(&mut state[WIDTH - 1]);

// Multiply this result by the MDS matrix
self.mul_matrix(constants, state);
self.mul_matrix(state);
}

/// Applies a `Full Round` also known as a `Full S-Box layer` to a set of
/// inputs.
///
/// One full round constists of 3 steps:
/// - ARK: Add round keys to each state element.
/// - Sub State: Apply `quintic S-Box` to **all of the state-elements**
/// One full round consists of 3 steps:
/// - ARC: Add round constants to the elements of the state.
/// - Sub Words: Apply `quintic S-Box` to **all of the state-elements**
/// generated from the first step.
/// - Mix Layer: Multiplies the output state from the second step by the
/// `MDS_MATRIX`.
fn apply_full_round<'a, I>(
&mut self,
constants: &mut I,
state: &mut [T; WIDTH],
) where
I: Iterator<Item = &'a BlsScalar>,
{
// Add round keys to each state element
self.add_round_key(constants, state);

// Then apply quintic s-box
fn apply_full_round(&mut self, state: &mut [T; WIDTH]) {
// Increment the inner rounds counter
self.increment_round();

// Add round constants to each state element
self.add_round_constants(state);

// Then apply quintic s-box to each element of the state
state.iter_mut().for_each(|w| self.quintic_s_box(w));

// Multiply this result by the MDS matrix
self.mul_matrix(constants, state);
self.mul_matrix(state);
}

/// Applies one Hades permutation.
///
/// This permutation is a 3-step process that:
/// - Applies half of the `FULL_ROUNDS` (which can be understood as linear
/// ops).
/// - Applies the `PARTIAL_ROUDS` (which can be understood as non-linear
/// - Applies the `PARTIAL_ROUNDS` (which can be understood as non-linear
/// ops).
/// - Applies the other half of the `FULL_ROUNDS`.
///
/// This structure allows to minimize the number of non-linear ops while
/// mantaining the security.
/// maintaining the security.
fn perm(&mut self, state: &mut [T; WIDTH]) {
let mut constants = ROUND_CONSTANTS.iter();

// Apply R_f full rounds
for _ in 0..TOTAL_FULL_ROUNDS / 2 {
self.apply_full_round(&mut constants, state);
for _ in 0..FULL_ROUNDS / 2 {
self.apply_full_round(state);
}

// Apply R_P partial rounds
for _ in 0..PARTIAL_ROUNDS {
self.apply_partial_round(&mut constants, state);
self.apply_partial_round(state);
}

// Apply R_f full rounds
for _ in 0..TOTAL_FULL_ROUNDS / 2 {
self.apply_full_round(&mut constants, state);
for _ in 0..FULL_ROUNDS / 2 {
self.apply_full_round(state);
}
}

/// Return the total rounds count
fn rounds() -> usize {
TOTAL_FULL_ROUNDS + PARTIAL_ROUNDS
FULL_ROUNDS + PARTIAL_ROUNDS
}
}
Loading

0 comments on commit 4a9697e

Please sign in to comment.