Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new Poseidon2 relations #3406

Merged
merged 28 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e1c732d
initial commit
zac-williamson Oct 27, 2023
ea12f99
mmmmm constexpr
zac-williamson Oct 27, 2023
95e6572
wip
zac-williamson Oct 27, 2023
8c30828
basic poseidon hash working
zac-williamson Oct 27, 2023
86cf018
added tests + comments
zac-williamson Oct 30, 2023
6dd2511
comments
zac-williamson Oct 30, 2023
3dbd8df
removed string_view constructors
zac-williamson Oct 30, 2023
3631294
poseidon2 parameters now consistent with definition in paper
zac-williamson Oct 31, 2023
910b303
fixed bug where constructing uint from a string that is too big!
zac-williamson Oct 31, 2023
c7b4157
added cast to fix build error
lucasxia01 Nov 7, 2023
7bcee20
benchmarking file for native impl
lucasxia01 Nov 7, 2023
752bd14
Merge branch 'master' into zw/poseidon2
lucasxia01 Nov 7, 2023
7d0fe79
Merge branch 'master' into zw/poseidon2
lucasxia01 Nov 20, 2023
20a7eb2
Merge branch 'master' into zw/poseidon2
lucasxia01 Nov 22, 2023
f09ed91
external poseidon2 round relation
lucasxia01 Nov 20, 2023
d679581
added ARC and SBox rounds to external
lucasxia01 Nov 20, 2023
35ab7d9
created internal round relation
lucasxia01 Nov 20, 2023
5e94698
naming update
lucasxia01 Nov 22, 2023
14157c1
external relation consistency test
lucasxia01 Nov 22, 2023
e04037e
internal round consistency test
lucasxia01 Nov 22, 2023
6da3335
initial manual relation tests
lucasxia01 Nov 22, 2023
0c961b1
variable renaming
lucasxia01 Nov 24, 2023
8ef04db
added manual tests for internal
lucasxia01 Nov 24, 2023
b144cce
Merge branch 'master' into lx/poseidon2-relations
lucasxia01 Nov 28, 2023
80958c5
updated based on review
lucasxia01 Nov 30, 2023
a3c8eed
naming update
lucasxia01 Nov 30, 2023
52d260b
comment and scoping update
lucasxia01 Dec 1, 2023
a53e861
Merge branch 'master' into lx/poseidon2-relations
lucasxia01 Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
barretenberg_module(crypto_poseidon2 ecc numeric)
barretenberg_module(crypto_poseidon2 ecc numeric)
lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#pragma once
#include "barretenberg/relations/relation_types.hpp"
namespace proof_system {

template <typename FF_> class Poseidon2ExternalRelationImpl {
public:
using FF = FF_;

static constexpr std::array<size_t, 4> SUBRELATION_PARTIAL_LENGTHS{
7, // external poseidon2 round sub-relation for first value
7, // external poseidon2 round sub-relation for second value
7, // external poseidon2 round sub-relation for third value
7, // external poseidon2 round sub-relation for fourth value
};

/**
* @brief Expression for the poseidon2 external gate.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you please explain what exactly is being calculated here in terms of the notation of the paper? I say more about that below. I think the intent is the external round function of Section 6 of the paper, but I'm worried there's a discrepancy: looks like you're using $M_{\mathcal{E}} = M_4$, but to my eyes it looks like there might be a missing 2, ie should we have $M_{\mathcal{E}} = 2M_4$? I didn't do a thorough read of the paper--did you look into this?

* @details This relation is defined as:
lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved
* q_pos2 * ( (t6 - w_1_shift) + \alpha * (t5 - w_2_shift) +
* \alpha^2 * (t7 - w_3_shift) + \alpha^3 * (t4 - w_4_shift) ) = 0 where:
* u1 := (w_1 + q_1)^5
* u2 := (w_2 + q_2)^5
* u3 := (w_3 + q_3)^5
* u4 := (w_4 + q_4)^5
* t0 := u1 + u2 (1, 1, 0, 0)
* t1 := u3 + u4 (0, 0, 1, 1)
* t2 := u2 + u2 + t1 = 2 * u2 + u3 + u4 (0, 2, 1, 1)
* t3 := u4 + u4 + t0 = u1 + u2 + 2 * u4 (1, 1, 0, 2)
* t4 := 4 * t1 + t3 = u1 + u2 + 4 * u3 + 6 * u4 (1, 1, 4, 6)
* t5 := 4 * t0 + t2 = 4 * u1 + 6 * u2 + u3 + u4 (4, 6, 1, 1)
* t6 := t3 + t5 = 5 * u1 + 7 * u2 + 1 * u3 + 3 * u4 (5, 7, 1, 3)
* t7 := t2 + t4 (1, 3, 5, 7)
*
* @param evals transformed to `evals + C(in(X)...)*scaling_factor`
* @param in an std::array containing the fully extended Univariate edges.
* @param parameters contains beta, gamma, and public_input_delta, ....
* @param scaling_factor optional term to scale the evaluation before adding to evals.
*/
template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
void static accumulate(ContainerOverSubrelations& evals,
const AllEntities& in,
const Parameters&,
const FF& scaling_factor)
{
using Accumulator = std::tuple_element_t<0, ContainerOverSubrelations>;
using View = typename Accumulator::View;
auto w_l = View(in.w_l);
auto w_r = View(in.w_r);
auto w_o = View(in.w_o);
auto w_4 = View(in.w_4);
auto w_l_shift = View(in.w_l_shift);
auto w_r_shift = View(in.w_r_shift);
auto w_o_shift = View(in.w_o_shift);
auto w_4_shift = View(in.w_4_shift);
auto q_l = View(in.q_l);
auto q_r = View(in.q_r);
auto q_o = View(in.q_o);
auto q_4 = View(in.q_4);
auto q_poseidon2_external = View(in.q_poseidon2_external);

// add round constants which are loaded in selectors
auto v1 = w_l + q_l;
auto v2 = w_r + q_r;
auto v3 = w_o + q_o;
auto v4 = w_4 + q_4;

// apply s-box round
auto u1 = v1 * v1;
u1 *= u1;
u1 *= v1;
auto u2 = v2 * v2;
u2 *= u2;
u2 *= v2;
auto u3 = v3 * v3;
u3 *= u3;
u3 *= v3;
auto u4 = v4 * v4;
u4 *= u4;
u4 *= v4;

// matrix mul with 14 additions
auto t0 = u1 + u2; // A + B
lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved
auto t1 = u3 + u4; // C + D
auto t2 = u2 + u2; // 2B
t2 += t1; // 2B + C + D
auto t3 = u4 + u4; // 2D
t3 += t0; // 2D + A + B
auto t4 = t1 + t1;
t4 += t4;
t4 += t3; // A + B + 4C + 6D
auto t5 = t0 + t0;
t5 += t5;
t5 += t2; // 4A + 6B + C + D
auto t6 = t3 + t5; // 5A + 7B + 3C + D
lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved
auto t7 = t2 + t4; // A + 3B + 5D + 7C
lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved

{
auto tmp = q_poseidon2_external * (t6 - w_l_shift);
tmp *= scaling_factor;
std::get<0>(evals) += tmp;
}
{
auto tmp = q_poseidon2_external * (t5 - w_r_shift);
tmp *= scaling_factor;
std::get<1>(evals) += tmp;
}
{
auto tmp = q_poseidon2_external * (t7 - w_o_shift);
tmp *= scaling_factor;
std::get<2>(evals) += tmp;
}
{
auto tmp = q_poseidon2_external * (t4 - w_4_shift);
tmp *= scaling_factor;
std::get<3>(evals) += tmp;
}
};
};

template <typename FF> using Poseidon2ExternalRelation = Relation<Poseidon2ExternalRelationImpl<FF>>;
} // namespace proof_system
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#pragma once
#include "barretenberg/crypto/poseidon2/poseidon2_params.hpp"
#include "relation_types.hpp"

