From 5ac46aa6ca18340c010c3652ba000c3c647b85f0 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Thu, 12 Jan 2023 11:53:12 +0000 Subject: [PATCH 1/5] anemoi: removed duplicate gadgets for the flystel Q-functions for prime and binary fields (https://github.com/clearmatics/libsnark/issues/77, https://github.com/clearmatics/libsnark/pull/65#discussion_r992421012, https://github.com/clearmatics/libsnark/pull/65#discussion_r992423162) - resolved conflicts after rebase onto anemoi-hash-r1cs --- libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc | 1 - 1 file changed, 1 deletion(-) diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc index e5fccc268..bead5d78c 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc @@ -90,7 +90,6 @@ void flystel_Q_prime_field_gadget::generate_r1cs_witness() // // where A0=(0, beta, 0, 0), B0=(0, 1, 0, 0), C0=(0, 0, 1, 0) and // A1=(0, 0, 1, 0), B1=(0, 1, 0, 0), C1=(-gamma, 0, 0, 1) - template flystel_Q_binary_field_gadget::flystel_Q_binary_field_gadget( protoboard> &pb, From 3592255d03e037167d88d90b81724522f70281ee Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Mon, 16 Jan 2023 11:29:56 +0000 Subject: [PATCH 2/5] anemoi: implemented function for generating the mds matrix for different number of columns using class specialization (https://github.com/clearmatics/libsnark/pull/102#discussion_r1069518363) --- .../hashes/anemoi/anemoi_components.hpp | 29 ++++++-- .../hashes/anemoi/anemoi_components.tcc | 67 ++++++++++--------- .../anemoi/tests/test_anemoi_gadget.cpp | 38 +++++++++++ 3 files changed, 96 insertions(+), 38 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp index d5dc85779..101814fe0 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp @@ -183,11 +183,6 @@ class flystel_prime_field_gadget : public gadget> void generate_r1cs_witness(); }; -// get the MDS matrix from the number of columns 2,3 or 4 -template -std::array, NumStateColumns_L> -anemoi_permutation_mds(const FieldT g); - /// One round of the Anemoi permutation mapping (Fr)^{2L} -> (Fr)^{2L} /// /// NumStateColumns_L : L parameter - number of columns in the @@ -241,6 +236,30 @@ class anemoi_permutation_round_prime_field_gadget void generate_r1cs_witness(); }; +// MDS matrix for each allowed dimension: 2,3 or 4 +template class anemoi_permutation_mds; + +template class anemoi_permutation_mds +{ +public: + static std::array, 2>, 2> permutation_mds( + const libff::Fr g); +}; + +template class anemoi_permutation_mds +{ +public: + static std::array, 3>, 3> permutation_mds( + const libff::Fr g); +}; + +template class anemoi_permutation_mds +{ +public: + static std::array, 4>, 4> permutation_mds( + const libff::Fr g); +}; + } // namespace libsnark #include "libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc" diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc index bead5d78c..028006bbe 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc @@ -320,37 +320,6 @@ void flystel_prime_field_gadget::generate_r1cs_witness() this->pb.lc_val(output_y1) = input_x1_value - this->pb.val(a1); } -template -std::vector>> anemoi_permutation_mds( - const libff::Fr g) -{ - static_assert( - (NumStateColumns_L == 1) || (NumStateColumns_L == 2) || - (NumStateColumns_L == 3) || (NumStateColumns_L == 4), - "NumStateColumns_L must be 2,3 or 4"); - - const libff::Fr g2 = g * g; - - // allocate matrix M of dimension LxL - std::vector>> M; - M.resize(NumStateColumns_L, std::vector>(NumStateColumns_L)); - - if (NumStateColumns_L == 2) { - M = {{1, g}, {g, g2 + 1}}; - } - if (NumStateColumns_L == 3) { - M = {{g + 1, 1, g + 1}, {1, 1, g}, {g, 1, 1}}; - } - if (NumStateColumns_L == 4) { - M = { - {1, g + 1, g, g}, - {g2, g + g2, g + 1, g + g + 1}, - {g2, g2, 1, g + 1}, - {g + 1, g + g + 1, g, g + 1}}; - } - return M; -} - // Fast matrix-vector multiplication algorithm for Anemoi MDS layer with \ell = // 1,2 for inputs of type "linear combination of FieldT elements" template @@ -532,11 +501,11 @@ anemoi_permutation_round_prime_field_gadget< } if (ncols > 1) { - M_matrix = anemoi_permutation_mds(g); + M_matrix = anemoi_permutation_mds::permutation_mds(g); } else { // ncols == 1 // the MDS matrix for a state with 1 column (L=1) is the same as // for a state with 2 columns (L=2) - M_matrix = anemoi_permutation_mds(g); + M_matrix = anemoi_permutation_mds::permutation_mds(g); } // multiply by matrix M @@ -613,6 +582,38 @@ void anemoi_permutation_round_prime_field_gadget< } } +template +std::array, 2>, 2> anemoi_permutation_mds:: + permutation_mds(const libff::Fr g) +{ + using FieldT = libff::Fr; + const FieldT g2 = g * g; + anemoi_mds_matrix_t M = {{{1, g}, {g, g2 + 1}}}; + return M; +} + +template +std::array, 3>, 3> anemoi_permutation_mds:: + permutation_mds(const libff::Fr g) +{ + anemoi_mds_matrix_t M = {{{g + 1, 1, g + 1}, {1, 1, g}, {g, 1, 1}}}; + return M; +} + +template +std::array, 4>, 4> anemoi_permutation_mds:: + permutation_mds(const libff::Fr g) +{ + using FieldT = libff::Fr; + const FieldT g2 = g * g; + anemoi_mds_matrix_t M = { + {{1, g + 1, g, g}, + {g2, g + g2, g + 1, g + g + 1}, + {g2, g2, 1, g + 1}, + {g + 1, g + g + 1, g, g + 1}}}; + return M; +} + } // namespace libsnark #endif // LIBSNARK_GADGETLIB1_GADGETS_HASHES_ANEMOI_COMPONENTS_TCC_ diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp b/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp index 58a4378e1..40abb3331 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp @@ -301,6 +301,43 @@ void test_anemoi_permutation_round_prime_field_gadget() "anemoi_permutation_round_prime_field_gadget tests successful"); } +template>> +void test_anemoi_permutation_mds() +{ + // anemoi_permutation_mds::permutation_mds() + using FieldT = libff::Fr; + const FieldT g = anemoi_parameters::multiplicative_generator_g; + // NumStateColumnsL == 2 + { + const size_t NumStateColumnsL = 2; + std::array, NumStateColumnsL> + M_expect = {{{1, 7}, {7, 50}}}; + std::array, NumStateColumnsL> M = + anemoi_permutation_mds::permutation_mds(g); + ASSERT_EQ(M, M_expect); + } + // NumStateColumnsL == 3 + { + const size_t NumStateColumnsL = 3; + std::array, NumStateColumnsL> + M_expect = {{{8, 1, 8}, {1, 1, 7}, {7, 1, 1}}}; + std::array, NumStateColumnsL> M = + anemoi_permutation_mds::permutation_mds(g); + ASSERT_EQ(M, M_expect); + } + // NumStateColumnsL == 4 + { + const size_t NumStateColumnsL = 4; + std::array, NumStateColumnsL> + M_expect = { + {{1, 8, 7, 7}, {49, 56, 8, 15}, {49, 49, 1, 8}, {8, 15, 7, 8}}}; + std::array, NumStateColumnsL> M = + anemoi_permutation_mds::permutation_mds(g); + ASSERT_EQ(M, M_expect); + } + libff::print_time("anemoi_permutation_mds tests successful"); +} + template void test_for_curve() { // Execute all tests for the given curve. @@ -319,6 +356,7 @@ template void test_for_curve() test_anemoi_permutation_round_prime_field_gadget(); test_anemoi_permutation_round_prime_field_gadget(); test_anemoi_permutation_round_prime_field_gadget(); + test_anemoi_permutation_mds(); } TEST(TestAnemoiGadget, BLS12_381) { test_for_curve(); } From c84efa46ddb84535236cd1480b1bc6ecfae469e0 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 17 Jan 2023 09:20:09 +0000 Subject: [PATCH 3/5] anemoi: added a TODO note regarding the removal of the input g parameter from all anemoi_permutation_mds::permutation_mds functions (https://github.com/clearmatics/libsnark/pull/102#discussion_r1071444422) --- .../gadgets/hashes/anemoi/anemoi_components.tcc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc index 028006bbe..fe70f97a5 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc @@ -582,6 +582,20 @@ void anemoi_permutation_round_prime_field_gadget< } } +// TODO: consdier applying the following changes to all +// anemoi_permutation_mds::permutation_mds functions in order to +// remove the input g parameter: +// +// - extract the ppT part from the anemoi_parameters class +// +// - use the ppT part from the anemoi_parameters class to implicitly +// get the value of g as +// anemoi_parameters::multiplicative_generator_g; +// +// - remove the input parameter const libff::Fr g from all +// permutation_mds functions and extract g as above +// +// see: https://github.com/clearmatics/libsnark/pull/102#discussion_r1071444422 template std::array, 2>, 2> anemoi_permutation_mds:: permutation_mds(const libff::Fr g) From 85bb95334f5d39bfe4e760b1fe98ce3abb5f24b7 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 17 Jan 2023 12:57:16 +0000 Subject: [PATCH 4/5] anemoi: defined the types of the mds matrices (https://github.com/clearmatics/libsnark/pull/102#discussion_r1071214317) --- .../gadgets/hashes/anemoi/anemoi_components.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp index 101814fe0..ce9bf36b1 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp @@ -241,23 +241,26 @@ template class anemoi_permutation_mds; template class anemoi_permutation_mds { + using anemoi_mds_matrix_t = std::array, 2>, 2>; + public: - static std::array, 2>, 2> permutation_mds( - const libff::Fr g); + static anemoi_mds_matrix_t permutation_mds(const libff::Fr g); }; template class anemoi_permutation_mds { + using anemoi_mds_matrix_t = std::array, 3>, 3>; + public: - static std::array, 3>, 3> permutation_mds( - const libff::Fr g); + static anemoi_mds_matrix_t permutation_mds(const libff::Fr g); }; template class anemoi_permutation_mds { + using anemoi_mds_matrix_t = std::array, 4>, 4>; + public: - static std::array, 4>, 4> permutation_mds( - const libff::Fr g); + static anemoi_mds_matrix_t permutation_mds(const libff::Fr g); }; } // namespace libsnark From 2c62e4d8732fb8b8dfc740f13789fd609a831826 Mon Sep 17 00:00:00 2001 From: Vesselin Velichkov Date: Tue, 17 Jan 2023 22:22:30 +0000 Subject: [PATCH 5/5] anemoi: fixed compilation errors related to method anemoi_permutation_mds::permutation_mds after rebase onto anemoi-hash-r1cs --- .../hashes/anemoi/anemoi_components.tcc | 57 +++++++++++++++++-- .../anemoi/tests/test_anemoi_gadget.cpp | 1 + 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc index fe70f97a5..a317134cf 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc @@ -500,12 +500,57 @@ anemoi_permutation_round_prime_field_gadget< Z_right.push_back(X_right[i] + D[i]); } - if (ncols > 1) { - M_matrix = anemoi_permutation_mds::permutation_mds(g); - } else { // ncols == 1 - // the MDS matrix for a state with 1 column (L=1) is the same as - // for a state with 2 columns (L=2) - M_matrix = anemoi_permutation_mds::permutation_mds(g); + // Note 1: the sequence of if-s over ncols \in {1,2,3,4} that + // follows is due to the fact that the specialized class + // anemoi_permutation_mds only accepts const size_t n = + // , but it would not accept const size_t = + // NumStateColumns_L. TODO: fix using a more efficient approach. + + // Note 2: the for-loop within each if(ncols == ), copies + // the 2d array returned by anemoi_permutation_mds::permutation_mds(g) into a 2d vector which is the type of + // the class member M_matrix. TODO: fix this by either using a + // more efficient approach or changing the type of M_matrix to be + // of type 2d array. + + // Note 3: for matrix-vector multiplication we currently provide + // fast routines for dimensions NumStateColumns_L \in {2,3,4} that + // only accept g and a vector as input (the + // anemoi_fast_multiply_mds_* functions). Therefore the class + // member M_matrix is not used at the moment. It is included for + // future use for 2 foreseeable scenarios: 1) an instance of + // Anemoi with NumStateColumns_L > 4 for which we do not have a + // fast multiplication routine and 2) keep the possibility to + // still use normal matrix-vector multiplication if one wants to + + // the MDS matrix for a state with 1 column (L=1) is the same as + // for a state with 2 columns (L=2) + if ((ncols == 1) || (ncols == 2)) { + const size_t n = 2; + std::array, n> M = + anemoi_permutation_mds::permutation_mds(g); + for (size_t i = 0; i < n; ++i) { + std::vector v(std::begin(M[i]), std::end(M[i])); + M_matrix.push_back(v); + } + } + if (ncols == 3) { + const size_t n = 3; + std::array, n> M = + anemoi_permutation_mds::permutation_mds(g); + for (size_t i = 0; i < n; ++i) { + std::vector v(std::begin(M[i]), std::end(M[i])); + M_matrix.push_back(v); + } + } + if (ncols == 4) { + const size_t n = 4; + std::array, n> M = + anemoi_permutation_mds::permutation_mds(g); + for (size_t i = 0; i < n; ++i) { + std::vector v(std::begin(M[i]), std::end(M[i])); + M_matrix.push_back(v); + } } // multiply by matrix M diff --git a/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp b/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp index 40abb3331..5bae89888 100644 --- a/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp +++ b/libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp @@ -8,6 +8,7 @@ #include "libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/anemoi_outputs.hpp" +#include #include #include #include