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: add poseidon2 hashing to native transcript #3718

Merged
merged 43 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
29a0d28
added poseidon2 to native transcript
lucasxia01 Dec 14, 2023
61c9eca
wip
lucasxia01 Jan 4, 2024
a8204fb
removed grumpkin poseidon2 params
lucasxia01 Jan 10, 2024
05085c5
removed transcript template param,
lucasxia01 Jan 10, 2024
99bd01d
removing poseidon2 grumpkin
lucasxia01 Jan 10, 2024
029350c
removed template param from honk::proof
lucasxia01 Jan 10, 2024
a045b6d
linker error be gone among other merge errors
lucasxia01 Jan 14, 2024
86065bc
conversions
lucasxia01 Jan 16, 2024
d50ac92
updated calc_num_frs() with all transcript types
lucasxia01 Jan 17, 2024
5f46e2d
completed convert_to_bn254_frs for various transcript types
lucasxia01 Jan 17, 2024
d157087
convert_from_bn254_frs initial impl updated
lucasxia01 Jan 17, 2024
f769528
fixing bugs (wip)
lucasxia01 Jan 17, 2024
e8702c7
hacky solution to templating to get things to compile
lucasxia01 Jan 17, 2024
86eae85
checking if CI tests still fail
lucasxia01 Jan 18, 2024
4a04326
fixed bugs in conversions
lucasxia01 Jan 18, 2024
2d16e5d
added (partial) unit tests
lucasxia01 Jan 18, 2024
2c6406d
updated structuring and tests
lucasxia01 Jan 18, 2024
c0c715c
temporary "fix" to ci gcc compile error
lucasxia01 Jan 18, 2024
dd3366c
cleaning up field conversion calc_num_frs style
lucasxia01 Jan 18, 2024
b37bed8
undo challenge fix
lucasxia01 Jan 18, 2024
09f7ea2
pushing linker error
lucasxia01 Jan 19, 2024
7346629
Merge branch 'master' into lx/transcript-native-field-refactor
lucasxia01 Jan 19, 2024
1484030
changed to bb::
lucasxia01 Jan 19, 2024
97c2f88
inline + comments + cleanup
lucasxia01 Jan 19, 2024
e2f7526
completed tests, small updates
lucasxia01 Jan 19, 2024
f67148d
Merge branch 'master' into lx/transcript-native-field-refactor
lucasxia01 Jan 19, 2024
c0b5fb6
reomving unnecessary cmake stuff
lucasxia01 Jan 22, 2024
d3e110b
Merge branch 'master' into lx/transcript-native-field-refactor
lucasxia01 Jan 22, 2024
330c0c8
Merge branch 'master' into lx/transcript-native-field-refactor
lucasxia01 Jan 23, 2024
7fd7553
fix?
lucasxia01 Jan 23, 2024
bbfb92b
cbind fix fix
lucasxia01 Jan 23, 2024
a53a144
undo
lucasxia01 Jan 23, 2024
e12cb61
maybe cbind fix
lucasxia01 Jan 23, 2024
fe43adf
cbind fix for real this time
lucasxia01 Jan 24, 2024
b1d5678
fixed error caused by overfixing
lucasxia01 Jan 24, 2024
cab1312
Merge branch 'master' into lx/transcript-native-field-refactor
lucasxia01 Jan 24, 2024
54bb864
fixed merge conflicts with protogalaxy, decider recursive verifiers
lucasxia01 Jan 24, 2024
9cc55d1
updated conversion for grumpkin fr
lucasxia01 Jan 29, 2024
87078b3
responded to PR comments, refactored, added comments
lucasxia01 Jan 29, 2024
850ec4d
small style updates
lucasxia01 Jan 30, 2024
9f6293c
Merge branch 'master' into lx/transcript-native-field-refactor
lucasxia01 Jan 30, 2024
777e8b1
updated merged in code
lucasxia01 Jan 30, 2024
de5b619
updated protogalaxy cmakelists
lucasxia01 Jan 30, 2024
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
2 changes: 2 additions & 0 deletions barretenberg/cpp/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ set(BARRETENBERG_TARGET_OBJECTS
$<TARGET_OBJECTS:crypto_keccak_objects>
$<TARGET_OBJECTS:crypto_pedersen_commitment_objects>
$<TARGET_OBJECTS:crypto_pedersen_hash_objects>
$<TARGET_OBJECTS:crypto_poseidon2_objects>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

not sure what this is doing but this helped me resolve some annoying linker errors, presumably introduced because goblin was introduced to main

Copy link
Contributor Author

@lucasxia01 lucasxia01 Jan 22, 2024

Choose a reason for hiding this comment

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

this is necessary from building without it/with it since transcript uses it, which is used by main.cpp in goblin_verify

$<TARGET_OBJECTS:crypto_schnorr_objects>
$<TARGET_OBJECTS:crypto_sha256_objects>
$<TARGET_OBJECTS:dsl_objects>
Expand All @@ -128,6 +129,7 @@ set(BARRETENBERG_TARGET_OBJECTS
$<TARGET_OBJECTS:stdlib_merkle_tree_objects>
$<TARGET_OBJECTS:stdlib_pedersen_commitment_objects>
$<TARGET_OBJECTS:stdlib_pedersen_hash_objects>
$<TARGET_OBJECTS:stdlib_poseidon2_objects>
$<TARGET_OBJECTS:stdlib_primitives_objects>
$<TARGET_OBJECTS:stdlib_recursion_objects>
$<TARGET_OBJECTS:stdlib_schnorr_objects>
Expand Down
2 changes: 2 additions & 0 deletions barretenberg/cpp/src/barretenberg/barretenberg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "crypto/keccak/keccak.hpp"
#include "crypto/pedersen_commitment/pedersen.hpp"
#include "crypto/pedersen_hash/pedersen.hpp"
#include "crypto/poseidon2/poseidon2.hpp"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added in an attempt to solve linker error, but probably still needed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

seems like this file is unused so adding this is just for documentation about what is in barretenberg

#include "crypto/schnorr/schnorr.hpp"
#include "crypto/sha256/sha256.hpp"
#include "ecc/curves/bn254/fq.hpp"
Expand All @@ -41,6 +42,7 @@
#include "stdlib/hash/blake2s/blake2s.hpp"
#include "stdlib/hash/blake3s/blake3s.hpp"
#include "stdlib/hash/pedersen/pedersen.hpp"
#include "stdlib/hash/poseidon2/poseidon2.hpp"
#include "stdlib/merkle_tree/hash.hpp"
#include "stdlib/merkle_tree/membership.hpp"
#include "stdlib/merkle_tree/memory_store.hpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ template <typename Params> class Poseidon2Permutation {
using MatrixDiagonal = std::array<FF, t>;
using RoundConstantsContainer = std::array<RoundConstants, NUM_ROUNDS>;

static constexpr MatrixDiagonal internal_matrix_diagonal =
Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal;
static constexpr RoundConstantsContainer round_constants = Poseidon2Bn254ScalarFieldParams::round_constants;
static constexpr MatrixDiagonal internal_matrix_diagonal = Params::internal_matrix_diagonal;
static constexpr RoundConstantsContainer round_constants = Params::round_constants;

static constexpr void matrix_multiplication_4x4(State& input)
{
Expand Down
24 changes: 16 additions & 8 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr,
acir_composer->create_circuit(constraint_system, witness);

acir_composer->init_proving_key();
auto proof_data = acir_composer->create_proof(*is_recursive);
*out = to_heap_buffer(proof_data);
auto proof = acir_composer->create_proof(*is_recursive);
*out = to_heap_buffer(proof);
}

WASM_EXPORT void acir_goblin_accumulate(in_ptr acir_composer_ptr,
Expand All @@ -73,8 +73,11 @@ WASM_EXPORT void acir_goblin_accumulate(in_ptr acir_composer_ptr,
auto witness = acir_format::witness_buf_to_witness_data(from_buffer<std::vector<uint8_t>>(witness_vec));

acir_composer->create_circuit(constraint_system, witness);
auto proof_data = acir_composer->accumulate();
*out = to_heap_buffer(proof_data);
auto proof = acir_composer->accumulate();
auto proof_data_buf = to_buffer</*include_size=*/true>(
proof); // template parameter needs to be set so that vector deserialization from
// buffer, which reads the size at the beginning can be done properly
*out = to_heap_buffer(proof_data_buf);
}

WASM_EXPORT void acir_goblin_prove(in_ptr acir_composer_ptr,
Expand All @@ -87,8 +90,11 @@ WASM_EXPORT void acir_goblin_prove(in_ptr acir_composer_ptr,
auto witness = acir_format::witness_buf_to_witness_data(from_buffer<std::vector<uint8_t>>(witness_vec));

acir_composer->create_circuit(constraint_system, witness);
auto proof_data = acir_composer->accumulate_and_prove();
*out = to_heap_buffer(proof_data);
auto proof = acir_composer->accumulate_and_prove();
auto proof_data_buf = to_buffer</*include_size=*/true>(
proof); // template parameter needs to be set so that vector deserialization from
// buffer, which reads the size at the beginning can be done properly
*out = to_heap_buffer(proof_data_buf);
}

WASM_EXPORT void acir_load_verification_key(in_ptr acir_composer_ptr, uint8_t const* vk_buf)
Expand Down Expand Up @@ -125,14 +131,16 @@ WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, uint8_t const* a
WASM_EXPORT void acir_goblin_verify_accumulator(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result)
{
auto acir_composer = reinterpret_cast<acir_proofs::GoblinAcirComposer*>(*acir_composer_ptr);
auto proof = from_buffer<std::vector<uint8_t>>(proof_buf);
auto proof_data_buf = from_buffer<std::vector<uint8_t>>(proof_buf);
auto proof = from_buffer<std::vector<bb::fr>>(proof_data_buf);
Copy link
Contributor

Choose a reason for hiding this comment

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

flagging: should these transformations just become part of the methods the data is input to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

clarify what that means?

Copy link
Contributor

Choose a reason for hiding this comment

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

never mind - this was a note to self as I was going through. Nothing to do here

*result = acir_composer->verify_accumulator(proof);
}

WASM_EXPORT void acir_goblin_verify(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result)
{
auto acir_composer = reinterpret_cast<acir_proofs::GoblinAcirComposer*>(*acir_composer_ptr);
auto proof = from_buffer<std::vector<uint8_t>>(proof_buf);
auto proof_data_buf = from_buffer<std::vector<uint8_t>>(proof_buf);
auto proof = from_buffer<std::vector<bb::fr>>(proof_data_buf);
Copy link
Contributor

Choose a reason for hiding this comment

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

So here and elsewhere we're taking a uint8_t* then reading into a std::vector<uint8_t> then reading that into a std::vector<bb::fr>. Any reason we can't skip the intermediate step?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can't skip an intermediate step because to_heap_buffer does not call to_buffer on the first call. If I can change that part of to_heap_buffer without breaking other things, then it might be fine, but just went with this to be safe.

*result = acir_composer->verify(proof);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,37 @@ void GoblinAcirComposer::create_circuit(acir_format::AcirFormat& constraint_syst
GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder_);
}

std::vector<uint8_t> GoblinAcirComposer::accumulate()
std::vector<bb::fr> GoblinAcirComposer::accumulate()
{
// // Construct a GUH proof for the circuit via the accumulate mechanism
// return goblin.accumulate_for_acir(builder_);

// Construct one final GUH proof via the accumulate mechanism
std::vector<uint8_t> ultra_proof = goblin.accumulate_for_acir(builder_);
std::vector<bb::fr> ultra_proof = goblin.accumulate_for_acir(builder_);

// Construct a Goblin proof (ECCVM, Translator, Merge); result stored internally
goblin.prove_for_acir();

return ultra_proof;
}

bool GoblinAcirComposer::verify_accumulator(std::vector<uint8_t> const& proof)
bool GoblinAcirComposer::verify_accumulator(std::vector<bb::fr> const& proof)
{
return goblin.verify_accumulator_for_acir(proof);
}

std::vector<uint8_t> GoblinAcirComposer::accumulate_and_prove()
std::vector<bb::fr> GoblinAcirComposer::accumulate_and_prove()
{
// Construct one final GUH proof via the accumulate mechanism
std::vector<uint8_t> ultra_proof = goblin.accumulate_for_acir(builder_);
std::vector<bb::fr> ultra_proof = goblin.accumulate_for_acir(builder_);

// Construct a Goblin proof (ECCVM, Translator, Merge); result stored internally
goblin.prove_for_acir();

return ultra_proof;
}

bool GoblinAcirComposer::verify(std::vector<uint8_t> const& proof)
bool GoblinAcirComposer::verify(std::vector<bb::fr> const& proof)
{
// Verify the final GUH proof
bool ultra_verified = goblin.verify_accumulator_for_acir(proof);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ class GoblinAcirComposer {
* @brief Accumulate a circuit via Goblin
* @details For the present circuit, construct a GUH proof and the vkey needed to verify it
*
* @return std::vector<uint8_t> The GUH proof bytes
* @return std::vector<bb::fr> The GUH proof bytes
*/
std::vector<uint8_t> accumulate();
std::vector<bb::fr> accumulate();

/**
* @brief Verify the Goblin accumulator (the GUH proof) using the vkey internal to Goblin
*
* @param proof
* @return bool Whether or not the proof was verified
*/
bool verify_accumulator(std::vector<uint8_t> const& proof);
bool verify_accumulator(std::vector<bb::fr> const& proof);

/**
* @brief Accumulate a final circuit and construct a full Goblin proof
Expand All @@ -48,14 +48,14 @@ class GoblinAcirComposer {
* accumulation phase.
*
*/
std::vector<uint8_t> accumulate_and_prove();
std::vector<bb::fr> accumulate_and_prove();

/**
* @brief Verify the final GUH proof and the full Goblin proof
*
* @return bool verified
*/
bool verify(std::vector<uint8_t> const& proof);
bool verify(std::vector<bb::fr> const& proof);

private:
acir_format::GoblinBuilder builder_;
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/ecc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ target_precompile_headers(
$<$<COMPILE_LANGUAGE:CXX>:"${CMAKE_CURRENT_SOURCE_DIR}/fields/field_impl_generic.hpp">
$<$<COMPILE_LANGUAGE:CXX>:"${CMAKE_CURRENT_SOURCE_DIR}/fields/field_impl_x64.hpp">
$<$<COMPILE_LANGUAGE:CXX>:"${CMAKE_CURRENT_SOURCE_DIR}/fields/field.hpp">
)
)
116 changes: 116 additions & 0 deletions barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@

#include "barretenberg/ecc/fields/field_conversion.hpp"

namespace bb::field_conversion {

static constexpr uint64_t NUM_CONVERSION_LIMB_BITS = 68; // set to be 68 because bigfield has 68 bit limbs
static constexpr uint64_t TOTAL_BITS = 254;

bb::fr convert_from_bn254_frs(std::span<const bb::fr> fr_vec, bb::fr* /*unused*/)
{
ASSERT(fr_vec.size() == 1);
return fr_vec[0];
}

bool convert_from_bn254_frs(std::span<const bb::fr> fr_vec, bool* /*unused*/)
{
ASSERT(fr_vec.size() == 1);
return fr_vec[0] != 0;
}

/**
* @brief Converts 2 bb::fr elements to grumpkin::fr
* @details First, this function must take in 2 bb::fr elements because the grumpkin::fr field has a larger modulus than
* the bb::fr field, so we choose to send 1 grumpkin::fr element to 2 bb::fr elements to maintain injectivity.
* For the implementation, we want to minimize the number of constraints created by the circuit form, which happens to
* use 68 bit limbs to represent a grumpkin::fr (as a bigfield). Therefore, our mapping will split a grumpkin::fr into a
* 136 bit chunk for the lower two bigfield limbs and the upper chunk for the upper two limbs. The upper chunk ends up
* being 254 - 2*68 = 118 bits as a result. This is why we check that the bb::frs must be at most 136 and 118 bits
* respectively (to ensure no overflow). Then, we converts the two chunks to a grumpkin::fr using uint256_t conversions.
* @param low_bits_in
* @param high_bits_in
* @return grumpkin::fr
*/
grumpkin::fr convert_from_bn254_frs(std::span<const bb::fr> fr_vec, grumpkin::fr* /*unused*/)
{
// Combines the two elements into one uint256_t, and then convert that to a grumpkin::fr
ASSERT(uint256_t(fr_vec[0]) < (uint256_t(1) << (NUM_CONVERSION_LIMB_BITS * 2))); // lower 136 bits
ASSERT(uint256_t(fr_vec[1]) <
(uint256_t(1) << (TOTAL_BITS - NUM_CONVERSION_LIMB_BITS * 2))); // upper 254-136=118 bits
uint256_t value = uint256_t(fr_vec[0]) + (uint256_t(fr_vec[1]) << (NUM_CONVERSION_LIMB_BITS * 2));
grumpkin::fr result(value);
return result;
}

curve::BN254::AffineElement convert_from_bn254_frs(std::span<const bb::fr> fr_vec,
curve::BN254::AffineElement* /*unused*/)
{
curve::BN254::AffineElement val;
val.x = convert_from_bn254_frs<grumpkin::fr>(fr_vec.subspan(0, 2));
val.y = convert_from_bn254_frs<grumpkin::fr>(fr_vec.subspan(2, 2));
return val;
}

curve::Grumpkin::AffineElement convert_from_bn254_frs(std::span<const bb::fr> fr_vec,
curve::Grumpkin::AffineElement* /*unused*/)
{
ASSERT(fr_vec.size() == 2);
curve::Grumpkin::AffineElement val;
val.x = fr_vec[0];
val.y = fr_vec[1];
return val;
}

/**
* @brief Converts grumpkin::fr to 2 bb::fr elements
* @details First, this function must return 2 bb::fr elements because the grumpkin::fr field has a larger modulus than
* the bb::fr field, so we choose to send 1 grumpkin::fr element to 2 bb::fr elements to maintain injectivity.
* This function the reverse of convert_from_bn254_frs(std::span<const bb::fr> fr_vec, grumpkin::fr*) by merging the two
* pairs of limbs back into the 2 bb::fr elements. For the implementation, we want to minimize the number of constraints
* created by the circuit form, which happens to use 68 bit limbs to represent a grumpkin::fr (as a bigfield).
* Therefore, our mapping will split a grumpkin::fr into a 136 bit chunk for the lower two bigfield limbs and the upper
* chunk for the upper two limbs. The upper chunk ends up being 254 - 2*68 = 118 bits as a result. We manipulate the
* value using bitwise masks and shifts to obtain our two chunks.
* @param input
* @return std::array<bb::fr, 2>
*/
std::vector<bb::fr> convert_to_bn254_frs(const grumpkin::fr& val)
{
// Goal is to slice up the 64 bit limbs of grumpkin::fr/uint256_t to mirror the 68 bit limbs of bigfield
// We accomplish this by dividing the grumpkin::fr's value into two 68*2=136 bit pieces.
constexpr uint64_t LOWER_BITS = 2 * NUM_CONVERSION_LIMB_BITS;
constexpr uint256_t LOWER_MASK = (uint256_t(1) << LOWER_BITS) - 1;
auto value = uint256_t(val);
ASSERT(value < (uint256_t(1) << TOTAL_BITS));
std::vector<bb::fr> result(2);
result[0] = static_cast<uint256_t>(value & LOWER_MASK);
result[1] = static_cast<uint256_t>(value >> LOWER_BITS);
ASSERT(static_cast<uint256_t>(result[1]) < (uint256_t(1) << (TOTAL_BITS - LOWER_BITS)));
return result;
}

std::vector<bb::fr> convert_to_bn254_frs(const bb::fr& val)
{
std::vector<bb::fr> fr_vec{ val };
return fr_vec;
}

std::vector<bb::fr> convert_to_bn254_frs(const curve::BN254::AffineElement& val)
{
auto fr_vec_x = convert_to_bn254_frs(val.x);
auto fr_vec_y = convert_to_bn254_frs(val.y);
std::vector<bb::fr> fr_vec(fr_vec_x.begin(), fr_vec_x.end());
fr_vec.insert(fr_vec.end(), fr_vec_y.begin(), fr_vec_y.end());
return fr_vec;
}

std::vector<bb::fr> convert_to_bn254_frs(const curve::Grumpkin::AffineElement& val)
{
auto fr_vec_x = convert_to_bn254_frs(val.x);
auto fr_vec_y = convert_to_bn254_frs(val.y);
std::vector<bb::fr> fr_vec(fr_vec_x.begin(), fr_vec_x.end());
fr_vec.insert(fr_vec.end(), fr_vec_y.begin(), fr_vec_y.end());
return fr_vec;
}

} // namespace bb::field_conversion
Loading
Loading