Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bitwise_trace.cpp
Go to the documentation of this file.
2
3#include <cstddef>
4#include <cstdint>
5#include <memory>
6#include <ranges>
7#include <stdexcept>
8
14
15namespace bb::avm2::tracegen {
16
19{
20 using C = Column;
21
22 // We activate last selector in the extra pre-pended row (to support shift)
23 trace.set(C::bitwise_last, 0, 1);
24
25 uint32_t row = 1;
26 for (const auto& event : events) {
27 auto tag = event.a.get_tag();
28
29 // We start with full inputs and output and we shift
30 // them byte-per-byte to the right.
31 uint128_t input_a = static_cast<uint128_t>(event.a.as_ff());
32 uint128_t input_b = static_cast<uint128_t>(event.b.as_ff());
33 uint128_t output_c = event.res;
34
35 // Error Handling, check tag a is FF or tag a != tag b
36 bool is_tag_ff = event.a.get_tag() == MemoryTag::FF;
37 bool is_tag_mismatch = event.a.get_tag() != event.b.get_tag();
38 // For tag_a != FF, we subtrace MemoryTag::FF for clarity even thought MemoryTag::FF is 0.
39 FF tag_a_inv =
40 is_tag_ff
41 ? FF(0)
42 : (FF(static_cast<uint8_t>(event.a.get_tag())) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert();
43 // For tag_a != tag_b
44 FF tag_ab_diff_inv =
45 is_tag_mismatch
46 ? (FF(static_cast<uint8_t>(event.a.get_tag())) - FF(static_cast<uint8_t>(event.b.get_tag()))).invert()
47 : FF(0);
48
49 if (is_tag_ff || is_tag_mismatch) {
50 // There is an error, fill in values that are still needed to satisfy constraints despite the error.
51 trace.set(row,
52 { {
53 { C::bitwise_op_id, static_cast<uint8_t>(event.operation) },
54 { C::bitwise_start, 1 },
55 { C::bitwise_sel_get_ctr, 0 },
56 { C::bitwise_last, 1 }, // Error triggers a last
57 { C::bitwise_acc_ia, uint256_t::from_uint128(input_a) },
58 { C::bitwise_acc_ib, uint256_t::from_uint128(input_b) },
59 { C::bitwise_acc_ic, uint256_t::from_uint128(output_c) },
60 { C::bitwise_ia_byte, uint256_t::from_uint128(input_a) },
61 { C::bitwise_ib_byte, uint256_t::from_uint128(input_b) },
62 { C::bitwise_ic_byte, uint256_t::from_uint128(output_c) },
63 { C::bitwise_tag_a, static_cast<uint8_t>(event.a.get_tag()) },
64 { C::bitwise_tag_b, static_cast<uint8_t>(event.b.get_tag()) },
65 { C::bitwise_tag_c, static_cast<uint8_t>(event.a.get_tag()) }, // same as tag_a
66 // Err Flags
67 { C::bitwise_sel_tag_ff_err, is_tag_ff ? 1 : 0 },
68 { C::bitwise_sel_tag_mismatch_err, is_tag_mismatch ? 1 : 0 },
69 { C::bitwise_err, 1 },
70 // Err Helpers
71 { C::bitwise_tag_a_inv, tag_a_inv },
72 { C::bitwise_tag_ab_diff_inv, tag_ab_diff_inv },
73
74 } });
75 row++;
76 continue; // Skip the rest of the processing for this event
77 }
78
79 // At this point we know that we will not error, so we can proceed with the bitwise operation.
80
81 // Note that for tag U1, we take only one bit. This is correctly
82 // captured below since input_a/b and output_c are each a single bit
83 // and the byte mask correctly extracts it.
84 const uint128_t mask_low_byte = (1 << 8) - 1;
85 const auto start_ctr = get_tag_bytes(tag);
86
87 for (int ctr = start_ctr; ctr > 0; ctr--) {
88 bool is_start = (ctr == start_ctr);
89 trace.set(row,
90 { { { C::bitwise_op_id, static_cast<uint8_t>(event.operation) },
91 { C::bitwise_acc_ia, uint256_t::from_uint128(input_a) },
92 { C::bitwise_acc_ib, uint256_t::from_uint128(input_b) },
93 { C::bitwise_acc_ic, uint256_t::from_uint128(output_c) },
94 { C::bitwise_ia_byte, uint256_t::from_uint128(input_a & mask_low_byte) },
95 { C::bitwise_ib_byte, uint256_t::from_uint128(input_b & mask_low_byte) },
96 { C::bitwise_ic_byte, uint256_t::from_uint128(output_c & mask_low_byte) },
97 { C::bitwise_tag_a, is_start ? static_cast<uint8_t>(event.a.get_tag()) : 0 },
98 { C::bitwise_tag_b, is_start ? static_cast<uint8_t>(event.b.get_tag()) : 0 },
99 { C::bitwise_tag_c, is_start ? static_cast<uint8_t>(event.a.get_tag()) : 0 }, // same as tag_a
100 { C::bitwise_ctr, ctr },
101 { C::bitwise_ctr_inv, ctr != 0 ? FF(ctr).invert() : 1 },
102 { C::bitwise_ctr_min_one_inv, ctr != 1 ? FF(ctr - 1).invert() : 1 },
103 { C::bitwise_last, ctr == 1 ? 1 : 0 },
104 { C::bitwise_sel, ctr != 0 ? 1 : 0 },
105 { C::bitwise_start, is_start ? 1 : 0 },
106 { C::bitwise_sel_get_ctr, is_start ? 1 : 0 }, // Same as bitwise_start but in non-error case
107 // Err Helpers, in the happy path we still need to prove we would not have errored
108 { C::bitwise_tag_a_inv, is_start ? tag_a_inv : 0 },
109 { C::bitwise_tag_ab_diff_inv, is_start ? tag_ab_diff_inv : 0 } } });
110
111 input_a >>= 8;
112 input_b >>= 8;
113 output_c >>= 8;
114 row++;
115 }
116 }
117}
118
122 .add<lookup_bitwise_integral_tag_length_settings, InteractionType::LookupIntoIndexedByClk>()
124
125} // namespace bb::avm2::tracegen
void process(const simulation::EventEmitterInterface< simulation::BitwiseEvent >::Container &events, TraceContainer &trace)
static const InteractionDefinition interactions
InteractionDefinition & add(auto &&... args)
static constexpr uint256_t from_uint128(const uint128_t a) noexcept
Definition uint256.hpp:94
TestTraceContainer trace
lookup_settings< lookup_bitwise_byte_operations_settings_ > lookup_bitwise_byte_operations_settings
lookup_settings< lookup_bitwise_dispatch_exec_bitwise_settings_ > lookup_bitwise_dispatch_exec_bitwise_settings
AvmFlavorSettings::FF FF
Definition field.hpp:10
uint8_t get_tag_bytes(ValueTag tag)
simulation::PublicDataTreeReadWriteEvent event
unsigned __int128 uint128_t
Definition serialize.hpp:44