Skip to content

Commit a70ec1d

Browse files
authored
Poseidon optimization starknet (#855)
* Poseidon * Add docs * Clearer docs * Remove unneeded pub crate * Clippy * Revert clippy * Allow op ref * Fix wasm target * Fix wasm target * Fmt
1 parent 699c12d commit a70ec1d

File tree

4 files changed

+31
-18
lines changed

4 files changed

+31
-18
lines changed

crypto/src/hash/poseidon/mod.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ pub trait Poseidon: PermutationParameters + self::private::Sealed {
1818
fn hades_permutation(state: &mut [FE<Self::F>]);
1919
fn full_round(state: &mut [FE<Self::F>], round_number: usize);
2020
fn partial_round(state: &mut [FE<Self::F>], round_number: usize);
21-
fn mix(state: &mut [FE<Self::F>]);
2221
fn hash(x: &FE<Self::F>, y: &FE<Self::F>) -> FE<Self::F>;
2322
fn hash_single(x: &FE<Self::F>) -> FE<Self::F>;
2423
fn hash_many(inputs: &[FE<Self::F>]) -> FE<Self::F>;
@@ -56,21 +55,7 @@ impl<P: PermutationParameters> Poseidon for P {
5655

5756
state[P::STATE_SIZE - 1] = state[P::STATE_SIZE - 1].pow(P::ALPHA);
5857

59-
Self::mix(state);
60-
}
61-
62-
fn mix(state: &mut [FE<Self::F>]) {
63-
let mut new_state: Vec<FE<Self::F>> = Vec::with_capacity(P::STATE_SIZE);
64-
for i in 0..P::STATE_SIZE {
65-
let mut new_e = FE::zero();
66-
for (j, current_state) in state.iter().enumerate() {
67-
let mut mij = P::MDS_MATRIX[i * P::N_MDS_MATRIX_COLS + j].clone();
68-
mij *= current_state;
69-
new_e += mij;
70-
}
71-
new_state.push(new_e);
72-
}
73-
state.clone_from_slice(&new_state[0..P::STATE_SIZE]);
58+
P::mix(state);
7459
}
7560

7661
fn hash(x: &FE<Self::F>, y: &FE<Self::F>) -> FE<Self::F> {

crypto/src/hash/poseidon/parameters.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use alloc::vec::Vec;
12
use lambdaworks_math::field::{element::FieldElement as FE, traits::IsPrimeField};
23

34
/// Parameters for Poseidon
@@ -24,4 +25,21 @@ pub trait PermutationParameters {
2425
const ROUND_CONSTANTS: &'static [FE<Self::F>];
2526
const N_ROUND_CONSTANTS_ROWS: usize;
2627
const N_ROUND_CONSTANTS_COLS: usize;
28+
29+
/// This is the mix function that operates with the MDS matrix
30+
/// Round Constants are sometimes picked to simplify this function,
31+
/// so it can be redefined by each set of permutation parameters if a simplification can be made to make it faster. Notice in that case, MDS constants may not be used.
32+
fn mix(state: &mut [FE<Self::F>]) {
33+
let mut new_state: Vec<FE<Self::F>> = Vec::with_capacity(Self::STATE_SIZE);
34+
for i in 0..Self::STATE_SIZE {
35+
let mut new_e = FE::zero();
36+
for (j, current_state) in state.iter().enumerate() {
37+
let mut mij = Self::MDS_MATRIX[i * Self::N_MDS_MATRIX_COLS + j].clone();
38+
mij *= current_state;
39+
new_e += mij;
40+
}
41+
new_state.push(new_e);
42+
}
43+
state.clone_from_slice(&new_state[0..Self::STATE_SIZE]);
44+
}
2745
}

crypto/src/hash/poseidon/starknet/parameters.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@ impl PermutationParameters for PoseidonCairoStark252 {
1919
&PoseidonCairoStark252::ROUND_CONSTANTS;
2020
const N_ROUND_CONSTANTS_ROWS: usize = 91;
2121
const N_ROUND_CONSTANTS_COLS: usize = 3;
22+
23+
/// Redefined mix function for optimization purposes
24+
fn mix(state: &mut [FE<Self::F>]) {
25+
let t = &state[0] + &state[1] + &state[2];
26+
state[0] = &t + &state[0].double();
27+
state[1] = &t - &state[1].double();
28+
let minus_state_2 = -&state[2];
29+
state[2] = &t + &minus_state_2 + &minus_state_2 + &minus_state_2;
30+
}
2231
}
2332

2433
#[derive(Clone, Default)]
2534
pub struct PoseidonCairoStark252;
2635

2736
impl PoseidonCairoStark252 {
37+
/// Since the mix function was redefined, these constants are not used, but are still valid.
2838
const MDS_MATRIX: [FE<Stark252PrimeField>; 3 * 3] = [
2939
FE::from_hex_unchecked("3"),
3040
FE::from_hex_unchecked("1"),
@@ -41,7 +51,7 @@ impl PoseidonCairoStark252 {
4151
// And the round 0 ones matches the one used
4252
// in Cairo Lang
4353
// https://github.com/starkware-libs/cairo-lang/blob/c98fc0b50529185b7018208cb3460191eeb53e0d/src/starkware/cairo/stark_verifier/air/layouts/starknet/autogenerated.cairo#L1574-L1596
44-
const ROUND_CONSTANTS: [FE<Stark252PrimeField>; 3 * 91] = [
54+
pub const ROUND_CONSTANTS: [FE<Stark252PrimeField>; 3 * 91] = [
4555
FE::from_hex_unchecked("6861759ea556a2339dd92f9562a30b9e58e2ad98109ae4780b7fd8eac77fe6f"),
4656
FE::from_hex_unchecked("3827681995d5af9ffc8397a3d00425a3da43f76abf28a64e4ab1a22f27508c4"),
4757
FE::from_hex_unchecked("3a3956d2fad44d0e7f760a2277dc7cb2cac75dc279b2d687a0dbe17704a8309"),

crypto/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
#![allow(clippy::op_ref)]
12
#![cfg_attr(not(feature = "std"), no_std)]
2-
33
#[macro_use]
44
extern crate alloc;
55

0 commit comments

Comments
 (0)