Skip to content

Commit

Permalink
anemoi: implemented gadget for the full anemoi permutation (WIP) (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vesselin Velichkov committed Feb 3, 2023
1 parent 1b96808 commit a48ffe6
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 2 deletions.
42 changes: 42 additions & 0 deletions libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,48 @@ template<typename ppT> class anemoi_permutation_mds<ppT, 4>
static anemoi_mds_matrix_t permutation_mds(const libff::Fr<ppT> g);
};

/// Full Anemoi permutation mapping (Fr)^{2L} -> (Fr)^{2L}
/// see anemoi_permutation_round_prime_field_gadget
template<
typename ppT,
size_t NumStateColumns_L,
class parameters = anemoi_parameters<libff::Fr<ppT>>>
class anemoi_permutation_prime_field_gadget : public gadget<libff::Fr<ppT>>
{
using FieldT = libff::Fr<ppT>;

private:
// C round constants for all rounds
std::vector<std::vector<FieldT>> C_const_vec;
// D round constants for all rounds
std::vector<std::vector<FieldT>> D_const_vec;
// vector of round gadgets
std::vector<anemoi_permutation_round_prime_field_gadget<
ppT,
NumStateColumns_L,
parameters>>
Round;

public:
const pb_linear_combination_array<FieldT> X_left_input;
const pb_linear_combination_array<FieldT> X_right_input;
const pb_variable_array<FieldT> Y_left_output;
const pb_variable_array<FieldT> Y_right_output;

anemoi_permutation_prime_field_gadget(
protoboard<FieldT> &pb,
const std::vector<std::vector<FieldT>> &C_const,
const std::vector<std::vector<FieldT>> &D_const,
const pb_linear_combination_array<FieldT> &X_left_input,
const pb_linear_combination_array<FieldT> &X_right_input,
const pb_variable_array<FieldT> &Y_left_output,
const pb_variable_array<FieldT> &Y_right_output,
const std::string &annotation_prefix);

void generate_r1cs_constraints();
void generate_r1cs_witness();
};

} // namespace libsnark

#include "libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc"
Expand Down
41 changes: 41 additions & 0 deletions libsnark/gadgetlib1/gadgets/hashes/anemoi/anemoi_components.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,47 @@ std::array<std::array<libff::Fr<ppT>, 4>, 4> anemoi_permutation_mds<ppT, 4>::
return M;
}

template<typename ppT, size_t NumStateColumns_L, class parameters>
anemoi_permutation_prime_field_gadget<ppT, NumStateColumns_L, parameters>::
anemoi_permutation_prime_field_gadget(
protoboard<libff::Fr<ppT>> &pb,
const std::vector<std::vector<FieldT>> &C,
const std::vector<std::vector<FieldT>> &D,
const pb_linear_combination_array<FieldT> &X_left,
const pb_linear_combination_array<FieldT> &X_right,
const pb_variable_array<FieldT> &Y_left,
const pb_variable_array<FieldT> &Y_right,
const std::string &annotation_prefix)
: gadget<libff::Fr<ppT>>(pb, annotation_prefix)
, C_const_vec(C)
, D_const_vec(D)
, X_left_input(X_left)
, X_right_input(X_right)
, Y_left_output(Y_left)
, Y_right_output(Y_right)
{
// Number of columns can not be larger than rounds128 size
assert(NumStateColumns_L <= parameters::nrounds128.size());
// Number of columns can not be larger than rounds256 size
assert(NumStateColumns_L <= parameters::nrounds256.size());

// TBD
}

template<typename ppT, size_t NumStateColumns_L, class parameters>
void anemoi_permutation_prime_field_gadget<ppT, NumStateColumns_L, parameters>::
generate_r1cs_constraints()
{
// TBD
}

template<typename ppT, size_t NumStateColumns_L, class parameters>
void anemoi_permutation_prime_field_gadget<ppT, NumStateColumns_L, parameters>::
generate_r1cs_witness()
{
// TBD
}

} // namespace libsnark