namespace proof_system {

template <typename FF_> class Poseidon2InternalRelationImpl {
public:
using FF = FF_;

static constexpr std::array<size_t, 4> SUBRELATION_PARTIAL_LENGTHS{
7, // internal poseidon2 round sub-relation for first value
7, // internal poseidon2 round sub-relation for second value
7, // internal poseidon2 round sub-relation for third value
7, // internal poseidon2 round sub-relation for fourth value
};

/**
* @brief Expression for the poseidon2 internal gate.
* @details This relation is defined as:
* q_pos2 * ( (v1 - w_1_shift) + \alpha * (v2 - w_2_shift) +
* \alpha^2 * (v3 - w_3_shift) + \alpha^3 * (v4 - w_4_shift) ) = 0 where:
* v1 := (w_1 + q_1)^5
* v2 := w_2
* v3 := w_3
* v4 := w_4
* sum := v1 + v2 + v3 + v4
* v1 := v1 * D1 + sum
* v2 := v2 * D2 + sum
* v3 := v3 * D3 + sum
* v4 := v4 * D4 + sum
* Di is the ith internal diagonal value - 1 of the internal matrix
*
* @param evals transformed to `evals + C(in(X)...)*scaling_factor`
* @param in an std::array containing the fully extended Univariate edges.
* @param parameters contains beta, gamma, and public_input_delta, ....
* @param scaling_factor optional term to scale the evaluation before adding to evals.
*/
template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
void static accumulate(ContainerOverSubrelations& evals,
const AllEntities& in,
const Parameters&,
const FF& scaling_factor)
{
using Accumulator = std::tuple_element_t<0, ContainerOverSubrelations>;
using View = typename Accumulator::View;
auto w_l = View(in.w_l);
auto w_r = View(in.w_r);
auto w_o = View(in.w_o);
auto w_4 = View(in.w_4);
auto w_l_shift = View(in.w_l_shift);
auto w_r_shift = View(in.w_r_shift);
auto w_o_shift = View(in.w_o_shift);
auto w_4_shift = View(in.w_4_shift);
auto q_l = View(in.q_l);
auto q_poseidon2_internal = View(in.q_poseidon2_internal);

// add round constants
auto v1 = w_l + q_l;

// apply s-box round
auto u1 = v1 * v1;
u1 *= u1;
u1 *= v1;

// matrix mul with 4 muls and 7 additions
auto sum = u1 + w_r + w_o + w_4;
{
lucasxia01 marked this conversation as resolved.
Show resolved Hide resolved
auto t0 = u1 * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[0];
t0 += sum;
auto tmp = q_poseidon2_internal * (t0 - w_l_shift);
tmp *= scaling_factor;
std::get<0>(evals) += tmp;
}
{
auto t1 = w_r * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[1];
t1 += sum;
auto tmp = q_poseidon2_internal * (t1 - w_r_shift);
tmp *= scaling_factor;
std::get<1>(evals) += tmp;
}
{
auto t2 = w_o * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[2];
t2 += sum;
auto tmp = q_poseidon2_internal * (t2 - w_o_shift);
tmp *= scaling_factor;
std::get<2>(evals) += tmp;
}
{
auto t3 = w_4 * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[3];
t3 += sum;
auto tmp = q_poseidon2_internal * (t3 - w_4_shift);
tmp *= scaling_factor;
std::get<3>(evals) += tmp;
}
};
}; // namespace proof_system

template <typename FF> using Poseidon2InternalRelation = Relation<Poseidon2InternalRelationImpl<FF>>;
} // namespace proof_system
168 changes: 168 additions & 0 deletions barretenberg/cpp/src/barretenberg/relations/relation_manual.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "barretenberg/flavor/flavor.hpp"
#include "barretenberg/relations/poseidon2_external_relation.hpp"
#include "barretenberg/relations/poseidon2_internal_relation.hpp"
#include "barretenberg/relations/relation_parameters.hpp"
#include <gtest/gtest.h>

