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 goblin_element& other) = default;
60 goblin_element(goblin_element&& other) noexcept = default;
61 goblin_element& operator=(const goblin_element& other) = default;
62 goblin_element& operator=(goblin_element&& other) noexcept = default;
63 ~goblin_element() = default;
64
65 void assert_equal(const goblin_element& other) const
66 {
67 if (this->get_value() != other.get_value()) {
68 info("WARNING: goblin_element::assert_equal value check failed!");
69 }
70 x.assert_equal(other.x);
71 y.assert_equal(other.y);
72 }
73
74 static goblin_element from_witness(Builder* ctx, const typename NativeGroup::affine_element& input)
75 {
77 // ECCVM requires points at infinity to be represented by 0-value x/y coords
78 if (input.is_point_at_infinity()) {
79 Fq x = Fq::from_witness(ctx, bb::fq(0));
80 Fq y = Fq::from_witness(ctx, bb::fq(0));
81 out.x = x;
82 out.y = y;
83 } else {
84 Fq x = Fq::from_witness(ctx, input.x);
85 Fq y = Fq::from_witness(ctx, input.y);
86 out.x = x;
87 out.y = y;
88 }
89 out.set_point_at_infinity(witness_t<Builder>(ctx, input.is_point_at_infinity()));
91 return out;
92 }
93
98 {
99 this->x.convert_constant_to_fixed_witness(builder);
100 this->y.convert_constant_to_fixed_witness(builder);
102 }
103
108 {
109 // Origin tags should be updated within
110 this->x.fix_witness();
111 this->y.fix_witness();
112
113 // This is now effectively a constant
115 }
116
117 void validate_on_curve() const
118 {
119 // happens in goblin eccvm
120 }
121
123 {
124 uint256_t x = uint256_t(NativeGroup::one.x);
125 uint256_t y = uint256_t(NativeGroup::one.y);
126 Fq x_fq(ctx, x);
127 Fq y_fq(ctx, y);
128 return goblin_element(x_fq, y_fq);
129 }
130
132 {
133 Fr zero = Fr::from_witness_index(ctx, ctx->zero_idx);
134 zero.unset_free_witness_tag();
135 Fq x_fq(zero, zero);
136 Fq y_fq(zero, zero);
137 goblin_element result(x_fq, y_fq);
138 result.set_point_at_infinity(true);
139 return result;
140 }
141
143 {
144 return goblin_element::operator+(*this, other);
145 }
147 {
148 return goblin_element::operator-(*this, other);
149 }
150
152 {
153 return batch_mul({ *this, other }, { Fr(1), Fr(1) });
154 }
155
157 {
158 auto builder = get_context(other);
159 // Check that the internal accumulator is zero
160 ASSERT(builder->op_queue->get_accumulator().is_point_at_infinity());
161
162 // Compute the result natively, and validate that result + other == *this
163 typename NativeGroup::affine_element result_value = typename NativeGroup::affine_element(
164 typename NativeGroup::element(get_value()) - typename NativeGroup::element(other.get_value()));
165
166 ecc_op_tuple op_tuple;
167 op_tuple = builder->queue_ecc_add_accum(other.get_value());
168 {
169 auto x_lo = Fr::from_witness_index(builder, op_tuple.x_lo);
170 auto x_hi = Fr::from_witness_index(builder, op_tuple.x_hi);
171 auto y_lo = Fr::from_witness_index(builder, op_tuple.y_lo);
172 auto y_hi = Fr::from_witness_index(builder, op_tuple.y_hi);
173 x_lo.assert_equal(other.x.limbs[0]);
174 x_hi.assert_equal(other.x.limbs[1]);
175 y_lo.assert_equal(other.y.limbs[0]);
176 y_hi.assert_equal(other.y.limbs[1]);
177 }
178
179 ecc_op_tuple op_tuple2 = builder->queue_ecc_add_accum(result_value);
180 auto x_lo = Fr::from_witness_index(builder, op_tuple2.x_lo);
181 auto x_hi = Fr::from_witness_index(builder, op_tuple2.x_hi);
182 auto y_lo = Fr::from_witness_index(builder, op_tuple2.y_lo);
183 auto y_hi = Fr::from_witness_index(builder, op_tuple2.y_hi);
184
185 Fq result_x(x_lo, x_hi);
186 Fq result_y(y_lo, y_hi);
187 goblin_element result(result_x, result_y);
188
189 // if the output is at infinity, this is represented by x/y coordinates being zero
190 // because they are all 136-bit, we can do a cheap zerocheck by first summing the limbs
191 auto op2_is_infinity = (x_lo.add_two(x_hi, y_lo) + y_hi).is_zero();
192 result.set_point_at_infinity(op2_is_infinity);
193 {
194 ecc_op_tuple op_tuple3 = builder->queue_ecc_eq();
195 auto x_lo = Fr::from_witness_index(builder, op_tuple3.x_lo);
196 auto x_hi = Fr::from_witness_index(builder, op_tuple3.x_hi);
197 auto y_lo = Fr::from_witness_index(builder, op_tuple3.y_lo);
198 auto y_hi = Fr::from_witness_index(builder, op_tuple3.y_hi);
199
200 x_lo.assert_equal(x.limbs[0]);
201 x_hi.assert_equal(x.limbs[1]);
202 y_lo.assert_equal(y.limbs[0]);
203 y_hi.assert_equal(y.limbs[1]);
204 }
205
206 // Set the tag of the result to the union of the tags of inputs
208 return result;
209 }
210
212
214 {
215 *this = *this + other;
216 return *this;
217 }
219 {
220 *this = *this - other;
221 return *this;
222 }
224 {
225 return std::array<goblin_element, 2>{ *this + other, *this - other };
226 }
227
228 goblin_element operator*(const Fr& scalar) const { return batch_mul({ *this }, { scalar }); }
229
231 {
232 goblin_element negated = -(*this);
233 goblin_element result(*this);
234 result.y = Fq::conditional_assign(predicate, negated.y, result.y);
235 return result;
236 }
237
239 {
240 // no need to normalize, all goblin eccvm operations are returned normalized
241 return *this;
242 }
243
245 {
246 // no need to reduce, all goblin eccvm operations are returned normalized
247 return *this;
248 }
249
250 goblin_element dbl() const { return batch_mul({ *this }, { 2 }); }
251
252 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1291) max_num_bits is unused; could implement and
253 // use this to optimize other operations. interface compatible with biggroup.hpp, the final parameter
254 // handle_edge_cases is not needed as this is always done in the eccvm
256 const std::vector<Fr>& scalars,
257 const size_t max_num_bits = 0,
258 const bool handle_edge_cases = false);
259
260 // we use this data structure to add together a sequence of points.
261 // By tracking the previous values of x_1, y_1, \lambda, we can avoid
262
263 typename NativeGroup::affine_element get_value() const
264 {
265 bb::fq x_val = x.get_value().lo;
266 bb::fq y_val = y.get_value().lo;
267 auto result = typename NativeGroup::affine_element(x_val, y_val);
269 result.self_set_infinity();
270 }
271 return result;
272 }
273
275 {
276 if (x.get_context() != nullptr) {
277 return x.get_context();
278 }
279 if (y.get_context() != nullptr) {
280 return y.get_context();
281 }
282 return nullptr;
283 }
284
285 Builder* get_context(const goblin_element& other) const
286 {
287 if (x.get_context() != nullptr) {
288 return x.get_context();
289 }
290 if (y.get_context() != nullptr) {
291 return y.get_context();
292 }
293 if (other.x.get_context() != nullptr) {
294 return other.x.get_context();
295 }
296 if (other.y.get_context() != nullptr) {
297 return other.y.get_context();
298 }
299 return nullptr;
300 }
301
303 void set_point_at_infinity(const bool_ct& is_infinity) { _is_infinity = is_infinity; }
312 {
313 const bool_ct is_infinity = is_point_at_infinity();
314 goblin_element result(*this);
315 const Fq zero = Fq::zero();
316 result.x = Fq::conditional_assign(is_infinity, zero, result.x);
317 result.y = Fq::conditional_assign(is_infinity, zero, result.y);
318 return result;
319 }
320
322 {
323 return OriginTag(x.get_origin_tag(), y.get_origin_tag(), _is_infinity.get_origin_tag());
324 }
325
326 void set_origin_tag(const OriginTag& tag) const
327 {
328 x.set_origin_tag(tag);
329 y.set_origin_tag(tag);
331 }
332
337 {
338 x.set_free_witness_tag();
339 y.set_free_witness_tag();
341 }
342
347 {
348 x.unset_free_witness_tag();
349 y.unset_free_witness_tag();
351 }
361 uint32_t set_public() const
362 {
363 const uint32_t start_idx = x.set_public();
364 y.set_public();
365
366 return start_idx;
367 }
368
378 {
379 const size_t FRS_PER_FQ = Fq::PUBLIC_INPUTS_SIZE;
380 std::span<const Fr, FRS_PER_FQ> x_limbs{ limbs.data(), FRS_PER_FQ };
381 std::span<const Fr, FRS_PER_FQ> y_limbs{ limbs.data() + FRS_PER_FQ, FRS_PER_FQ };
382
383 return { Fq::reconstruct_from_public(x_limbs), Fq::reconstruct_from_public(y_limbs) };
384 }
385
388
389 private:
391};
392
396 bb::g1>;
397
398template <typename C, typename Fq, typename Fr, typename G>
399inline std::ostream& operator<<(std::ostream& os, goblin_element<C, Fq, Fr, G> const& v)
400{
401 return os << "{ " << v.x << " , " << v.y << " }";
402}
403} // namespace bb::stdlib::element_goblin
404
#define ASSERT(expression,...)
Definition assert.hpp:49
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:119
void set_free_witness_tag()
Definition bool.hpp:121
void unset_free_witness_tag()
Definition bool.hpp:122
OriginTag get_origin_tag() const
Definition bool.hpp:120
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.
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)
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.
void assert_equal(const goblin_element &other) const
goblin_element & operator=(goblin_element &&other) noexcept=default
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
void info(Args... args)
Definition log.hpp:70
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