Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
fixed_base.test.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#include "fixed_base.hpp"
10#include <gtest/gtest.h>
11
13
14class FixedBaseTableTest : public ::testing::Test {
15 protected:
19};
20
30TEST_F(FixedBaseTableTest, GeneratorPointsAndBasePointRelationships)
31{
32 const auto lhs_gen = table::lhs_generator_point();
33 const auto rhs_gen = table::rhs_generator_point();
34
35 const auto lhs_lo = table::lhs_base_point_lo();
36 const auto lhs_hi = table::lhs_base_point_hi();
37 const auto rhs_lo = table::rhs_base_point_lo();
38 const auto rhs_hi = table::rhs_base_point_hi();
39
40 // Both generators must be valid points on the Grumpkin curve
41 EXPECT_TRUE(lhs_gen.on_curve());
42 EXPECT_TRUE(rhs_gen.on_curve());
43
44 // LHS and RHS generators must be different points
45 EXPECT_NE(lhs_gen, rhs_gen);
46
47 // The "lo" base points (for the low 128 bits of the scalar) should be the same as the generators themselves
48 EXPECT_EQ(lhs_lo, lhs_gen);
49 EXPECT_EQ(rhs_lo, rhs_gen);
50
51 // The "hi" base points should be the "lo" points multiplied by 2^128
52 EXPECT_EQ(lhs_hi, affine_element(element(lhs_lo) * table::MAX_LO_SCALAR));
53 EXPECT_EQ(rhs_hi, affine_element(element(rhs_lo) * table::MAX_LO_SCALAR));
54}
55
63TEST_F(FixedBaseTableTest, LookupTableGenerationCorrectness)
64{
65 const auto base_point = table::lhs_generator_point();
66 const auto offset_gen = grumpkin::g1::affine_one;
67 const auto lookup_table = table::generate_single_lookup_table(base_point, offset_gen);
68
69 // Table should have exactly MAX_TABLE_SIZE (512) entries for 9-bit lookups
70 EXPECT_EQ(lookup_table.size(), table::MAX_TABLE_SIZE);
71
72 // Verify every entry follows the pattern: table[i] = offset_gen + i * base_point
73 // This allows us to compute k * base_point by looking up table[k] and subtracting offset_gen
74 for (size_t i = 0; i < lookup_table.size(); ++i) {
75 element expected = element(offset_gen) + element(base_point) * i;
76 EXPECT_EQ(lookup_table[i], affine_element(expected));
77
78 // Every point in the table must be a valid curve point
79 EXPECT_TRUE(lookup_table[i].on_curve());
80 }
81}
82
94TEST_F(FixedBaseTableTest, MultiTableStructureAndOffsets)
95{
96 const auto& all_tables = table::fixed_base_tables();
97 const auto& offset_gens = table::fixed_base_table_offset_generators();
98
99 // We should have exactly 4 multi-tables: LHS_LO, LHS_HI, RHS_LO, RHS_HI
100 EXPECT_EQ(all_tables.size(), table::NUM_FIXED_BASE_MULTI_TABLES);
101
102 // LO multi-tables have 15 sub-tables (14 full 9-bit tables + 1 partial 2-bit table)
103 EXPECT_EQ(all_tables[0].size(), table::NUM_TABLES_PER_LO_MULTITABLE); // LHS_LO
104 EXPECT_EQ(all_tables[2].size(), table::NUM_TABLES_PER_LO_MULTITABLE); // RHS_LO
105
106 // HI multi-tables have 14 sub-tables (all full 9-bit tables)
107 EXPECT_EQ(all_tables[1].size(), table::NUM_TABLES_PER_HI_MULTITABLE); // LHS_HI
108 EXPECT_EQ(all_tables[3].size(), table::NUM_TABLES_PER_HI_MULTITABLE); // RHS_HI
109
110 // Verify that every sub-table has the correct size and contains valid curve points
111 // Note: Even partial tables allocate full MAX_TABLE_SIZE for consistency
112 for (const auto& multi_table : all_tables) {
113 for (const auto& sub_table : multi_table) {
114 EXPECT_EQ(sub_table.size(), table::MAX_TABLE_SIZE);
115
116 // Every point in every table must be a valid curve point
117 for (const auto& point : sub_table) {
118 EXPECT_TRUE(point.on_curve());
119 }
120 }
121 }
122
123 // There should be one offset generator per multi-table
124 EXPECT_EQ(offset_gens.size(), table::NUM_FIXED_BASE_MULTI_TABLES);
125
126 // Each offset generator should match what compute_generator_offset produces
127 EXPECT_EQ(offset_gens[0], table::compute_generator_offset<table::BITS_PER_LO_SCALAR>(table::lhs_base_point_lo()));
128 EXPECT_EQ(offset_gens[1], table::compute_generator_offset<table::BITS_PER_HI_SCALAR>(table::lhs_base_point_hi()));
129 EXPECT_EQ(offset_gens[2], table::compute_generator_offset<table::BITS_PER_LO_SCALAR>(table::rhs_base_point_lo()));
130 EXPECT_EQ(offset_gens[3], table::compute_generator_offset<table::BITS_PER_HI_SCALAR>(table::rhs_base_point_hi()));
131
132 // Verify that get_generator_offset_for_table_id returns the correct offset for each multi-table ID
137}
138
146TEST_F(FixedBaseTableTest, TableGenerationAndValueRetrieval)
147{
148 // Generate a basic table for the first LHS_LO sub-table
149 auto basic_table =
150 table::generate_basic_fixed_base_table<0>(FIXED_BASE_0_0, /*basic_table_index=*/0, /*table_index=*/0);
151
152 // The lookup function should be properly initialized
153 EXPECT_NE(basic_table.get_values_from_key, nullptr);
154
155 // Column 1 should contain sequential indices from 0 to MAX_TABLE_SIZE-1
156 // These indices correspond to the scalar values being looked up
157 for (size_t i = 0; i < basic_table.column_1.size(); ++i) {
158 EXPECT_EQ(basic_table.column_1[i], bb::fr(i));
159 }
160
161 // Test that value retrieval works correctly for various indices
162 // The key format is {index, 0} where the second element is unused for fixed base tables
163 for (size_t test_idx : { size_t(0), size_t(5), size_t(100), table::MAX_TABLE_SIZE - 1 }) {
164 std::array<uint64_t, 2> test_key = { test_idx, 0 };
165 auto values = basic_table.get_values_from_key(test_key);
166
167 // The returned values should be the x and y coordinates at the given index
168 EXPECT_EQ(values[0], basic_table.column_2[test_idx]); // x-coordinate
169 EXPECT_EQ(values[1], basic_table.column_3[test_idx]); // y-coordinate
170 }
171
172 // Test multi-table generation for the LHS_LO multi-table
173 auto multi_table = table::get_fixed_base_table<0, table::BITS_PER_LO_SCALAR>(FIXED_BASE_LEFT_LO);
174
175 // Verify the multi-table has the correct ID and number of sub-tables
176 EXPECT_EQ(multi_table.id, FIXED_BASE_LEFT_LO);
177 EXPECT_EQ(multi_table.basic_table_ids.size(), table::NUM_TABLES_PER_LO_MULTITABLE);
178 EXPECT_EQ(multi_table.get_table_values.size(), table::NUM_TABLES_PER_LO_MULTITABLE);
179
180 // Each sub-table should have a valid lookup function and the correct slice size
181 // Even the last table (which only uses 2 bits) reports MAX_TABLE_SIZE for consistency
182 for (size_t i = 0; i < multi_table.get_table_values.size(); ++i) {
183 EXPECT_NE(multi_table.get_table_values[i], nullptr);
184 EXPECT_EQ(multi_table.slice_sizes[i], table::MAX_TABLE_SIZE);
185 }
186}
187
198TEST_F(FixedBaseTableTest, PartialTableHandling)
199{
200 // E.g. the last table in LHS_LO handles only 2 bits, so it should have 2^2 = 4 entries
201 size_t last_table_idx_lo = table::NUM_TABLES_PER_LO_MULTITABLE - 1;
202 auto basic_table = table::generate_basic_fixed_base_table</*multitable_index=*/0>(
203 static_cast<BasicTableId>(FIXED_BASE_0_0 + last_table_idx_lo), last_table_idx_lo, last_table_idx_lo);
204 EXPECT_EQ(basic_table.column_1.size(), 4);
205
206 // The last table in LHS_HI handles a full 9 bits, so it should have 2^9 = 512 entries
207 // 126 bits divides evenly by 9, so all HI tables are full-sized
208 size_t last_table_idx_hi = table::NUM_TABLES_PER_HI_MULTITABLE - 1;
209 auto hi_basic_table = table::generate_basic_fixed_base_table<1>(
210 static_cast<BasicTableId>(FIXED_BASE_1_0 + last_table_idx_hi), last_table_idx_hi, last_table_idx_hi);
211 EXPECT_EQ(hi_basic_table.column_1.size(), table::MAX_TABLE_SIZE);
212}
213
214} // namespace bb::plookup::fixed_base
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
group_elements::affine_element< Fq, Fr, Params > affine_element
Definition group.hpp:42
static constexpr affine_element affine_one
Definition group.hpp:48
group_elements::element< Fq, Fr, Params > element
Definition group.hpp:41
static affine_element get_generator_offset_for_table_id(MultiTableId table_id)
Given a table id, return the offset generator term that will be present in the final scalar mul outpu...
static constexpr uint256_t MAX_LO_SCALAR
static constexpr affine_element rhs_generator_point()
static single_lookup_table generate_single_lookup_table(const affine_element &base_point, const affine_element &offset_generator)
Given a base_point [P] and an offset_generator [G], compute a lookup table of MAX_TABLE_SIZE that con...
static const all_multi_tables & fixed_base_tables()
static affine_element lhs_base_point_lo()
static affine_element rhs_base_point_lo()
static const std::array< affine_element, table::NUM_FIXED_BASE_MULTI_TABLES > & fixed_base_table_offset_generators()
offset generators!
static affine_element lhs_base_point_hi()
static BasicTable generate_basic_fixed_base_table(BasicTableId id, size_t basic_table_index, size_t table_index)
Generate a single fixed-base-scalar-mul plookup table.
static constexpr affine_element lhs_generator_point()
static affine_element rhs_base_point_hi()
grumpkin::g1::affine_element affine_element
Definition c_bind.hpp:15
TEST_F(FixedBaseTableTest, GeneratorPointsAndBasePointRelationships)
Test that generator points are correctly initialized and have the expected relationships.
@ FIXED_BASE_0_0
Definition types.hpp:68
@ FIXED_BASE_1_0
Definition types.hpp:69
@ FIXED_BASE_RIGHT_HI
Definition types.hpp:103
@ FIXED_BASE_LEFT_LO
Definition types.hpp:100
@ FIXED_BASE_LEFT_HI
Definition types.hpp:101
@ FIXED_BASE_RIGHT_LO
Definition types.hpp:102
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr size_t NUM_FIXED_BASE_MULTI_TABLES
static constexpr size_t MAX_TABLE_SIZE
static constexpr size_t NUM_TABLES_PER_HI_MULTITABLE
static constexpr size_t NUM_TABLES_PER_LO_MULTITABLE