From 6b0a303e48a09d06454a8a01e8047c2db27b92aa Mon Sep 17 00:00:00 2001 From: redshiftzero Date: Fri, 16 Jun 2023 15:43:15 -0400 Subject: [PATCH] poseidon2: external matrix --- poseidon-parameters/src/v2.rs | 2 + poseidon-paramgen/src/appendix_g.rs | 6 +- poseidon-paramgen/src/mds.rs | 2 +- poseidon-paramgen/src/poseidon_build.rs | 2 +- poseidon-paramgen/src/rounds.rs | 2 +- poseidon-paramgen/src/v2.rs | 40 +++-- poseidon-paramgen/src/v2/external.rs | 192 ++++++++++++++++++++++++ poseidon-paramgen/src/v2/internal.rs | 7 + 8 files changed, 233 insertions(+), 20 deletions(-) create mode 100644 poseidon-paramgen/src/v2/external.rs create mode 100644 poseidon-paramgen/src/v2/internal.rs diff --git a/poseidon-parameters/src/v2.rs b/poseidon-parameters/src/v2.rs index 931205e..0bbb8c5 100644 --- a/poseidon-parameters/src/v2.rs +++ b/poseidon-parameters/src/v2.rs @@ -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 { diff --git a/poseidon-paramgen/src/appendix_g.rs b/poseidon-paramgen/src/appendix_g.rs index 8d8de47..74f3c05 100644 --- a/poseidon-paramgen/src/appendix_g.rs +++ b/poseidon-paramgen/src/appendix_g.rs @@ -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)] diff --git a/poseidon-paramgen/src/mds.rs b/poseidon-paramgen/src/mds.rs index 066ef69..e5e82fa 100644 --- a/poseidon-paramgen/src/mds.rs +++ b/poseidon-paramgen/src/mds.rs @@ -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() { diff --git a/poseidon-paramgen/src/poseidon_build.rs b/poseidon-paramgen/src/poseidon_build.rs index dab96de..90485f6 100644 --- a/poseidon-paramgen/src/poseidon_build.rs +++ b/poseidon-paramgen/src/poseidon_build.rs @@ -53,7 +53,7 @@ use poseidon_parameters::v2::{Alpha, ArcMatrix, RoundNumbers, SquareMatrix, Matr struct DisplayableV2PoseidonParameters<'a, F: PrimeField>(&'a V2PoseidonParameters); impl 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!() } } diff --git a/poseidon-paramgen/src/rounds.rs b/poseidon-paramgen/src/rounds.rs index e59577f..8b71451 100644 --- a/poseidon-paramgen/src/rounds.rs +++ b/poseidon-paramgen/src/rounds.rs @@ -32,7 +32,7 @@ pub fn v1_generate(input: &InputParameters, alpha: &Alpha) -> choice.unwrap() } -pub fn v2_generate(input: &InputParameters, alpha: &Alpha) -> RoundNumbers { +pub fn v2_generate(_input: &InputParameters, _alpha: &Alpha) -> RoundNumbers { todo!() } diff --git a/poseidon-paramgen/src/v2.rs b/poseidon-paramgen/src/v2.rs index d4f5ad8..9b76109 100644 --- a/poseidon-paramgen/src/v2.rs +++ b/poseidon-paramgen/src/v2.rs @@ -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. @@ -24,16 +27,29 @@ pub fn generate( let alpha = alpha::generate::(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 = internal::generate(t); - PoseidonParameters:: { - 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:: { + 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:: { + M: input.M, + t: input.t, + alpha, + rounds, + arc, + m_e, + m_i, + } } } diff --git a/poseidon-paramgen/src/v2/external.rs b/poseidon-paramgen/src/v2/external.rs new file mode 100644 index 0000000..c301221 --- /dev/null +++ b/poseidon-paramgen/src/v2/external.rs @@ -0,0 +1,192 @@ +use ark_ff::PrimeField; +use poseidon_parameters::{ + v2::MatrixOperations, + v2::{SquareMatrix, SquareMatrixOperations}, +}; + +/// Generate external matrix +pub fn generate(t: usize) -> SquareMatrix { + 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::::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 = 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 = 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)); + } +} diff --git a/poseidon-paramgen/src/v2/internal.rs b/poseidon-paramgen/src/v2/internal.rs new file mode 100644 index 0000000..52cd770 --- /dev/null +++ b/poseidon-paramgen/src/v2/internal.rs @@ -0,0 +1,7 @@ +use ark_ff::PrimeField; +use poseidon_parameters::v2::SquareMatrix; + +/// Generate internal matrix +pub fn generate(_t: usize) -> SquareMatrix { + unimplemented!() +}