poseidon_parameters/
arc_matrix.rs

1use crate::{error::PoseidonParameterError, matrix::Matrix, matrix_ops::MatrixOperations};
2use decaf377::Fq;
3
4/// Represents an matrix of round constants.
5///
6/// Arc stands for `AddRoundConstant` which is the
7/// step in the permutation where this matrix is used.
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct ArcMatrix<const N_ROWS: usize, const N_COLS: usize, const N_ELEMENTS: usize>(
10    pub Matrix<N_ROWS, N_COLS, N_ELEMENTS>,
11);
12
13impl<const N_ROWS: usize, const N_COLS: usize, const N_ELEMENTS: usize>
14    ArcMatrix<N_ROWS, N_COLS, N_ELEMENTS>
15{
16    pub fn transpose(&self) -> ArcMatrix<N_COLS, N_ROWS, N_ELEMENTS> {
17        ArcMatrix(self.0.transpose())
18    }
19
20    pub fn inner_elements(&self) -> [Fq; N_ELEMENTS] {
21        self.0.elements
22    }
23
24    /// Create a new matrix from a slice of elements.
25    pub const fn new_from_known(elements: [Fq; N_ELEMENTS]) -> Self {
26        Self(Matrix::new_from_known(elements))
27    }
28}
29
30impl<const N_ROWS: usize, const N_COLS: usize, const N_ELEMENTS: usize> MatrixOperations
31    for ArcMatrix<N_ROWS, N_COLS, N_ELEMENTS>
32{
33    fn new(elements: &[Fq]) -> Self {
34        Self(Matrix::new(elements))
35    }
36
37    fn elements(&self) -> &[Fq] {
38        self.0.elements()
39    }
40
41    fn get_element(&self, i: usize, j: usize) -> Fq {
42        self.0.get_element(i, j)
43    }
44
45    fn set_element(&mut self, i: usize, j: usize, val: Fq) {
46        self.0.set_element(i, j, val)
47    }
48
49    fn n_rows(&self) -> usize {
50        self.0.n_rows()
51    }
52
53    fn n_cols(&self) -> usize {
54        self.0.n_cols()
55    }
56
57    fn hadamard_product(&self, rhs: &Self) -> Result<Self, PoseidonParameterError>
58    where
59        Self: Sized,
60    {
61        Ok(Self(self.0.hadamard_product(&rhs.0)?))
62    }
63}
64
65/// Represents an optimized matrix of round constants.
66///
67/// This modifies the partial rounds in the middle of the permutation,
68/// wherein you add constants _first_ before iterating through the partial
69/// rounds.
70///
71/// This method follows `calc_equivalent_constants` from Appendix B's
72/// `poseidonperm_x3_64_24_optimized.sage`.
73#[derive(Clone, Debug, PartialEq, Eq)]
74pub struct OptimizedArcMatrix<const N_ROWS: usize, const N_COLS: usize, const N_ELEMENTS: usize>(
75    pub ArcMatrix<N_ROWS, N_COLS, N_ELEMENTS>,
76);
77
78impl<const N_ROWS: usize, const N_COLS: usize, const N_ELEMENTS: usize>
79    OptimizedArcMatrix<N_ROWS, N_COLS, N_ELEMENTS>
80{
81    pub fn transpose(&self) -> OptimizedArcMatrix<N_COLS, N_ROWS, N_ELEMENTS> {
82        OptimizedArcMatrix(self.0.transpose())
83    }
84
85    /// Create a new matrix from a slice of elements.
86    pub const fn new_from_known(elements: [Fq; N_ELEMENTS]) -> Self {
87        Self(ArcMatrix::new_from_known(elements))
88    }
89}
90
91impl<const N_ROWS: usize, const N_COLS: usize, const N_ELEMENTS: usize> MatrixOperations
92    for OptimizedArcMatrix<N_ROWS, N_COLS, N_ELEMENTS>
93{
94    /// Create a `OptimizedArcMatrix` from its elements.
95    fn new(elements: &[Fq]) -> Self {
96        Self(ArcMatrix::new(elements))
97    }
98
99    fn elements(&self) -> &[Fq] {
100        self.0.elements()
101    }
102
103    fn get_element(&self, i: usize, j: usize) -> Fq {
104        self.0.get_element(i, j)
105    }
106
107    fn set_element(&mut self, i: usize, j: usize, val: Fq) {
108        self.0.set_element(i, j, val)
109    }
110
111    fn n_rows(&self) -> usize {
112        self.0.n_rows()
113    }
114
115    fn n_cols(&self) -> usize {
116        self.0.n_cols()
117    }
118
119    fn hadamard_product(&self, rhs: &Self) -> Result<Self, PoseidonParameterError>
120    where
121        Self: Sized,
122    {
123        Ok(Self(self.0.hadamard_product(&rhs.0)?))
124    }
125}