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 1 commit
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
4 changes: 3 additions & 1 deletion barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ WASM_EXPORT void acir_goblin_accumulate(in_ptr acir_composer_ptr,

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

Expand Down
91 changes: 78 additions & 13 deletions barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,111 @@ 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 Checks that each bb::fr must be at most 128 bits (to ensure no overflow), and decomposes each
* bb::fr into two 64-bit limbs, and the 4 64-bit limbs form the 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_bn254_frs_to_grumpkin_fr(const bb::fr& low_bits_in, const bb::fr& high_bits_in)
grumpkin::fr convert_from_bn254_frs(std::span<const bb::fr> fr_vec, grumpkin::fr* /*unused*/)
{
// TODO: figure out can_overflow, maximum_bitlength in stdlib version
// Combines the two elements into one uint256_t, and then convert that to a grumpkin::fr
ASSERT(uint256_t(low_bits_in) < (uint256_t(1) << (NUM_CONVERSION_LIMB_BITS * 2))); // lower 136 bits
ASSERT(uint256_t(high_bits_in) <
(uint256_t(1) << (TOTAL_BITS - NUM_CONVERSION_LIMB_BITS * 2))); // upper 254-136 bits
uint256_t value = uint256_t(low_bits_in) + (uint256_t(high_bits_in) << (NUM_CONVERSION_LIMB_BITS * 2));
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 Does the reverse of convert_barretenberg_frs_to_grumpkin_fr, by merging the two pairs of limbs back into the
* 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::array<bb::fr, 2> convert_grumpkin_fr_to_bn254_frs(const grumpkin::fr& input)
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(input);
auto value = uint256_t(val);
ASSERT(value < (uint256_t(1) << TOTAL_BITS));
std::array<bb::fr, 2> result;
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
122 changes: 41 additions & 81 deletions barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,7 @@
namespace bb::field_conversion {

/**
* @brief Converts 2 bb::fr elements to grumpkin::fr
* @details Checks that each bb::fr must be at most 128 bits (to ensure no overflow), and decomposes each
* bb::fr into two 64-bit limbs, and the 4 64-bit limbs form the grumpkin::fr
* @param low_bits_in
* @param high_bits_in
* @return grumpkin::fr
*/
grumpkin::fr convert_bn254_frs_to_grumpkin_fr(const bb::fr& low_bits_in, const bb::fr& high_bits_in);

/**
* @brief Converts grumpkin::fr to 2 bb::fr elements
* @details Does the reverse of convert_bn254_frs_to_grumpkin_fr, by merging the two pairs of limbs back into the
* 2 bb::fr elements.
* @param input
* @return std::array<bb::fr, 2>
*/
std::array<bb::fr, 2> convert_grumpkin_fr_to_bn254_frs(const grumpkin::fr& input);

/**
* @brief Calculates the size of a types in terms of bb::frs
* @brief Calculates number of bb::fr required to represent the input type
* @details We want to support the following types: bool, size_t, uint32_t, uint64_t, bb::fr, grumpkin::fr,
* curve::BN254::AffineElement, curve::Grumpkin::AffineElement, bb::Univariate<FF, N>, std::array<FF, N>, for
* FF = bb::fr/grumpkin::fr, and N is arbitrary
Expand Down Expand Up @@ -80,55 +61,45 @@ template <typename T> constexpr size_t calc_num_254_frs()
* @brief Conversions from vector of bb::fr elements to transcript types.
* @details We want to support the following types: bool, size_t, uint32_t, uint64_t, bb::fr, grumpkin::fr,
* curve::BN254::AffineElement, curve::Grumpkin::AffineElement, bb::Univariate<FF, N>, std::array<FF, N>, for
* FF = bb::fr/grumpkin::fr, and N is arbitrary
* FF = bb::fr/grumpkin::fr, and N is arbitrary.
* The only nontrivial implementation is the conversion for grumpkin::fr. More details are given in the function comment
* below.
* @tparam T
* @param fr_vec
* @return T
*/
template <typename T> T convert_from_bn254_frs(std::span<const bb::fr> fr_vec);

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

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

inline 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];
}
bb::fr convert_from_bn254_frs(std::span<const bb::fr> fr_vec, bb::fr* /*unused*/);

inline grumpkin::fr convert_from_bn254_frs(std::span<const bb::fr> fr_vec, grumpkin::fr* /*unused*/)
{
ASSERT(fr_vec.size() == 2);
return convert_bn254_frs_to_grumpkin_fr(fr_vec[0], fr_vec[1]);
}
/**
* @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*/);

inline 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::BN254::AffineElement convert_from_bn254_frs(std::span<const bb::fr> fr_vec,
curve::BN254::AffineElement* /*unused*/);

inline 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;
}
curve::Grumpkin::AffineElement convert_from_bn254_frs(std::span<const bb::fr> fr_vec,
curve::Grumpkin::AffineElement* /*unused*/);

template <size_t N>
inline std::array<bb::fr, N> convert_from_bn254_frs(std::span<const bb::fr> fr_vec, std::array<bb::fr, N>* /*unused*/)
Expand Down Expand Up @@ -195,36 +166,26 @@ template <std::integral T> std::vector<bb::fr> inline convert_to_bn254_frs(const
return fr_vec;
}

std::vector<bb::fr> inline convert_to_bn254_frs(const grumpkin::fr& val)
{
auto fr_arr = convert_grumpkin_fr_to_bn254_frs(val);
std::vector<bb::fr> fr_vec(fr_arr.begin(), fr_arr.end());
return fr_vec;
}
/**
* @brief Converts grumpkin::fr to 2 bb::fr elements
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm slightly torn on this because I generally think more documentation is better but I think it's best to only add this level of description to either the declaration OR the definition, not both. It's a bit less clutter that way and it also avoids the two things diverging and causing confusion about the source of truth. Excellent comments here - but maybe only need them in one place

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will put the comment in the definition then since it has implementation details

* @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);

std::vector<bb::fr> inline 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 bb::fr& val);

std::vector<bb::fr> inline 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::BN254::AffineElement& val);

std::vector<bb::fr> inline 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;
}
std::vector<bb::fr> convert_to_bn254_frs(const curve::Grumpkin::AffineElement& val);

template <size_t N> std::vector<bb::fr> inline convert_to_bn254_frs(const std::array<bb::fr, N>& val)
{
Expand Down Expand Up @@ -262,7 +223,6 @@ template <size_t N> std::vector<bb::fr> inline convert_to_bn254_frs(const bb::Un
return fr_vec;
}

// TODO: why is this needed here but not for the other 3 functions?
template <typename AllValues> std::vector<bb::fr> inline convert_to_bn254_frs(const AllValues& val)
{
auto data = val.get_all();
Expand Down
Loading
Loading