Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
biggroup_goblin.hpp
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#pragma once
8
9#include "../bigfield/bigfield.hpp"
10#include "../bigfield/goblin_field.hpp"
11#include "../circuit_builders/circuit_builders_fwd.hpp"
12#include "../field/field.hpp"
13#include "../memory/rom_table.hpp"
14#include "../memory/twin_rom_table.hpp"
20
22
38template <class Builder_, class Fq, class Fr, class NativeGroup> class goblin_element {
39 public:
40 using Builder = Builder_;
41 using BaseField = Fq;
43 using biggroup_tag = goblin_element; // Facilitates a constexpr check IsBigGroup
44
45 // Number of bb::fr field elements used to represent a goblin element in the public inputs
46 static constexpr size_t PUBLIC_INPUTS_SIZE = BIGGROUP_PUBLIC_INPUTS_SIZE;
47
48 goblin_element() = default;
49 goblin_element(const typename NativeGroup::affine_element& input)
50 : x(input.x)
51 , y(input.y)
53 {}
54 goblin_element(const Fq& x, const Fq& y)
55 : x(x)
56 , y(y)
57 , _is_infinity(false)
58 {}
59 goblin_element(const Fq& x, const Fq& y, const bool_ct is_infinity)
60 : x(x)
61 , y(y)
62 , _is_infinity(is_infinity)
63 {}
64 goblin_element(const goblin_element& other) = default;
65 goblin_element(goblin_element&& other) noexcept = default;
66 goblin_element& operator=(const goblin_element& other) = default;
67 goblin_element& operator=(goblin_element&& other) noexcept = default;
68 ~goblin_element() = default;
69
81 const std::string msg = "goblin_element::incomplete_assert_equal") const
82 {
83 is_point_at_infinity().assert_equal(other.is_point_at_infinity(), msg + " (infinity flag)");
84 x.assert_equal(other.x, msg + " (x coordinate)");
85 y.assert_equal(other.y, msg + " (y coordinate)");
86 }
87
88 static goblin_element from_witness(Builder* ctx, const typename NativeGroup::affine_element& input)
89 {
91 // ECCVM requires points at infinity to be represented by 0-value x/y coords
92 if (input.is_point_at_infinity()) {
93 Fq x = Fq::from_witness(ctx, bb::fq(0));
94 Fq y = Fq::from_witness(ctx, bb::fq(0));
95 out.x = x;
96 out.y = y;
97 } else {
98 Fq x = Fq::from_witness(ctx, input.x);
99 Fq y = Fq::from_witness(ctx, input.y);
100 out.x = x;
101 out.y = y;
102 }
103 out.set_point_at_infinity(witness_t<Builder>(ctx, input.is_point_at_infinity()));
105 return out;
106 }
107
112 {
113 this->x.convert_constant_to_fixed_witness(builder);
114 this->y.convert_constant_to_fixed_witness(builder);
116 }
117
122 {
123 // Origin tags should be updated within
124 this->x.fix_witness();
125 this->y.fix_witness();
126
127 // This is now effectively a constant
129 }
130
131 void validate_on_curve() const
132 {
133 // happens in goblin eccvm
134 }
135
137 {
138 uint256_t x = uint256_t(NativeGroup::one.x);
139 uint256_t y = uint256_t(NativeGroup::one.y);
140 Fq x_fq(ctx, x);
141 Fq y_fq(ctx, y);
142 return goblin_element(x_fq, y_fq);
143 }
144
146 {
147 Fr zero = Fr::from_witness_index(ctx, ctx->zero_idx());
148 zero.unset_free_witness_tag();
149 Fq x_fq(zero, zero);
150 Fq y_fq(zero, zero);
151 goblin_element result(x_fq, y_fq);
152 result.set_point_at_infinity(true);
153 return result;
154 }
155
157 {
158 return goblin_element::operator+(*this, other);
159 }
161 {
162 return goblin_element::operator-(*this, other);
163 }
164
166 {
167 return batch_mul({ *this, other }, { Fr(1), Fr(1) });
168 }
169
171 {
172 auto builder = get_context(other);
173 // Check that the internal accumulator is zero
174 ASSERT(builder->op_queue->get_accumulator().is_point_at_infinity());
175
176 // Compute the result natively, and validate that result + other == *this
177 typename NativeGroup::affine_element result_value = typename NativeGroup::affine_element(
178 typename NativeGroup::element(get_value()) - typename NativeGroup::element(other.get_value()));
179
180 ecc_op_tuple op_tuple;
181 op_tuple = builder->queue_ecc_add_accum(other.get_value());
182 {
183 auto x_lo = Fr::from_witness_index(builder, op_tuple.x_lo);
184 auto x_hi = Fr::from_witness_index(builder, op_tuple.x_hi);
185 auto y_lo = Fr::from_witness_index(builder, op_tuple.y_lo);
186 auto y_hi = Fr::from_witness_index(builder, op_tuple.y_hi);
187 x_lo.assert_equal(other.x.limbs[0]);
188 x_hi.assert_equal(other.x.limbs[1]);
189 y_lo.assert_equal(other.y.limbs[0]);
190 y_hi.assert_equal(other.y.limbs[1]);
191 }
192 // if function queue_ecc_add_accum is used, op_tuple creates as a result of construct_and_populate_ultra_ops
193 // function. In case of queue_ecc_add_accum, scalar is zero, (z_1, z_2) = (scalar, 0) = (0, 0) and they just put
194 // in the wires.
195 builder->update_used_witnesses({ op_tuple.z_1, op_tuple.z_2 });
196
197 ecc_op_tuple op_tuple2 = builder->queue_ecc_add_accum(result_value);
198 auto x_lo = Fr::from_witness_index(builder, op_tuple2.x_lo);
199 auto x_hi = Fr::from_witness_index(builder, op_tuple2.x_hi);
200 auto y_lo = Fr::from_witness_index(builder, op_tuple2.y_lo);
201 auto y_hi = Fr::from_witness_index(builder, op_tuple2.y_hi);
202
203 // if function queue_ecc_add_accum is used, op_tuple creates as a result of construct_and_populate_ultra_ops
204 // function. In case of queue_ecc_add_accum, scalar is zero, (z_1, z_2) = (scalar, 0) = (0, 0) and they just put
205 // in the wires.
206 builder->update_used_witnesses({ op_tuple2.z_1, op_tuple2.z_2 });
207
208 Fq result_x(x_lo, x_hi);
209 Fq result_y(y_lo, y_hi);
210 goblin_element result(result_x, result_y);
211
212 // if the output is at infinity, this is represented by x/y coordinates being zero
213 // because they are all 136-bit, we can do a cheap zerocheck by first summing the limbs
214 auto op2_is_infinity = (x_lo.add_two(x_hi, y_lo) + y_hi).is_zero();
215 result.set_point_at_infinity(op2_is_infinity);
216 {
217 ecc_op_tuple op_tuple3 = builder->queue_ecc_eq();
218 auto x_lo = Fr::from_witness_index(builder, op_tuple3.x_lo);
219 auto x_hi = Fr::from_witness_index(builder, op_tuple3.x_hi);
220 auto y_lo = Fr::from_witness_index(builder, op_tuple3.y_lo);
221 auto y_hi = Fr::from_witness_index(builder, op_tuple3.y_hi);
222
223 x_lo.assert_equal(x.limbs[0]);
224 x_hi.assert_equal(x.limbs[1]);
225 y_lo.assert_equal(y.limbs[0]);
226 y_hi.assert_equal(y.limbs[1]);
227 }
228
229 // Set the tag of the result to the union of the tags of inputs
231 return result;
232 }
233
235
237 {
238 *this = *this + other;
239 return *this;
240 }
242 {
243 *this = *this - other;
244 return *this;
245 }
247 {
248 return std::array<goblin_element, 2>{ *this + other, *this - other };
249 }
250
251 goblin_element operator*(const Fr& scalar) const { return batch_mul({ *this }, { scalar }); }
252
254 {
255 goblin_element negated = -(*this);
256 goblin_element result(*this);
257 result.y = Fq::conditional_assign(predicate, negated.y, result.y);
258 return result;
259 }
260
268 goblin_element conditional_select(const goblin_element& other, const bool_ct& predicate) const
269 {
270 goblin_element result(*this);
271 result.x = Fq::conditional_assign(predicate, other.x, result.x);
272 result.y = Fq::conditional_assign(predicate, other.y, result.y);
273 result._is_infinity =
275 return result;
276 }
277
279 {
280 // no need to normalize, all goblin eccvm operations are returned normalized
281 return *this;
282 }
283
285 {
286 // no need to reduce, all goblin eccvm operations are returned normalized
287 return *this;
288 }
289
290 goblin_element dbl() const { return batch_mul({ *this }, { 2 }); }
291
292 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1291) max_num_bits is unused; could implement and
293 // use this to optimize other operations. interface compatible with biggroup.hpp, the final parameter
294 // handle_edge_cases is not needed as this is always done in the eccvm
296 const std::vector<Fr>& scalars,
297 const size_t max_num_bits = 0,
298 const bool handle_edge_cases = false);
299
300 // we use this data structure to add together a sequence of points.
301 // By tracking the previous values of x_1, y_1, \lambda, we can avoid
302
303 typename NativeGroup::affine_element get_value() const
304 {
305 bb::fq x_val = x.get_value().lo;
306 bb::fq y_val = y.get_value().lo;
307 auto result = typename NativeGroup::affine_element(x_val, y_val);
309 result.self_set_infinity();
310 }
311 return result;
312 }
313
315 {
316 if (x.get_context() != nullptr) {
317 return x.get_context();
318 }
319 if (y.get_context() != nullptr) {
320 return y.get_context();
321 }
322 return nullptr;
323 }
324
325 Builder* get_context(const goblin_element& other) const
326 {
327 if (x.get_context() != nullptr) {
328 return x.get_context();
329 }
330 if (y.get_context() != nullptr) {
331 return y.get_context();
332 }
333 if (other.x.get_context() != nullptr) {
334 return other.x.get_context();
335 }
336 if (other.y.get_context() != nullptr) {
337 return other.y.get_context();
338 }
339 return nullptr;
340 }
341
343 void set_point_at_infinity(const bool_ct& is_infinity) { _is_infinity = is_infinity; }
352 {
353 const bool_ct is_infinity = is_point_at_infinity();
354 goblin_element result(*this);
355 const Fq zero = Fq::zero();
356 result.x = Fq::conditional_assign(is_infinity, zero, result.x);
357 result.y = Fq::conditional_assign(is_infinity, zero, result.y);
358 return result;
359 }
360
362 {
363 return OriginTag(x.get_origin_tag(), y.get_origin_tag(), _is_infinity.get_origin_tag());
364 }
365
366 void set_origin_tag(const OriginTag& tag) const
367 {
368 x.set_origin_tag(tag);
369 y.set_origin_tag(tag);
371 }
372
377 {
378 x.set_free_witness_tag();
379 y.set_free_witness_tag();
381 }
382
387 {
388 x.unset_free_witness_tag();
389 y.unset_free_witness_tag();
391 }
401 uint32_t set_public() const
402 {
403 const uint32_t start_idx = x.set_public();
404 y.set_public();
405
406 return start_idx;
407 }
408
418 {
419 const size_t FRS_PER_FQ = Fq::PUBLIC_INPUTS_SIZE;
420 std::span<const Fr, FRS_PER_FQ> x_limbs{ limbs.data(), FRS_PER_FQ };
421 std::span<const Fr, FRS_PER_FQ> y_limbs{ limbs.data() + FRS_PER_FQ, FRS_PER_FQ };
422
423 return { Fq::reconstruct_from_public(x_limbs), Fq::reconstruct_from_public(y_limbs) };
424 }
425
428
429 private:
431};
432
436 bb::g1>;
437
438template <typename C, typename Fq, typename Fr, typename G>
439inline std::ostream& operator<<(std::ostream& os, goblin_element<C, Fq, Fr, G> const& v)
440{
441 return os << "{ " << v.x << " , " << v.y << " }";
442}
443} // namespace bb::stdlib::element_goblin
444
#define ASSERT(expression,...)
Definition assert.hpp:77
group class. Represents an elliptic curve group element. Group is parametrised by Fq and Fr
Definition group.hpp:36
Implements boolean logic in-circuit.
Definition bool.hpp:59
void set_origin_tag(const OriginTag &new_tag) const
Definition bool.hpp:128
void set_free_witness_tag()
Definition bool.hpp:130
static bool_t conditional_assign(const bool_t< Builder > &predicate, const bool_t &lhs, const bool_t &rhs)
Implements the ternary operator - if predicate == true then return lhs, else return rhs.
Definition bool.cpp:456
void unset_free_witness_tag()
Definition bool.hpp:131
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
Definition bool.cpp:423
OriginTag get_origin_tag() const
Definition bool.hpp:129
Custom element class for when using goblin.
goblin_element operator+(const goblin_element &other) const
void set_origin_tag(const OriginTag &tag) const
goblin_element operator-(const goblin_element &other) const
goblin_element conditional_negate(const bool_ct &predicate) const
goblin_element checked_unconditional_add(const goblin_element &other) const
static goblin_element batch_mul(const std::vector< goblin_element > &points, const std::vector< Fr > &scalars, const size_t max_num_bits=0, const bool handle_edge_cases=false)
Goblin style batch multiplication.
goblin_element conditional_select(const goblin_element &other, const bool_ct &predicate) const
Selects this if predicate is false, other if predicate is true.
static goblin_element one(Builder *ctx)
goblin_element operator*(const Fr &scalar) const
uint32_t set_public() const
Set the witness indices representing the goblin element to public.
goblin_element(goblin_element &&other) noexcept=default
std::array< goblin_element, 2 > checked_unconditional_add_sub(const goblin_element &other) const
goblin_element checked_unconditional_subtract(const goblin_element &other) const
goblin_element operator+=(const goblin_element &other)
void incomplete_assert_equal(const goblin_element &other, const std::string msg="goblin_element::incomplete_assert_equal") const
Asserts that two goblin elements are equal (i.e., x, y coordinates and infinity flag are all equal).
NativeGroup::affine_element get_value() const
void set_free_witness_tag()
Set the free witness flag for the goblin element's tags.
void convert_constant_to_fixed_witness(Builder *builder)
Creates fixed witnesses from a constant element.
goblin_element get_standard_form() const
Enforce x and y coordinates of a point to be (0,0) in the case of point at infinity.
static goblin_element reconstruct_from_public(const std::span< const Fr, PUBLIC_INPUTS_SIZE > &limbs)
Reconstruct a goblin element from its representation as limbs stored in the public inputs.
Builder * get_context(const goblin_element &other) const
static goblin_element point_at_infinity(Builder *ctx)
goblin_element(const typename NativeGroup::affine_element &input)
goblin_element operator-=(const goblin_element &other)
goblin_element & operator=(const goblin_element &other)=default
static goblin_element from_witness(Builder *ctx, const typename NativeGroup::affine_element &input)
void unset_free_witness_tag()
Unset the free witness flag for the goblin element's tags.
goblin_element & operator=(goblin_element &&other) noexcept=default
goblin_element(const Fq &x, const Fq &y, const bool_ct is_infinity)
void set_point_at_infinity(const bool_ct &is_infinity)
goblin_element(const goblin_element &other)=default
goblin_field wraps x/y coordinates of bn254 group elements when using goblin
AluTraceBuilder builder
Definition alu.test.cpp:123
std::ostream & operator<<(std::ostream &os, goblin_element< C, Fq, Fr, G > const &v)
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
Curve::ScalarField Fr
static constexpr size_t PUBLIC_INPUTS_SIZE
static field reconstruct_from_public(const std::span< const field< V >, PUBLIC_INPUTS_SIZE > &limbs)
static constexpr field zero()
bb::fq Fq