Skip to content

Commit

Permalink
poseidon2: external matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
redshiftzero committed Jun 20, 2023
1 parent 4900900 commit 9fcc086
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 20 deletions.
2 changes: 2 additions & 0 deletions poseidon-parameters/src/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub use crate::arc_matrix::ArcMatrix;
pub use crate::matrix::SquareMatrix;
pub use crate::round_numbers::RoundNumbers;

pub use crate::{matrix_ops::MatrixOperations, matrix_ops::SquareMatrixOperations};

/// A set of Poseidon2 parameters for a given set of input parameters.
#[derive(Clone, Debug)]
pub struct PoseidonParameters<F: PrimeField> {
Expand Down
6 changes: 1 addition & 5 deletions poseidon-paramgen/src/appendix_g.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ mod tests {
use num_bigint::BigUint;
use poseidon_parameters::v1::{Alpha, PoseidonParameters};

use crate::{
input::{self, InputParameters},
rounds,
v1::generate,
};
use crate::{input::InputParameters, rounds, v1::generate};

/// Represents a row in Table 7-9 in Appendix G of the paper.
#[allow(dead_code)]
Expand Down
2 changes: 1 addition & 1 deletion poseidon-paramgen/src/mds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ mod tests {
use poseidon_parameters::v1::Alpha;

use super::*;
use crate::{input, rounds};
use crate::rounds;

#[test]
fn convert_from_mds_to_vec_of_vecs() {
Expand Down
2 changes: 1 addition & 1 deletion poseidon-paramgen/src/poseidon_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use poseidon_parameters::v2::{Alpha, ArcMatrix, RoundNumbers, SquareMatrix, Matr

struct DisplayableV2PoseidonParameters<'a, F: PrimeField>(&'a V2PoseidonParameters<F>);
impl<F: PrimeField> Display for DisplayableV2PoseidonParameters<'_, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
Expand Down
2 changes: 1 addition & 1 deletion poseidon-paramgen/src/rounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn v1_generate<T: BigInteger>(input: &InputParameters<T>, alpha: &Alpha) ->
choice.unwrap()
}

pub fn v2_generate<T: BigInteger>(input: &InputParameters<T>, alpha: &Alpha) -> RoundNumbers {
pub fn v2_generate<T: BigInteger>(_input: &InputParameters<T>, _alpha: &Alpha) -> RoundNumbers {
todo!()
}

Expand Down
40 changes: 28 additions & 12 deletions poseidon-paramgen/src/v2.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use ark_ff::PrimeField;

mod external;
mod internal;

use crate::{alpha, input::InputParameters, round_constants, rounds};
use poseidon_parameters::v2::PoseidonParameters;
use poseidon_parameters::v2::{PoseidonParameters, SquareMatrix};

/// For generating parameters at build time.
pub mod poseidon_build {
pub use crate::poseidon_build::v2_compile as compile;
}

/// Generate a Poseidon instance mapped over Fp given a choice of:
/// Generate a Poseidon2 instance mapped over Fp given a choice of:
///
/// * M, the desired security level (in bits),
/// * t, the width of the desired hash function, e.g. $t=3$ corresponds to 2-to-1 hash.
Expand All @@ -24,16 +27,29 @@ pub fn generate<F: PrimeField>(
let alpha = alpha::generate::<F>(p, allow_inverse);
let rounds = rounds::v2_generate(&input, &alpha);
let arc = round_constants::v2_generate(&input, rounds, alpha);
let m_e = todo!();
let m_i = todo!();
let m_i: SquareMatrix<F> = internal::generate(t);

PoseidonParameters::<F> {
M: input.M,
t: input.t,
alpha,
rounds,
arc,
m_e,
m_i,
// We use the internal matrix also for the external rounds if t < 4.
if t < 4 {
PoseidonParameters::<F> {
M: input.M,
t: input.t,
alpha,
rounds,
arc,
m_i: m_i.clone(),
m_e: m_i,
}
} else {
let m_e = external::generate(t);
PoseidonParameters::<F> {
M: input.M,
t: input.t,
alpha,
rounds,
arc,
m_e,
m_i,
}
}
}
192 changes: 192 additions & 0 deletions poseidon-paramgen/src/v2/external.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use ark_ff::PrimeField;
use poseidon_parameters::{
v2::MatrixOperations,
v2::{SquareMatrix, SquareMatrixOperations},
};

/// Generate external matrix
pub fn generate<F: PrimeField>(t: usize) -> SquareMatrix<F> {
if t < 4 {
// For t=[2, 3], we don't need to generate an external matrix
// because we also use the internal matrix in the full rounds.
panic!("unexpected state size: should use internal matrix for t < 4")
} else if t % 4 != 0 {
// The internal matrix is only defined for t = 4t' where t' is an integer.
panic!("unexpected state size: internal matrix only defined for t % 4 != 0")
}

// For t>= 4, we use the following fixed matrix (Section 5.1, Poseidon2 paper).
let M4 = SquareMatrix::<F>::from_vec(vec![
F::from(5u64),
F::from(7u64),
F::one(),
F::from(3u64),
F::from(4u64),
F::from(6u64),
F::one(),
F::one(),
F::one(),
F::from(3u64),
F::from(5u64),
F::from(7u64),
F::one(),
F::one(),
F::from(4u64),
F::from(6u64),
]);

if t == 4 {
M4
} else {
let mut matrix = SquareMatrix::identity(t);
let d = t / 4;
for i in 0..d {
for j in 0..d {
if i == j {
for inner_row in 0..4 {
for inner_col in 0..4 {
matrix.set_element(
i * 4 + inner_row,
j * 4 + inner_col,
F::from(2u64) * M4.get_element(inner_row, inner_col),
)
}
}
} else {
for inner_row in 0..4 {
for inner_col in 0..4 {
matrix.set_element(
i * 4 + inner_row,
j * 4 + inner_col,
M4.get_element(inner_row, inner_col),
)
}
}
}
}
}
matrix
}
}

#[cfg(test)]
mod tests {
use ark_ed_on_bls12_377::Fq;

use super::*;

#[test]
fn external_matrix_t_equals_4() {
let matrix: SquareMatrix<Fq> = generate(4);
// If t=4, the matrix should simply be the fixed M4, unmodified.

// Row 0
assert_eq!(Fq::from(5u64), matrix.get_element(0, 0));
assert_eq!(Fq::from(7u64), matrix.get_element(0, 1));
assert_eq!(Fq::from(1u64), matrix.get_element(0, 2));
assert_eq!(Fq::from(3u64), matrix.get_element(0, 3));

// Row 1
assert_eq!(Fq::from(4u64), matrix.get_element(1, 0));
assert_eq!(Fq::from(6u64), matrix.get_element(1, 1));
assert_eq!(Fq::from(1u64), matrix.get_element(1, 2));
assert_eq!(Fq::from(1u64), matrix.get_element(1, 3));

// Row 2
assert_eq!(Fq::from(1u64), matrix.get_element(2, 0));
assert_eq!(Fq::from(3u64), matrix.get_element(2, 1));
assert_eq!(Fq::from(5u64), matrix.get_element(2, 2));
assert_eq!(Fq::from(7u64), matrix.get_element(2, 3));

// Row 3
assert_eq!(Fq::from(1u64), matrix.get_element(3, 0));
assert_eq!(Fq::from(1u64), matrix.get_element(3, 1));
assert_eq!(Fq::from(4u64), matrix.get_element(3, 2));
assert_eq!(Fq::from(6u64), matrix.get_element(3, 3));
}

#[test]
fn external_matrix_t_equals_8() {
let matrix: SquareMatrix<Fq> = generate(8);

// Row 0
assert_eq!(Fq::from(10u64), matrix.get_element(0, 0));
assert_eq!(Fq::from(14u64), matrix.get_element(0, 1));
assert_eq!(Fq::from(2u64), matrix.get_element(0, 2));
assert_eq!(Fq::from(6u64), matrix.get_element(0, 3));
assert_eq!(Fq::from(5u64), matrix.get_element(0, 4));
assert_eq!(Fq::from(7u64), matrix.get_element(0, 5));
assert_eq!(Fq::from(1u64), matrix.get_element(0, 6));
assert_eq!(Fq::from(3u64), matrix.get_element(0, 7));

// Row 1
assert_eq!(Fq::from(8u64), matrix.get_element(1, 0));
assert_eq!(Fq::from(12u64), matrix.get_element(1, 1));
assert_eq!(Fq::from(2u64), matrix.get_element(1, 2));
assert_eq!(Fq::from(2u64), matrix.get_element(1, 3));
assert_eq!(Fq::from(4u64), matrix.get_element(1, 4));
assert_eq!(Fq::from(6u64), matrix.get_element(1, 5));
assert_eq!(Fq::from(1u64), matrix.get_element(1, 6));
assert_eq!(Fq::from(1u64), matrix.get_element(1, 7));

// Row 2
assert_eq!(Fq::from(2u64), matrix.get_element(2, 0));
assert_eq!(Fq::from(6u64), matrix.get_element(2, 1));
assert_eq!(Fq::from(10u64), matrix.get_element(2, 2));
assert_eq!(Fq::from(14u64), matrix.get_element(2, 3));
assert_eq!(Fq::from(1u64), matrix.get_element(2, 4));
assert_eq!(Fq::from(3u64), matrix.get_element(2, 5));
assert_eq!(Fq::from(5u64), matrix.get_element(2, 6));
assert_eq!(Fq::from(7u64), matrix.get_element(2, 7));

// Row 3
assert_eq!(Fq::from(2u64), matrix.get_element(3, 0));
assert_eq!(Fq::from(2u64), matrix.get_element(3, 1));
assert_eq!(Fq::from(8u64), matrix.get_element(3, 2));
assert_eq!(Fq::from(12u64), matrix.get_element(3, 3));
assert_eq!(Fq::from(1u64), matrix.get_element(3, 4));
assert_eq!(Fq::from(1u64), matrix.get_element(3, 5));
assert_eq!(Fq::from(4u64), matrix.get_element(3, 6));
assert_eq!(Fq::from(6u64), matrix.get_element(3, 7));

// Row 4
assert_eq!(Fq::from(5u64), matrix.get_element(4, 0));
assert_eq!(Fq::from(7u64), matrix.get_element(4, 1));
assert_eq!(Fq::from(1u64), matrix.get_element(4, 2));
assert_eq!(Fq::from(3u64), matrix.get_element(4, 3));
assert_eq!(Fq::from(10u64), matrix.get_element(4, 4));
assert_eq!(Fq::from(14u64), matrix.get_element(4, 5));
assert_eq!(Fq::from(2u64), matrix.get_element(4, 6));
assert_eq!(Fq::from(6u64), matrix.get_element(4, 7));

// Row 5
assert_eq!(Fq::from(4u64), matrix.get_element(5, 0));
assert_eq!(Fq::from(6u64), matrix.get_element(5, 1));
assert_eq!(Fq::from(1u64), matrix.get_element(5, 2));
assert_eq!(Fq::from(1u64), matrix.get_element(5, 3));
assert_eq!(Fq::from(8u64), matrix.get_element(5, 4));
assert_eq!(Fq::from(12u64), matrix.get_element(5, 5));
assert_eq!(Fq::from(2u64), matrix.get_element(5, 6));
assert_eq!(Fq::from(2u64), matrix.get_element(5, 7));

// Row 6
assert_eq!(Fq::from(1u64), matrix.get_element(6, 0));
assert_eq!(Fq::from(3u64), matrix.get_element(6, 1));
assert_eq!(Fq::from(5u64), matrix.get_element(6, 2));
assert_eq!(Fq::from(7u64), matrix.get_element(6, 3));
assert_eq!(Fq::from(2u64), matrix.get_element(6, 4));
assert_eq!(Fq::from(6u64), matrix.get_element(6, 5));
assert_eq!(Fq::from(10u64), matrix.get_element(6, 6));
assert_eq!(Fq::from(14u64), matrix.get_element(6, 7));

// Row 7
assert_eq!(Fq::from(1u64), matrix.get_element(7, 0));
assert_eq!(Fq::from(1u64), matrix.get_element(7, 1));
assert_eq!(Fq::from(4u64), matrix.get_element(7, 2));
assert_eq!(Fq::from(6u64), matrix.get_element(7, 3));
assert_eq!(Fq::from(2u64), matrix.get_element(7, 4));
assert_eq!(Fq::from(2u64), matrix.get_element(7, 5));
assert_eq!(Fq::from(8u64), matrix.get_element(7, 6));
assert_eq!(Fq::from(12u64), matrix.get_element(7, 7));
}
}
7 changes: 7 additions & 0 deletions poseidon-paramgen/src/v2/internal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use ark_ff::PrimeField;
use poseidon_parameters::v2::SquareMatrix;

/// Generate internal matrix
pub fn generate<F: PrimeField>(_t: usize) -> SquareMatrix<F> {
unimplemented!()
}

0 comments on commit 9fcc086

Please sign in to comment.