namespace proof_system::relation_manual_tests {

using FF = barretenberg::fr;

class RelationManual : public testing::Test {};

TEST_F(RelationManual, Poseidon2ExternalRelationZeros)
{
using Accumulator = std::array<FF, 4>;
using Relation = Poseidon2ExternalRelation<FF>;

Accumulator acc{ 0, 0, 0, 0 };
struct AllPoseidonValues {
FF q_poseidon2_external;
FF w_l;
FF w_r;
FF w_o;
FF w_4;
FF w_l_shift;
FF w_r_shift;
FF w_o_shift;
FF w_4_shift;
FF q_l;
FF q_r;
FF q_o;
FF q_4;
};
AllPoseidonValues all_poseidon_values{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

const auto parameters = RelationParameters<FF>::get_random();
Relation::accumulate(acc, all_poseidon_values, parameters, 1);
EXPECT_EQ(acc[0], 0);
EXPECT_EQ(acc[1], 0);
EXPECT_EQ(acc[2], 0);
EXPECT_EQ(acc[3], 0);
}

TEST_F(RelationManual, Poseidon2ExternalRelationRandom)
{
using Accumulator = std::array<FF, 4>;
using Relation = Poseidon2ExternalRelation<FF>;

Accumulator acc{ 0, 0, 0, 0 };
struct AllPoseidonValues {
FF q_poseidon2_external;
FF w_l;
FF w_r;
FF w_o;
FF w_4;
FF q_l;
FF q_r;
FF q_o;
FF q_4;
FF w_l_shift;
FF w_r_shift;
FF w_o_shift;
FF w_4_shift;
};
/*
* v1 = w_1 + q_1 = 5 + 6 = 11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name clash here: you mean l r o 4 not 1 2 3 4 right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a name clash everywhere and I don't know whether we want to use 1 2 3 4 or l r o 4. It looked like we use l r o 4 in actual code and 1 2 3 4 in comments, so thats the convention I've been following.

* v2 = w_2 + q_2 = 4 + 9 = 13
* v3 = w_3 + q_3 = 1 + 8 = 9
* v4 = w_4 + q_4 = 7 + 3 = 10
* u1 = v1^5 = 11^5 = 161051
* u2 = v2^5 = 13^5 = 371293
* u3 = v3^5 = 9^5 = 59049
* u4 = v4^5 = 10^5 = 100000
* matrix mul with calculator:
* 1 3763355
* 2 3031011
* 3 2270175
* 4 1368540
*/
AllPoseidonValues all_poseidon_values{ 1, 5, 4, 1, 7, 6, 9, 8, 3, 3763355, 3031011, 2270175, 1368540 };

const auto parameters = RelationParameters<FF>::get_random();
Relation::accumulate(acc, all_poseidon_values, parameters, 1);
EXPECT_EQ(acc[0], 0);
EXPECT_EQ(acc[1], 0);
EXPECT_EQ(acc[2], 0);
EXPECT_EQ(acc[3], 0);
}

TEST_F(RelationManual, Poseidon2InternalRelationZeros)
{
using Accumulator = std::array<FF, 4>;
using Relation = Poseidon2InternalRelation<FF>;

Accumulator acc{ 0, 0, 0, 0 };
struct AllPoseidonValues {
FF q_poseidon2_internal;
FF w_l;
FF w_r;
FF w_o;
FF w_4;
FF w_l_shift;
FF w_r_shift;
FF w_o_shift;
FF w_4_shift;
FF q_l;
FF q_r;
FF q_o;
FF q_4;
};
AllPoseidonValues all_poseidon_values{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

const auto parameters = RelationParameters<FF>::get_random();
Relation::accumulate(acc, all_poseidon_values, parameters, 1);
EXPECT_EQ(acc[0], 0);
EXPECT_EQ(acc[1], 0);
EXPECT_EQ(acc[2], 0);
EXPECT_EQ(acc[3], 0);
}

TEST_F(RelationManual, Poseidon2InternalRelationRandom)
{
using Accumulator = std::array<FF, 4>;
using Relation = Poseidon2InternalRelation<FF>;

Accumulator acc{ 0, 0, 0, 0 };
struct AllPoseidonValues {
FF q_poseidon2_internal;
FF w_l;
FF w_r;
FF w_o;
FF w_4;
FF q_l;

FF w_l_shift;
FF w_r_shift;
FF w_o_shift;
FF w_4_shift;
};
/*
* u1 = (w_1 + q_1)^5 = (1 + 5)^5 = 7776
* sum = u1 + w_2 + w_3 + w_4 = 7776 + 2 + 3 + 4 = 7785
* matrix mul with calculator:
* 1 0x122d9ce41e83c533318954d77a4ebc40eb729f6543ebd5f2e4ecb175ced3bc74
* 2 0x185028b6d489be7c029367a14616776b33bf2eada9bb370950d6719f68b5067f
* 3 0x00fce289a96b3f4a18562d0ef0ab76ca165e613222aa0c24501377003c5622a8
* 4 0x27e7677799fda1694819803f459b76d2fb1c45fdf0773375c72d61e8efb92893
*/
AllPoseidonValues all_poseidon_values{
1,
1,
2,
3,
4,
5,
FF(std::string("0x122d9ce41e83c533318954d77a4ebc40eb729f6543ebd5f2e4ecb175ced3bc74")),
FF(std::string("0x185028b6d489be7c029367a14616776b33bf2eada9bb370950d6719f68b5067f")),
FF(std::string("0x00fce289a96b3f4a18562d0ef0ab76ca165e613222aa0c24501377003c5622a8")),
FF(std::string("0x27e7677799fda1694819803f459b76d2fb1c45fdf0773375c72d61e8efb92893"))
};
const auto parameters = RelationParameters<FF>::get_random();
Relation::accumulate(acc, all_poseidon_values, parameters, 1);
EXPECT_EQ(acc[0], 0);
EXPECT_EQ(acc[1], 0);
EXPECT_EQ(acc[2], 0);
EXPECT_EQ(acc[3], 0);
}
}; // namespace proof_system::relation_manual_tests
Loading