Skip to content

Commit b2519dc

Browse files
Raise origin tags to uint256
1 parent e78af23 commit b2519dc

2 files changed

Lines changed: 44 additions & 52 deletions

File tree

barretenberg/cpp/src/barretenberg/transcript/origin_tag.cpp

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,36 @@ using namespace numeric;
1616

1717
namespace {
1818
/**
19-
* @brief Find the position of the highest set bit in a uint128_t
20-
* @return -1 if no bits are set, otherwise the bit position (0-127)
19+
* @brief Find the position of the highest set bit in a uint256_t
20+
* @return -1 if no bits are set, otherwise the bit position (0-255)
2121
*/
22-
inline int highest_set_bit_128(uint128_t value)
22+
inline int highest_set_bit_256(uint256_t value)
2323
{
2424
if (value == 0) {
2525
return -1;
2626
}
27-
// Check high 64 bits first
28-
auto high = static_cast<uint64_t>(value >> 64);
29-
if (high != 0) {
30-
return 127 - __builtin_clzll(high);
27+
// Check high bits first, then go down
28+
for (int idx = 0; idx < 3; idx++) {
29+
auto chunk = static_cast<uint64_t>(value >> 64 * (3 - idx));
30+
if (chunk != 0) {
31+
return 255 - (idx * 64) - __builtin_clzll(chunk);
32+
}
3133
}
32-
// Check low 64 bits
33-
auto low = static_cast<uint64_t>(value);
34-
return 63 - __builtin_clzll(low);
34+
35+
// Lowest bits
36+
auto chunk = static_cast<uint64_t>(value);
37+
return 63 - __builtin_clzll(chunk);
3538
}
3639

3740
/**
38-
* @brief Safely extract uint128_t from uint256_t data array using memcpy to avoid strict aliasing issues
41+
* @brief Safely extract uint256_t from uint512_t data array using memcpy to avoid strict aliasing issues
3942
*/
40-
inline uint128_t extract_uint128(const uint64_t* data)
43+
inline uint256_t extract_uint256(const uint256_t& data)
4144
{
42-
uint128_t result = 0;
43-
std::memcpy(&result, data, sizeof(uint128_t));
45+
uint256_t result = 0;
46+
for (size_t idx = 0; idx < 4; ++idx) {
47+
std::memcpy(&result.data[idx], &data.data[idx], sizeof(uint64_t));
48+
}
4449
return result;
4550
}
4651
} // namespace
@@ -60,22 +65,22 @@ inline uint128_t extract_uint128(const uint64_t* data)
6065
* @param provenance_a Round provenance of first element
6166
* @param provenance_b Round provenance of second element
6267
*/
63-
void check_round_provenance(const uint256_t& provenance_a, const uint256_t& provenance_b)
68+
void check_round_provenance(const uint512_t& provenance_a, const uint512_t& provenance_b)
6469
{
65-
// Lower 128 bits = submitted rounds, Upper 128 bits = challenge rounds
66-
const auto submitted_a = extract_uint128(&provenance_a.data[0]);
67-
const auto submitted_b = extract_uint128(&provenance_b.data[0]);
70+
// Lower 256 bits = submitted rounds, Upper 256 bits = challenge rounds
71+
const auto submitted_a = extract_uint256(provenance_a.lo);
72+
const auto submitted_b = extract_uint256(provenance_b.lo);
6873

6974
// Nothing to check if either has no submitted data or both are from the same round(s)
7075
if (submitted_a == 0 || submitted_b == 0 || submitted_a == submitted_b) {
7176
return;
7277
}
7378

7479
// Ensure that values from different rounds are not mixing without max challenge round >= max submitted round
75-
const auto challenges_a = extract_uint128(&provenance_a.data[2]);
76-
const auto challenges_b = extract_uint128(&provenance_b.data[2]);
77-
const int max_challenge_round = highest_set_bit_128(challenges_a | challenges_b);
78-
const int max_submitted_round = highest_set_bit_128(submitted_a | submitted_b);
80+
const auto challenges_a = extract_uint256(provenance_a.hi);
81+
const auto challenges_b = extract_uint256(provenance_b.hi);
82+
const int max_challenge_round = highest_set_bit_256(challenges_a | challenges_b);
83+
const int max_submitted_round = highest_set_bit_256(submitted_a | submitted_b);
7984

8085
if (max_challenge_round < max_submitted_round) {
8186
throw_or_abort("Round provenance check failed: max challenge round (" + std::to_string(max_challenge_round) +
@@ -92,8 +97,7 @@ OriginTag::OriginTag(const OriginTag& tag_a, const OriginTag& tag_b)
9297
{
9398
// Elements with instant death should not be touched
9499
if (tag_a.instant_death || tag_b.instant_death) {
95-
throw_or_abort("Touched an element that should not have been touched. tag_a id: " +
96-
std::to_string(tag_a.tag_id) + ", tag_b id: " + std::to_string(tag_b.tag_id));
100+
throw_or_abort("Touched an element that should not have been touched");
97101
}
98102
// If one of the tags is a constant, just use the other tag
99103
if (tag_a.transcript_index == CONSTANT) {
@@ -108,9 +112,7 @@ OriginTag::OriginTag(const OriginTag& tag_a, const OriginTag& tag_b)
108112
// A free witness element should not interact with an element that has an origin
109113
if (tag_a.is_free_witness()) {
110114
if (!tag_b.is_free_witness() && !tag_b.is_empty()) {
111-
throw_or_abort(
112-
"A free witness element (id: " + std::to_string(tag_a.tag_id) +
113-
") should not interact with an element that has an origin (id: " + std::to_string(tag_b.tag_id) + ")");
115+
throw_or_abort("A free witness element should not interact with an element that has an origin");
114116
} else {
115117
// If both are free witnesses or one of them is empty, just use tag_a
116118
*this = tag_a;
@@ -119,9 +121,7 @@ OriginTag::OriginTag(const OriginTag& tag_a, const OriginTag& tag_b)
119121
}
120122
if (tag_b.is_free_witness()) {
121123
if (!tag_a.is_free_witness() && !tag_a.is_empty()) {
122-
throw_or_abort(
123-
"A free witness element (id: " + std::to_string(tag_b.tag_id) +
124-
") should not interact with an element that has an origin (id: " + std::to_string(tag_a.tag_id) + ")");
124+
throw_or_abort("A free witness element should not interact with an element that has an origin");
125125
} else {
126126
// If both are free witnesses or one of them is empty, just use tag_b
127127
*this = tag_b;
@@ -130,10 +130,7 @@ OriginTag::OriginTag(const OriginTag& tag_a, const OriginTag& tag_b)
130130
}
131131
// Elements from different transcripts shouldn't interact
132132
if (tag_a.transcript_index != tag_b.transcript_index) {
133-
throw_or_abort("Tags from different transcripts were involved in the same computation. tag_a: { id: " +
134-
std::to_string(tag_a.tag_id) + ", transcript: " + std::to_string(tag_a.transcript_index) +
135-
" } tag_b: { id: " + std::to_string(tag_b.tag_id) +
136-
", transcript: " + std::to_string(tag_b.transcript_index) + " }");
133+
throw_or_abort("Tags from different transcripts were involved in the same computation");
137134
}
138135
// Check that submitted values from different rounds don't mix without challenges
139136
check_round_provenance(tag_a.round_provenance, tag_b.round_provenance);

barretenberg/cpp/src/barretenberg/transcript/origin_tag.hpp

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "barretenberg/common/assert.hpp"
1717
#include "barretenberg/common/throw_or_abort.hpp"
1818
#include "barretenberg/numeric/uint256/uint256.hpp"
19-
#include <atomic>
19+
#include "barretenberg/numeric/uintx/uintx.hpp"
2020
#include <cstddef>
2121
#include <iterator>
2222
#include <ostream>
@@ -65,15 +65,10 @@ template <typename T> constexpr bool is_iterable_v = is_iterable<T>::value;
6565

6666
namespace bb {
6767

68-
void check_round_provenance(const uint256_t& provenance_a, const uint256_t& provenance_b);
68+
void check_round_provenance(const uint512_t& provenance_a, const uint512_t& provenance_b);
6969
#ifndef AZTEC_NO_ORIGIN_TAGS
7070
struct OriginTag {
7171

72-
// Unique per-object ID for debugging: when a tag merge fails, the error message includes
73-
// the IDs of both tags so you can trace which specific field elements were involved.
74-
static inline std::atomic<uint64_t> next_tag_id{ 0 };
75-
uint64_t tag_id = next_tag_id.fetch_add(1, std::memory_order_relaxed);
76-
7772
static constexpr size_t CONSTANT = static_cast<size_t>(-1);
7873
static constexpr size_t FREE_WITNESS = static_cast<size_t>(-2);
7974
// transcript_index represents the index of a unique transcript object that generated the value. It uses
@@ -87,10 +82,10 @@ struct OriginTag {
8782
size_t transcript_index = FREE_WITNESS;
8883

8984
// round_provenance specifies which submitted values and challenges have been used to generate this element
90-
// The lower 128 bits represent using a submitted value from a corresponding round (the shift represents the
91-
// round) The higher 128 bits represent using a challenge value from an corresponding round (the shift
85+
// The lower 256 bits represent using a submitted value from a corresponding round (the shift represents the
86+
// round) The higher 256 bits represent using a challenge value from an corresponding round (the shift
9287
// represents the round)
93-
numeric::uint256_t round_provenance = numeric::uint256_t(0);
88+
numeric::uint512_t round_provenance = numeric::uint512_t(0);
9489

9590
// Instant death is used for poisoning values we should never use in arithmetic
9691
bool instant_death = false;
@@ -102,7 +97,7 @@ struct OriginTag {
10297
OriginTag& operator=(const OriginTag& other) = default;
10398
OriginTag& operator=(OriginTag&& other) noexcept
10499
{
105-
tag_id = other.tag_id;
100+
106101
transcript_index = other.transcript_index;
107102
round_provenance = other.round_provenance;
108103
instant_death = other.instant_death;
@@ -117,9 +112,9 @@ struct OriginTag {
117112
*/
118113
OriginTag(size_t transcript_idx, size_t round_number, bool is_submitted = true)
119114
: transcript_index(transcript_idx)
120-
, round_provenance((static_cast<uint256_t>(1) << (round_number + (is_submitted ? 0 : 128))))
115+
, round_provenance((static_cast<uint512_t>(1) << (round_number + (is_submitted ? 0 : 256))))
121116
{
122-
// BB_ASSERT_LT(round_number, 128U);
117+
BB_ASSERT_LT(round_number, 256U);
123118
}
124119

125120
/**
@@ -171,14 +166,14 @@ struct OriginTag {
171166
void unset_free_witness()
172167
{
173168
transcript_index = CONSTANT;
174-
round_provenance = numeric::uint256_t(0);
169+
round_provenance = numeric::uint512_t(0);
175170
}
176171

177172
bool is_constant() const { return transcript_index == CONSTANT && !instant_death; }
178173
void set_constant()
179174
{
180175
transcript_index = CONSTANT;
181-
round_provenance = numeric::uint256_t(0);
176+
round_provenance = numeric::uint512_t(0);
182177
}
183178

184179
// Static factory methods for cleaner syntax
@@ -206,12 +201,12 @@ struct OriginTag {
206201
/**
207202
* @brief Clear the round_provenance to address round provenance false positives.
208203
*/
209-
void clear_round_provenance() { round_provenance = numeric::uint256_t(0); }
204+
void clear_round_provenance() { round_provenance = numeric::uint512_t(0); }
210205
};
211206
inline std::ostream& operator<<(std::ostream& os, OriginTag const& v)
212207
{
213-
return os << "{ id: " << v.tag_id << ", transcript_idx: " << v.transcript_index
214-
<< ", round_prov: " << v.round_provenance << ", instadeath: " << v.instant_death << " }";
208+
return os << "{ transcript_idx: " << v.transcript_index << ", round_prov: " << v.round_provenance
209+
<< ", instadeath: " << v.instant_death << " }";
215210
}
216211

217212
#else

0 commit comments

Comments
 (0)