Skip to content

Commit

Permalink
chore: implement poseidon2 opcode (#4446)
Browse files Browse the repository at this point in the history
This PR create constraints for poseidon2permutation Noir opcodes.
I added a unit test for the opcode.

It also implements poseidon2 permutation circuit for UltraPlonk. Because
the s-box function would require an increase of the polynomial degree in
Ultraplonk relations, it is not compatible with GoblinPlonk circuits.
So I added a non-optimised UltraPlonk version for Poseidon2 permutation.
This is necessary because Noir requires the UltraPlonk backend and it
would not work if we had only the GoblinPlonk version of the opcode.

Thank you @lucasxia01 for the templatised version of the function.

---------

Co-authored-by: lucasxia01 <lucasxia01@gmail.com>
  • Loading branch information
guipublic and lucasxia01 authored Feb 13, 2024
1 parent 5ddfa16 commit 491a8df
Show file tree
Hide file tree
Showing 19 changed files with 291 additions and 10 deletions.
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ barretenberg_module(
stdlib_blake2s
stdlib_keccak
stdlib_pedersen_hash
stdlib_poseidon2
crypto_merkle_tree
stdlib_schnorr
crypto_sha256
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "acir_format.hpp"
#include "barretenberg/common/log.hpp"
#include "barretenberg/dsl/acir_format/bigint_constraint.hpp"
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"
#include <cstddef>

Expand Down Expand Up @@ -81,6 +80,9 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo
create_pedersen_hash_constraint(builder, constraint);
}

for (const auto& constraint : constraint_system.poseidon2_constraints) {
create_poseidon2_permutations(builder, constraint);
}
// Add fixed base scalar mul constraints
for (const auto& constraint : constraint_system.fixed_base_scalar_mul_constraints) {
create_fixed_base_constraint(builder, constraint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "keccak_constraint.hpp"
#include "logic_constraint.hpp"
#include "pedersen.hpp"
#include "poseidon2_constraint.hpp"
#include "range_constraint.hpp"
#include "recursion_constraint.hpp"
#include "schnorr_verify.hpp"
Expand Down Expand Up @@ -45,6 +46,7 @@ struct AcirFormat {
std::vector<Keccakf1600> keccak_permutations;
std::vector<PedersenConstraint> pedersen_constraints;
std::vector<PedersenHashConstraint> pedersen_hash_constraints;
std::vector<Poseidon2Constraint> poseidon2_constraints;
std::vector<FixedBaseScalarMul> fixed_base_scalar_mul_constraints;
std::vector<EcAdd> ec_add_constraints;
std::vector<RecursionConstraint> recursion_constraints;
Expand Down Expand Up @@ -77,6 +79,7 @@ struct AcirFormat {
keccak_permutations,
pedersen_constraints,
pedersen_hash_constraints,
poseidon2_constraints,
fixed_base_scalar_mul_constraints,
ec_add_constraints,
recursion_constraints,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -160,6 +161,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -227,6 +229,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -322,6 +325,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -436,6 +440,7 @@ TEST_F(AcirFormatTests, TestVarKeccak)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -482,6 +487,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation)
.keccak_permutations = { keccak_permutation },
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "barretenberg/dsl/acir_format/keccak_constraint.hpp"
#include "barretenberg/dsl/acir_format/logic_constraint.hpp"
#include "barretenberg/dsl/acir_format/pedersen.hpp"
#include "barretenberg/dsl/acir_format/poseidon2_constraint.hpp"
#include "barretenberg/dsl/acir_format/range_constraint.hpp"
#include "barretenberg/dsl/acir_format/recursion_constraint.hpp"
#include "barretenberg/dsl/acir_format/schnorr_verify.hpp"
Expand Down Expand Up @@ -307,6 +308,12 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci
.result = arg.output,
.opcode = BigIntOperationType::Div,
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::Poseidon2Permutation>) {
af.poseidon2_constraints.push_back(Poseidon2Constraint{
.state = map(arg.inputs, [](auto& e) { return e.witness.value; }),
.result = map(arg.outputs, [](auto& e) { return e.value; }),
.len = arg.len,
});
}
},
arg.value.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -250,6 +251,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -302,6 +304,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -358,6 +361,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ TEST_F(EcOperations, TestECOperations)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = { ec_add_constraint },
.recursion_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -153,6 +154,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -196,6 +198,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ TEST(ECDSASecp256r1, test_hardcoded)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -189,6 +190,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -236,6 +238,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -278,6 +281,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ template <typename Builder> void create_keccak_permutations(Builder& builder, co
// Get the witness assignment for each witness index
// Write the witness assignment to the byte_array
for (size_t i = 0; i < constraint.state.size(); ++i) {
info(constraint.state[i]);
state[i] = field_ct::from_witness_index(&builder, constraint.state[i]);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "poseidon2_constraint.hpp"
#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp"

namespace acir_format {
template <typename Builder> void create_poseidon2_permutations(Builder& builder, const Poseidon2Constraint& constraint)
{
using field_ct = bb::stdlib::field_t<Builder>;
using Poseidon2Params = bb::stdlib::crypto::Poseidon2Bn254ScalarFieldParams;
using State = std::array<field_ct, Poseidon2Params::t>;

ASSERT(constraint.state.size() == constraint.len);
ASSERT(constraint.result.size() == constraint.len);
// Get the witness assignment for each witness index
// Write the witness assignment to the byte_array state
State state;
for (size_t i = 0; i < constraint.state.size(); ++i) {
state[i] = field_ct::from_witness_index(&builder, constraint.state[i]);
}
State output_state;
output_state = bb::stdlib::Poseidon2Permutation<Poseidon2Params, Builder>::permutation(&builder, state);
for (size_t i = 0; i < output_state.size(); ++i) {
poly_triple assert_equal{
.a = output_state[i].normalize().witness_index,
.b = constraint.result[i],
.c = 0,
.q_m = 0,
.q_l = 1,
.q_r = -1,
.q_o = 0,
.q_c = 0,
};
builder.create_poly_gate(assert_equal);
}
}

template void create_poseidon2_permutations<UltraCircuitBuilder>(UltraCircuitBuilder& builder,
const Poseidon2Constraint& constraint);

template void create_poseidon2_permutations<GoblinUltraCircuitBuilder>(GoblinUltraCircuitBuilder& builder,
const Poseidon2Constraint& constraint);
} // namespace acir_format
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once
#include "barretenberg/dsl/types.hpp"
#include "barretenberg/serialize/msgpack.hpp"
#include <cstdint>
#include <vector>

namespace acir_format {

struct Poseidon2Constraint {
std::vector<uint32_t> state;
std::vector<uint32_t> result;
uint32_t len;

// For serialization, update with any new fields
MSGPACK_FIELDS(state, result, len);
friend bool operator==(Poseidon2Constraint const& lhs, Poseidon2Constraint const& rhs) = default;
};

template <typename Builder> void create_poseidon2_permutations(Builder& builder, const Poseidon2Constraint& constraint);

} // namespace acir_format
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "poseidon2_constraint.hpp"
#include "acir_format.hpp"
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "barretenberg/plonk/proof_system/types/proof.hpp"
#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp"

#include <cstdint>
#include <gtest/gtest.h>
#include <vector>

namespace acir_format::tests {

class Poseidon2Tests : public ::testing::Test {
protected:
static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); }
};
using fr = field<Bn254FrParams>;

/**
* @brief Create a circuit testing the Poseidon2 permutation function
*
*/
TEST_F(Poseidon2Tests, TestPoseidon2Permutation)
{
Poseidon2Constraint
poseidon2_constraint{
.state = { 1, 2, 3, 4, },
.result = { 5, 6, 7, 8, },
.len = 4,
};

AcirFormat constraint_system{ .varnum = 9,
.recursive = false,
.public_inputs = {},
.logic_constraints = {},
.range_constraints = {},
.sha256_constraints = {},
.sha256_compression = {},
.schnorr_constraints = {},
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_var_constraints = {},
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = { poseidon2_constraint },
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_to_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {} };

WitnessVector witness{
1,
0,
1,
2,
3,
bb::fr(std::string("0x01bd538c2ee014ed5141b29e9ae240bf8db3fe5b9a38629a9647cf8d76c01737")),
bb::fr(std::string("0x239b62e7db98aa3a2a8f6a0d2fa1709e7a35959aa6c7034814d9daa90cbac662")),
bb::fr(std::string("0x04cbb44c61d928ed06808456bf758cbf0c18d1e15a7b6dbc8245fa7515d5e3cb")),
bb::fr(std::string("0x2e11c5cff2a22c64d01304b778d78f6998eff1ab73163a35603f54794c30847a")),
};

auto builder = create_circuit(constraint_system, /*size_hint=*/0, witness);

auto composer = Composer();
auto prover = composer.create_ultra_with_keccak_prover(builder);
auto proof = prover.construct_proof();

auto verifier = composer.create_ultra_with_keccak_verifier(builder);

EXPECT_EQ(verifier.verify_proof(proof), true);
}

} // namespace acir_format::tests
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Builder create_inner_circuit()
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
Expand Down Expand Up @@ -254,6 +255,7 @@ Builder create_outer_circuit(std::vector<Builder>& inner_circuits)
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.fixed_base_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = recursion_constraints,
Expand Down
Loading

0 comments on commit 491a8df

Please sign in to comment.