#endif // LIBSNARK_GADGETLIB1_GADGETS_HASHES_ANEMOI_COMPONENTS_TCC_
60 changes: 60 additions & 0 deletions libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/anemoi_outputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,64 @@ std::vector<libff::Fr<libff::bls12_381_pp>> anemoi_expected_output_one_round(
return Y_expect_one_round;
}

std::vector<libff::Fr<libff::bls12_381_pp>> anemoi_expected_output(
const size_t &NumStateColumns_L)
{
std::vector<libff::Fr<libff::bls12_381_pp>> Y_expect;

assert(
((NumStateColumns_L == 1) || (NumStateColumns_L == 2) ||
(NumStateColumns_L == 3) || (NumStateColumns_L == 4)));

// Expected output for X rounds, L=1: Y_left || Y_right
if (NumStateColumns_L == 1) {
// TBD
Y_expect = {
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
};
}

// Expected output for X rounds, L=2: Y_left || Y_right
if (NumStateColumns_L == 2) {
// TBD
Y_expect = {
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
};
}

// Expected output for X rounds, L=3: Y_left || Y_right
if (NumStateColumns_L == 3) {
// TBD
Y_expect = {
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
};
}

// Expected output for X rounds, L=4: Y_left || Y_right
if (NumStateColumns_L == 4) {
// TBD
Y_expect = {
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
libff::Fr<libff::bls12_381_pp>("0"),
};
}

return Y_expect;
}

} // namespace libsnark
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ template<typename ppT>
using expected_round_values_fn_t =
std::function<std::vector<libff::Fr<ppT>>(const size_t)>;

// Returns the expected outputs from the full Anemoi permutation for
// BLS12_381
std::vector<libff::Fr<libff::bls12_381_pp>> anemoi_expected_output(
const size_t &NumStateColumns_L);

template<typename ppT>
using expected_values_fn_t =
std::function<std::vector<libff::Fr<ppT>>(const size_t)>;

} // namespace libsnark

#endif // LIBSNARK_GADGETLIB1_GADGETS_HASHES_ANEMOI_TESTS_ANEMOI_OUTPUTS_HPP_
114 changes: 112 additions & 2 deletions libsnark/gadgetlib1/gadgets/hashes/anemoi/tests/test_anemoi_gadget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,102 @@ void test_anemoi_permutation_round_prime_field_gadget(
"anemoi_permutation_round_prime_field_gadget tests successful");
}

template<
typename ppT,
size_t NumStateColumns_L,
class parameters = anemoi_parameters<libff::Fr<ppT>>>
void test_anemoi_permutation_prime_field_gadget(
expected_values_fn_t<ppT> expected_values_fn)

