Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
origin_tag.cpp
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
10#include <cstring>
11#include <string>
12
13namespace bb {
14using namespace numeric;
15#ifndef AZTEC_NO_ORIGIN_TAGS
16
17namespace {
22inline int highest_set_bit_128(uint128_t value)
23{
24 if (value == 0) {
25 return -1;
26 }
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);
31 }
32 // Check low 64 bits
33 auto low = static_cast<uint64_t>(value);
34 return 63 - __builtin_clzll(low);
35}
36
40inline uint128_t extract_uint128(const uint64_t* data)
41{
42 uint128_t result = 0;
43 std::memcpy(&result, data, sizeof(uint128_t));
44 return result;
45}
46} // namespace
47
63void check_round_provenance(const uint256_t& provenance_a, const uint256_t& provenance_b)
64{
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]);
68
69 // Nothing to check if either has no submitted data or both are from the same round(s)
70 if (submitted_a == 0 || submitted_b == 0 || submitted_a == submitted_b) {
71 return;
72 }
73
74 // 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);
79
80 if (max_challenge_round < max_submitted_round) {
81 throw_or_abort("Round provenance check failed: max challenge round (" + std::to_string(max_challenge_round) +
82 ") < max submitted round (" + std::to_string(max_submitted_round) + ")");
83 }
84}
85
86bool OriginTag::operator==(const OriginTag& other) const
87{
88 return this->transcript_index == other.transcript_index && this->round_provenance == other.round_provenance &&
89 this->instant_death == other.instant_death;
90}
91OriginTag::OriginTag(const OriginTag& tag_a, const OriginTag& tag_b)
92{
93 // Elements with instant death should not be touched
94 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));
97 }
98 // If one of the tags is a constant, just use the other tag
99 if (tag_a.transcript_index == CONSTANT) {
100 *this = tag_b;
101 return;
102 }
103 if (tag_b.transcript_index == CONSTANT) {
104 *this = tag_a;
105 return;
106 }
107
108 // A free witness element should not interact with an element that has an origin
109 if (tag_a.is_free_witness()) {
110 if (!tag_b.is_free_witness() && !tag_b.is_empty()) {
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) + ")");
114 } else {
115 // If both are free witnesses or one of them is empty, just use tag_a
116 *this = tag_a;
117 return;
118 }
119 }
120 if (tag_b.is_free_witness()) {
121 if (!tag_a.is_free_witness() && !tag_a.is_empty()) {
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) + ")");
125 } else {
126 // If both are free witnesses or one of them is empty, just use tag_b
127 *this = tag_b;
128 return;
129 }
130 }
131 // Elements from different transcripts shouldn't interact
132 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) + " }");
137 }
138 // Check that submitted values from different rounds don't mix without challenges
140
143}
144
145#else
146bool OriginTag::operator==(const OriginTag&) const
147{
148 return true;
149}
150
151#endif
152} // namespace bb
const std::vector< MemoryValue > data
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
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.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
unsigned __int128 uint128_t
Definition serialize.hpp:45
size_t transcript_index
OriginTag()=default
uint64_t tag_id
static constexpr size_t CONSTANT
bool is_empty() const
bool is_free_witness() const
numeric::uint256_t round_provenance
bool operator==(const OriginTag &other) const
void throw_or_abort(std::string const &err)