1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
80constexpr std::string OPERAND_PREFIX =
"op";
81constexpr std::string BYTE_PREFIX =
"bd";
82constexpr std::string SELECTOR_PREFIX =
"sel_op_dc_";
85constexpr size_t NUM_OF_OPERANDS = 8;
98uint32_t encode_operand_idx_with_layout(uint8_t operand_idx, uint8_t
offset, uint8_t
len)
100 uint32_t layout =
len;
101 layout += (
static_cast<uint32_t
>(
offset) << 8);
102 layout += (
static_cast<uint32_t
>(operand_idx) << 16);
106uint8_t get_op_idx(uint32_t op_idx_with_layout)
108 return static_cast<uint8_t
>(op_idx_with_layout >> 16);
111OperandLayout get_op_layout(uint32_t op_idx_with_layout)
113 uint8_t
offset =
static_cast<uint8_t
>((op_idx_with_layout >> 8) & 0xFF);
114 uint8_t
len =
static_cast<uint8_t
>(op_idx_with_layout & 0xFF);
115 return OperandLayout{ .offset =
offset, .len =
len };
121 for (
const auto& wire_opcode : set) {
122 value += (
static_cast<uint128_t>(1) <<
static_cast<uint8_t
>(wire_opcode));
130 size_t num_of_selectors = sel_bitmasks.size();
131 std::vector<bool> selectors;
132 selectors.reserve(num_of_selectors);
134 for (
const auto& bitmask : sel_bitmasks) {
135 selectors.push_back(((
static_cast<uint128_t>(1) <<
static_cast<uint128_t>(wire_opcode)) & bitmask) != 0);
138 std::string output =
format(
"{", selectors[0]);
139 for (
size_t i = 1; i < num_of_selectors; i++) {
140 output +=
format(
", ", selectors[i]);
146auto add_fold = [](
const std::string&
a,
const std::string&
b) {
return a +
" + " +
b; };
153 for (
const auto& partition : partitions) {
154 output +=
format(
"pol ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.union_subset));
155 output +=
format(
" = ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.subset_1));
156 output +=
format(
" + ", SELECTOR_PREFIX, bitmask_to_sel_idx.at(partition.subset_2),
";\n");
162std::string render_operand_layout_pil(OperandLayout layout)
164 std::vector<std::string> monomials;
165 monomials.reserve(layout.len);
166 uint8_t byte_offset = layout.offset;
167 for (
int i = 0; i < layout.len; i++) {
169 format(BYTE_PREFIX, byte_offset + i + 1,
" * 2**", 8 * (layout.len - i - 1)));
172 return std::accumulate(std::next(monomials.begin()), monomials.end(), monomials[0], add_fold);
175std::string render_pil(
178 std::string pil_equations;
179 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
180 pil_equations += (i == 0) ?
"#[ADDRESSING_MODE_BYTES_DECOMPOSITION]\n"
181 :
format(
"#[OP", static_cast<uint32_t>(i),
"_BYTES_DECOMPOSITION]\n");
182 pil_equations += (i == 0) ?
"addressing_mode = " :
format(OPERAND_PREFIX, static_cast<uint32_t>(i),
" = ");
184 pil_equations +=
"(1 - PARSING_ERROR_EXCEPT_TAG_ERROR) * (";
186 std::vector<std::string> additive_terms;
187 for (
const auto& sel_layout : sel_layout_breakdowns[i]) {
188 additive_terms.push_back(
189 format(SELECTOR_PREFIX, sel_layout.first,
" * (", render_operand_layout_pil(sel_layout.second),
")"));
192 std::accumulate(std::next(additive_terms.begin()), additive_terms.end(), additive_terms[0], add_fold);
193 pil_equations +=
");\n";
195 return pil_equations;
205 for (
const auto& [opcode,
format] : wire_formats) {
208 uint8_t byte_offset = 0;
210 for (
const auto& operand :
format) {
211 const auto operand_len =
static_cast<uint8_t
>(operand_type_sizes.at(operand));
212 const auto op_layout = OperandLayout{ .offset = byte_offset, .len = operand_len };
214 if (operand == OperandType::INDIRECT8 || operand == OperandType::INDIRECT16) {
215 operands_layout_array[0] = op_layout;
217 operands_layout_array[op_idx++] = op_layout;
219 byte_offset += operand_len;
231 for (
const auto& [wire_opcode, operand_layouts] : opcode_to_layouts) {
232 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
233 const auto& layout = operand_layouts[i];
234 if (layout.len != 0) {
235 const auto key = encode_operand_idx_with_layout(i, layout.offset, layout.len);
236 if (op_idx_with_layout_to_subset.contains(
key)) {
237 op_idx_with_layout_to_subset[
key].insert(wire_opcode);
239 op_idx_with_layout_to_subset[
key] = { wire_opcode };
244 return op_idx_with_layout_to_subset;
247TEST(DecompositionSelectors, CodeGen)
251 gen_opcode_to_operands_layout();
256 gen_op_idx_with_layout_to_opcode_subset(opcode_to_layouts);
266 for (
const auto& [op_layout, subset] : op_idx_with_layout_to_subset) {
267 const auto encoded = encode_subset_wire_opcodes(subset);
268 set_of_bitmasks.insert(encoded);
269 op_idx_with_layout_to_bitmask.insert(
std::make_pair(op_layout, encoded));
272 info(
"NUMBER OF SUBSETS: ", set_of_bitmasks.size());
275 bool partition_found =
true;
281 while (partition_found) {
282 for (
auto it1 = set_of_bitmasks.begin(); it1 != set_of_bitmasks.end(); it1++) {
284 for (it2++; it2 != set_of_bitmasks.end(); it2++) {
286 if ((*it1 & *it2) == 0 && set_of_bitmasks.contains(sub_union)) {
287 info(
"PARTITION FOUND! ", *it1,
" ", *it2,
" ", sub_union);
288 partitions.push_back(Partition{ .subset_1 = *it1, .subset_2 = *it2, .union_subset = sub_union });
289 set_of_bitmasks.erase(sub_union);
290 partition_found =
true;
293 partition_found =
false;
295 if (partition_found) {
301 info(
"NUMBER OF SUBSETS AFTER PARTITION REMOVAL: ", set_of_bitmasks.size());
309 info(
"\n#################################");
310 info(
" Precomputed Selectors Table:");
311 info(
"#################################\n");
313 info(
"constexpr size_t NUM_OP_DC_SELECTORS = ", set_of_bitmasks.size(),
";\n\n");
315 info(
"const std::unordered_map<WireOpCode, std::array<uint8_t, NUM_OP_DC_SELECTORS>> WireOpCode_DC_SELECTORS = "
320 const auto wire_opcode =
static_cast<WireOpCode>(i);
321 if (wire_formats.contains(wire_opcode)) {
322 info(
"{WireOpCode::", wire_opcode,
", ", render_selector_array(wire_opcode, bitmasks_vector),
"},");
328 for (
const auto& partition : partitions) {
329 bitmasks_vector.push_back(partition.union_subset);
334 for (
size_t i = 0; i < bitmasks_vector.size(); i++) {
342 for (
const auto& [op_idx_with_layout, bitmask] : op_idx_with_layout_to_bitmask) {
343 uint8_t op_idx = get_op_idx(op_idx_with_layout);
344 OperandLayout layout = get_op_layout(op_idx_with_layout);
345 size_t sel_idx = bitmask_to_sel_idx.at(bitmask);
346 sel_layout_breakdowns[op_idx].emplace_back(
std::make_pair(sel_idx, layout));
350 for (uint8_t i = 0; i < NUM_OF_OPERANDS; i++) {
352 sel_layout_breakdowns[i].begin(),
353 sel_layout_breakdowns[i].end(),
357 info(
"\n##################");
358 info(
"PIL Relations:");
359 info(
"##################\n");
361 info(render_partitions_pil(partitions, bitmask_to_sel_idx));
362 info(render_pil(sel_layout_breakdowns));
std::string format(Args... args)
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
const std::unordered_map< OperandType, uint32_t > & get_operand_type_sizes()
const std::unordered_map< WireOpCode, std::vector< OperandType > > & get_instruction_wire_formats()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t