{
using FieldT = libff::Fr<ppT>;

protoboard<FieldT> pb;
std::vector<std::vector<FieldT>> C;
std::vector<std::vector<FieldT>> D;

pb_variable_array<FieldT> X_left;
pb_variable_array<FieldT> X_right;
pb_variable_array<FieldT> Y_left;
pb_variable_array<FieldT> Y_right;

X_left.allocate(pb, NumStateColumns_L, "left inputs");
X_right.allocate(pb, NumStateColumns_L, "right inputs");

Y_left.allocate(pb, NumStateColumns_L, "left outputs");
Y_right.allocate(pb, NumStateColumns_L, "right outputs");

assert(NumStateColumns_L <= parameters::nrounds256.size());
assert(NumStateColumns_L <= parameters::nrounds128.size());

// the number of rounds depends on the number of columns in the
// state
size_t nrounds = parameters::nrounds256[NumStateColumns_L - 1];

// Store C,D round constants from parameters class
for (size_t iround = 0; iround < nrounds; iround++) {
// C,D constants for one round
std::vector<FieldT> C_iround;
std::vector<FieldT> D_iround;
for (size_t icol = 0; icol < NumStateColumns_L; icol++) {
if (NumStateColumns_L == 1) {
C_iround.push_back(
parameters::C_constants_col_one[iround][icol]);
D_iround.push_back(
parameters::D_constants_col_one[iround][icol]);
}
if (NumStateColumns_L == 2) {
C_iround.push_back(
parameters::C_constants_col_two[iround][icol]);
D_iround.push_back(
parameters::D_constants_col_two[iround][icol]);
}
if (NumStateColumns_L == 3) {
C_iround.push_back(
parameters::C_constants_col_three[iround][icol]);
D_iround.push_back(
parameters::D_constants_col_three[iround][icol]);
}
if (NumStateColumns_L == 4) {
C_iround.push_back(
parameters::C_constants_col_four[iround][icol]);
D_iround.push_back(
parameters::D_constants_col_four[iround][icol]);
}
}
C.push_back(C_iround);
D.push_back(D_iround);
}

anemoi_permutation_prime_field_gadget<ppT, NumStateColumns_L, parameters> d(
pb, C, D, X_left, X_right, Y_left, Y_right, "anemoi permutation");

// generate constraints
d.generate_r1cs_constraints();

// Input values: X_left = 0,1,2...L-1 ; X_right = L, L+1, 2L-1
for (size_t i = 0; i < NumStateColumns_L; i++) {
pb.val(X_left[i]) = FieldT(i);
pb.val(X_right[i]) = FieldT(NumStateColumns_L + i);
}

// generate witness for the given input
d.generate_r1cs_witness();

if (expected_values_fn) {
// TBD
ASSERT_EQ(0, 0);
}

// TBD
#if 0
ASSERT_TRUE(pb.is_satisfied());
test_pb_verify_circuit<ppT>(pb);
#endif

libff::print_time("anemoi_permutation_prime_field_gadget tests successful");
}

void test_anemoi_permutation_mds_bls12_381()
{
using ppT = libff::bls12_381_pp;
Expand Down Expand Up @@ -365,10 +461,13 @@ void test_intermediate_gadgets_bls12_381()

template<typename ppT>
void test_for_curve(
expected_round_values_fn_t<ppT> expected_round_values_fn = 0)
expected_round_values_fn_t<ppT> expected_round_values_fn = 0,
expected_values_fn_t<ppT> expected_values_fn = 0)
{
// Use the original parameters for the full permutation
using parameters = anemoi_parameters<ppT>;

// Test single round
test_anemoi_permutation_round_prime_field_gadget<ppT, 1, parameters>(
expected_round_values_fn);
test_anemoi_permutation_round_prime_field_gadget<ppT, 2, parameters>(
Expand All @@ -377,13 +476,24 @@ void test_for_curve(
expected_round_values_fn);
test_anemoi_permutation_round_prime_field_gadget<ppT, 4, parameters>(
expected_round_values_fn);

// Test single round
test_anemoi_permutation_prime_field_gadget<ppT, 1, parameters>(
expected_values_fn);
test_anemoi_permutation_prime_field_gadget<ppT, 2, parameters>(
expected_values_fn);
test_anemoi_permutation_prime_field_gadget<ppT, 3, parameters>(
expected_values_fn);
test_anemoi_permutation_prime_field_gadget<ppT, 4, parameters>(
expected_values_fn);
}

TEST(TestAnemoiGadget, BLS12_381) { test_intermediate_gadgets_bls12_381(); }

TEST(TestForCurve, BLS12_381)
{
test_for_curve<libff::bls12_381_pp>(&anemoi_expected_output_one_round);
test_for_curve<libff::bls12_381_pp>(
&anemoi_expected_output_one_round, &anemoi_expected_output);
}

TEST(TestForCurve, BLS12_377)
Expand Down

0 comments on commit a48ffe6

Please sign in to comment.