Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
origin_tag.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
19#include <atomic>
20#include <cstddef>
21#include <iterator>
22#include <ostream>
23#include <type_traits>
24#include <vector>
25
26// Trait to detect if a type is iterable
27template <typename T, typename = void> struct is_iterable : std::false_type {};
28
29// this gets used only when we can call std::begin() and std::end() on that type
30template <typename T>
31struct is_iterable<T, std::void_t<decltype(std::begin(std::declval<T&>())), decltype(std::end(std::declval<T&>()))>>
32 : std::true_type {};
33
34template <typename T> constexpr bool is_iterable_v = is_iterable<T>::value;
35
36#define STANDARD_TESTING_TAGS /*Tags reused in tests*/ \
37 const size_t parent_id = 0; \
38 [[maybe_unused]] const auto clear_tag = OriginTag::constant(); /* A tag representing a constant value */ \
39 [[maybe_unused]] const auto constant_tag = OriginTag::constant(); /* Alias for clear_tag */ \
40 [[maybe_unused]] const auto submitted_value_origin_tag = OriginTag( \
41 parent_id, /*round_id=*/0, /*is_submitted=*/true); /*A tag describing a value submitted in the 0th round*/ \
42 [[maybe_unused]] const auto next_submitted_value_origin_tag = OriginTag( \
43 parent_id, /*round_id=*/1, /*is_submitted=*/true); /*A tag describing a value submitted in the 1st round*/ \
44 [[maybe_unused]] const auto challenge_origin_tag = OriginTag( \
45 parent_id, /*round_id=*/0, /*is_submitted=*/false); /*A tag describing a challenge derived in the 0th round*/ \
46 [[maybe_unused]] const auto next_challenge_tag = OriginTag( \
47 parent_id, /*round_id=*/1, /*is_submitted=*/false); /*A tag describing a challenge derived in the 1st round*/ \
48 [[maybe_unused]] const auto first_two_merged_tag = \
49 OriginTag(submitted_value_origin_tag, \
50 challenge_origin_tag); /*A tag describing a value constructed from values submitted by the prover in \
51 the 0th round and challenges from the same round */ \
52 [[maybe_unused]] const auto first_and_third_merged_tag = \
53 OriginTag(submitted_value_origin_tag, \
54 next_challenge_tag); /* A tag describing a value constructed from values submitted in the 0th round \
55 and challenges computed in the 1st round*/ \
56 [[maybe_unused]] const auto first_second_third_merged_tag = OriginTag( \
57 first_two_merged_tag, next_challenge_tag); /* A tag describing a value computed from values submitted in the \
58 0th round and challenges generated in the 0th and 1st round*/ \
59 [[maybe_unused]] const auto first_to_fourth_merged_tag = \
60 OriginTag(first_second_third_merged_tag, \
61 next_submitted_value_origin_tag); /* A tag describing a value computed from values submitted in the \
62 0th and 1st round and challenges generated in the 0th and 1st round*/ \
63 [[maybe_unused]] const auto instant_death_tag = \
64 OriginTag::poisoned(); /* A tag that causes an abort on any arithmetic*/
65
66namespace bb {
67
68void check_round_provenance(const uint256_t& provenance_a, const uint256_t& provenance_b);
69#ifndef AZTEC_NO_ORIGIN_TAGS
70struct OriginTag {
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
77 static constexpr size_t CONSTANT = static_cast<size_t>(-1);
78 static constexpr size_t FREE_WITNESS = static_cast<size_t>(-2);
79 // transcript_index represents the index of a unique transcript object that generated the value. It uses
80 // a concrete index, not bits for now, since we never expect two different indices to be used in the same
81 // computation apart from equality assertion
82 // transcript_index is set to CONSTANT if the value is just a constant
83 // transcript_index is set to FREE_WITNESS if the value is a free witness (not a constant and not from the
84 // transcript)
85 // NOTE: The default is FREE_WITNESS so that if we forget to set the tag, it will be treated as a witness,
86 // which is safer (can trigger errors if misused) than treating it as a constant (which would be silently accepted)
88
89 // 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
92 // represents the round)
94
95 // Instant death is used for poisoning values we should never use in arithmetic
96 bool instant_death = false;
98 // Default Origin Tag has everything set to zero and can't cause any issues
99 OriginTag() = default;
100 OriginTag(const OriginTag& other) = default;
101 OriginTag(OriginTag&& other) = default;
102 OriginTag& operator=(const OriginTag& other) = default;
103 OriginTag& operator=(OriginTag&& other) noexcept
104 {
105 tag_id = other.tag_id;
106 transcript_index = other.transcript_index;
107 round_provenance = other.round_provenance;
108 instant_death = other.instant_death;
109 return *this;
110 }
118 OriginTag(size_t transcript_idx, size_t round_number, bool is_submitted = true)
119 : transcript_index(transcript_idx)
120 , round_provenance((static_cast<uint256_t>(1) << (round_number + (is_submitted ? 0 : 128))))
121 {
122 BB_ASSERT_LT(round_number, 128U);
123 }
124
134 OriginTag(const OriginTag& tag_a, const OriginTag& tag_b);
135
145 template <class... T>
146 OriginTag(const OriginTag& tag, const T&... rest)
150 {
151
152 OriginTag merged_tag = *this;
153 for (const auto& next_tag : { rest... }) {
154 merged_tag = OriginTag(merged_tag, next_tag);
155 }
156 *this = merged_tag;
158 ~OriginTag() = default;
159 bool operator==(const OriginTag& other) const;
160 void poison() { instant_death = true; }
161 void unpoison() { instant_death = false; }
162 bool is_poisoned() const { return instant_death; }
163 bool is_empty() const { return !instant_death && transcript_index == CONSTANT; };
164
165 bool is_free_witness() const { return transcript_index == FREE_WITNESS; }
166 void set_free_witness()
172 {
175 }
176
177 bool is_constant() const { return transcript_index == CONSTANT && !instant_death; }
178 void set_constant()
179 {
182 }
183
184 // Static factory methods for cleaner syntax
185 static OriginTag constant()
186 {
189 return tag;
190 }
191
192 static OriginTag free_witness()
193 {
196 return tag;
197 }
198
199 static OriginTag poisoned()
200 {
202 tag.instant_death = true;
203 return tag;
204 }
210};
211inline std::ostream& operator<<(std::ostream& os, OriginTag const& v)
212{
213 return os << "{ id: " << v.tag_id << ", transcript_idx: " << v.transcript_index
214 << ", round_prov: " << v.round_provenance << ", instadeath: " << v.instant_death << " }";
215}
216
217#else
218
219struct OriginTag {
220 OriginTag() = default;
221 OriginTag(const OriginTag& other) = default;
222 OriginTag(OriginTag&& other) = default;
223 OriginTag& operator=(const OriginTag& other) = default;
224 OriginTag& operator=(OriginTag&& other) = default;
225 ~OriginTag() = default;
226
227 OriginTag(size_t transcript_idx [[maybe_unused]],
228 size_t round_number [[maybe_unused]],
229 bool is_submitted [[maybe_unused]] = true)
230 {}
231
232 OriginTag(const OriginTag&, const OriginTag&) {}
233 template <class... T> OriginTag(const OriginTag&, const T&...) {}
234 bool operator==(const OriginTag& other) const;
235 void poison() {}
236 void unpoison() {}
237 static bool is_poisoned() { return false; }
238 static bool is_empty() { return true; };
239 bool is_free_witness() const { return false; }
240 void set_free_witness() {}
241 void unset_free_witness() {}
242 bool is_constant() const { return true; }
243 void set_constant() {}
244 void clear_round_provenance() {}
245
246 // Static factory methods (no-ops in release builds)
247 static OriginTag constant() { return OriginTag(); }
248 static OriginTag free_witness() { return OriginTag(); }
249 static OriginTag poisoned() { return OriginTag(); }
250};
251inline std::ostream& operator<<(std::ostream& os, OriginTag const&)
252{
253 return os << "{ Origin Tag tracking is disabled in release builds }";
254}
255#endif
256
257// Helper functions for working with origin tags
266template <bool in_circuit, typename T> inline void assign_origin_tag(T& elem, const OriginTag& tag)
267{
268 if constexpr (in_circuit) {
269 if constexpr (is_iterable_v<T>) {
270 for (auto& e : elem) {
271 e.set_origin_tag(tag);
272 }
273 } else {
274 elem.set_origin_tag(tag);
275 }
276 }
277}
278
287template <bool in_circuit, typename T> inline void check_origin_tag(T& elem, const OriginTag& tag)
288{
289 if constexpr (in_circuit) {
290 if constexpr (is_iterable_v<T>) {
291 for (auto& e : elem) {
292 BB_ASSERT(e.get_origin_tag() == tag);
293 };
294 } else {
295 BB_ASSERT(elem.get_origin_tag() == tag);
296 }
297 }
298}
299
307template <bool in_circuit, typename DataType> inline void unset_free_witness_tags(std::vector<DataType>& input)
308{
309 if constexpr (in_circuit) {
310 for (auto& entry : input) {
311 entry.unset_free_witness_tag();
312 }
313 }
314}
315
326template <bool in_circuit, typename Codec, typename T>
327inline std::vector<typename Codec::DataType> tag_and_serialize(const T& component, const OriginTag& tag)
328{
329 if constexpr (in_circuit) {
330 assign_origin_tag<in_circuit>(const_cast<T&>(component), tag);
331 }
332 // Serialize to field elements
333 return Codec::serialize_to_fields(component);
334}
335
344template <typename TranscriptType> inline OriginTag extract_transcript_tag(const TranscriptType& transcript)
345{
346 return OriginTag(transcript.transcript_index, transcript.round_index, /*is_submitted=*/true);
348
349} // namespace bb
350template <typename T>
351concept usesTag = requires(T x, const bb::OriginTag& tag) { x.set_origin_tag(tag); };
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
std::ostream & operator<<(std::ostream &os, uint256_t const &a)
Definition uint256.hpp:258
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< typename Codec::DataType > tag_and_serialize(const T &component, const OriginTag &tag)
Tag a component with a given origin tag and serialize it to field elements.
void check_round_provenance(const uint256_t &provenance_a, const uint256_t &provenance_b)
Detect if two elements from the same transcript are performing a suspicious interaction.
OriginTag extract_transcript_tag(const TranscriptType &transcript)
Extract origin tag context from a transcript.
void unset_free_witness_tags(std::vector< DataType > &input)
Unsets free witness tags on all elements in a vector.
void assign_origin_tag(T &elem, const OriginTag &tag)
Assigns an origin tag to an element or all elements in an iterable container.
void check_origin_tag(T &elem, const OriginTag &tag)
Checks that an element or all elements in an iterable container have the expected origin tag.
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
constexpr bool is_iterable_v
size_t transcript_index
void unset_free_witness()
OriginTag()=default
static OriginTag constant()
bool is_poisoned() const
void set_constant()
~OriginTag()=default
static std::atomic< uint64_t > next_tag_id
static OriginTag poisoned()
uint64_t tag_id
void set_free_witness()
static constexpr size_t CONSTANT
OriginTag & operator=(const OriginTag &other)=default
static constexpr size_t FREE_WITNESS
bool is_constant() const
bool is_empty() const
void clear_round_provenance()
Clear the round_provenance to address round provenance false positives.
bool is_free_witness() const
numeric::uint256_t round_provenance
static OriginTag free_witness()
bool operator==(const OriginTag &other) const