Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
straus_lookup_table.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
8#include "./cycle_group.hpp"
10
11namespace bb::stdlib {
12
26template <typename Builder>
28 Builder>::compute_straus_lookup_table_hints(const Element& base_point,
29 const Element& offset_generator,
30 size_t table_bits)
31{
32 const size_t table_size = 1UL << table_bits;
33 Element base = base_point.is_point_at_infinity() ? Group::one : base_point;
34 std::vector<Element> hints;
35 hints.emplace_back(offset_generator);
36 for (size_t i = 1; i < table_size; ++i) {
37 hints.emplace_back(hints[i - 1] + base);
38 }
39 return hints;
40}
41
56template <typename Builder>
58 const cycle_group<Builder>& base_point,
59 const cycle_group<Builder>& offset_generator,
60 size_t table_bits,
62 : _table_bits(table_bits)
63 , _context(context)
64 , tag(OriginTag(base_point.get_origin_tag(), offset_generator.get_origin_tag()))
65{
66 constexpr bool IS_ULTRA = Builder::CIRCUIT_TYPE == CircuitType::ULTRA;
67
68 const size_t table_size = 1UL << table_bits;
69 point_table.resize(table_size);
70 point_table[0] = offset_generator;
71
72 // We want to support the case where input points are points at infinity.
73 // If base point is at infinity, we want every point in the table to just be `generator_point`.
74 // We achieve this via the following:
75 // 1: We create a "work_point" that is base_point if not at infinity, otherwise is just 1
76 // 2: When computing the point table, we use "work_point" in additions instead of the "base_point" (to prevent
77 // x-coordinate collisions in honest case) 3: When assigning to the point table, we conditionally assign either
78 // the output of the point addition (if not at infinity) or the generator point (if at infinity)
79 // Note: if `base_point.is_point_at_infinity()` is constant, these conditional assigns produce zero gate overhead
80 cycle_group<Builder> fallback_point(Group::affine_one);
81 field_t modded_x = field_t::conditional_assign(base_point.is_point_at_infinity(), fallback_point.x, base_point.x);
82 field_t modded_y = field_t::conditional_assign(base_point.is_point_at_infinity(), fallback_point.y, base_point.y);
83 cycle_group<Builder> modded_base_point(modded_x, modded_y, false);
84
85 // if the input point is constant, it is cheaper to fix the point as a witness and then derive the table, than it is
86 // to derive the table and fix its witnesses to be constant! (due to group additions = 1 gate, and fixing x/y coords
87 // to be constant = 2 gates)
88 if (base_point.is_constant() && !base_point.is_point_at_infinity().get_value()) {
89 modded_base_point = cycle_group<Builder>::from_constant_witness(_context, modded_base_point.get_value());
91 for (size_t i = 1; i < table_size; ++i) {
93 hints.has_value() ? std::optional<AffineElement>(hints.value()[i - 1]) : std::nullopt;
94 point_table[i] = point_table[i - 1].unconditional_add(modded_base_point, hint);
95 }
96 } else {
98 // ensure all of the ecc add gates are lined up so that we can pay 1 gate per add and not 2
99 for (size_t i = 1; i < table_size; ++i) {
101 hints.has_value() ? std::optional<AffineElement>(hints.value()[i - 1]) : std::nullopt;
102 x_coordinate_checks.emplace_back(point_table[i - 1].x, modded_base_point.x);
103 point_table[i] = point_table[i - 1].unconditional_add(modded_base_point, hint);
104 }
105
106 // batch the x-coordinate checks together
107 // because `assert_is_not_zero` witness generation needs a modular inversion (expensive)
108 field_t coordinate_check_product = 1;
109 for (auto& [x1, x2] : x_coordinate_checks) {
110 auto x_diff = x2 - x1;
111 coordinate_check_product *= x_diff;
112 }
113 coordinate_check_product.assert_is_not_zero("straus_lookup_table x-coordinate collision");
114
115 for (size_t i = 1; i < table_size; ++i) {
117 base_point.is_point_at_infinity(), offset_generator, point_table[i]);
118 }
119 }
120 if constexpr (IS_ULTRA) {
121 rom_id = context->create_ROM_array(table_size);
122 for (size_t i = 0; i < table_size; ++i) {
123 if (point_table[i].is_constant()) {
124 auto element = point_table[i].get_value();
126 point_table[i].x.assert_equal(element.x);
127 point_table[i].y.assert_equal(element.y);
128 }
129 context->set_ROM_element_pair(
130 rom_id,
131 i,
132 std::array<uint32_t, 2>{ point_table[i].x.get_witness_index(), point_table[i].y.get_witness_index() });
133 }
134 } else {
135 BB_ASSERT_EQ(table_bits, 1U);
136 }
137}
138
146template <typename Builder> cycle_group<Builder> straus_lookup_table<Builder>::read(const field_t& _index)
147{
148 constexpr bool IS_ULTRA = Builder::CIRCUIT_TYPE == CircuitType::ULTRA;
149
150 if constexpr (IS_ULTRA) {
151 field_t index(_index);
152 if (index.is_constant()) {
154 index = witness_t(_context, _index.get_value());
155 index.assert_equal(_index.get_value());
156 }
157 auto output_indices = _context->read_ROM_array_pair(rom_id, index.get_witness_index());
158 field_t x = field_t::from_witness_index(_context, output_indices[0]);
159 field_t y = field_t::from_witness_index(_context, output_indices[1]);
160 // Merge tag of table with tag of index
161 x.set_origin_tag(OriginTag(tag, _index.get_origin_tag()));
162 y.set_origin_tag(OriginTag(tag, _index.get_origin_tag()));
163 return cycle_group<Builder>(x, y, /*is_infinity=*/false);
164 }
165 field_t x = _index * (point_table[1].x - point_table[0].x) + point_table[0].x;
166 field_t y = _index * (point_table[1].y - point_table[0].y) + point_table[0].y;
167
168 // Merge tag of table with tag of index
169 x.set_origin_tag(OriginTag(tag, _index.get_origin_tag()));
170 y.set_origin_tag(OriginTag(tag, _index.get_origin_tag()));
171 return cycle_group<Builder>(x, y, /*is_infinity=*/false);
172}
173
176
177} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
bool get_value() const
Definition bool.hpp:109
cycle_group represents a group Element of the proving system's embedded curve i.e....
static cycle_group from_constant_witness(Builder *_context, const AffineElement &_in)
Converts a native AffineElement into a witness, but constrains the witness values to be known constan...
static cycle_group conditional_assign(const bool_t &predicate, const cycle_group &lhs, const cycle_group &rhs)
bool_t is_point_at_infinity() const
AffineElement get_value() const
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
Definition field.cpp:929
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:59
static field_t conditional_assign(const bool_t< Builder > &predicate, const field_t &lhs, const field_t &rhs)
If predicate == true then return lhs, else return rhs.
Definition field.cpp:884
OriginTag get_origin_tag() const
Definition field.hpp:333
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
bool is_constant() const
Definition field.hpp:399
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:332
void assert_is_not_zero(std::string const &msg="field_t::assert_is_not_zero") const
Constrain *this to be non-zero by establishing that it has an inverse.
Definition field.cpp:707
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:461
straus_lookup_table computes a lookup table of size 1 << table_bits
std::vector< cycle_group< Builder > > point_table
cycle_group< Builder > read(const field_t &index)
Given an _index witness, return straus_lookup_table[index]
StrictMock< MockContext > context
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13