Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
biggroup_goblin_impl.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
13
37template <typename C, class Fq, class Fr, class G>
39 const std::vector<Fr>& scalars,
40 [[maybe_unused]] const size_t max_num_bits,
41 [[maybe_unused]] const bool handle_edge_cases)
42{
43 auto builder = points[0].get_context();
44
45 // Check that the internal accumulator is zero?
46 ASSERT(builder->op_queue->get_accumulator().is_point_at_infinity());
47
48 // Loop over all points and scalars
49 size_t num_points = points.size();
50
51 OriginTag tag_union{};
52 for (size_t i = 0; i < num_points; ++i) {
53 auto& point = points[i];
54 auto& scalar = scalars[i];
55
56 // Merge tags
57
58 tag_union = OriginTag(tag_union, OriginTag(point.get_origin_tag(), scalar.get_origin_tag()));
59 // Populate the goblin-style ecc op gates for the given mul inputs
60 ecc_op_tuple op_tuple;
61 bool scalar_is_constant_equal_one = scalar.get_witness_index() == IS_CONSTANT && scalar.get_value() == 1;
62 if (scalar_is_constant_equal_one) { // if scalar is 1, there is no need to perform a mul
63 op_tuple = builder->queue_ecc_add_accum(point.get_value());
64 } else { // otherwise, perform a mul-then-accumulate
65 op_tuple = builder->queue_ecc_mul_accum(point.get_value(), scalar.get_value());
66 }
67
68 // Add constraints demonstrating that the EC point coordinates were decomposed faithfully. In particular, show
69 // that the lo-hi components that have been encoded in the op wires can be reconstructed via the limbs of the
70 // original point coordinates.
71 auto x_lo = Fr::from_witness_index(builder, op_tuple.x_lo);
72 auto x_hi = Fr::from_witness_index(builder, op_tuple.x_hi);
73 auto y_lo = Fr::from_witness_index(builder, op_tuple.y_lo);
74 auto y_hi = Fr::from_witness_index(builder, op_tuple.y_hi);
75 // Note: These constraints do not assume or enforce that the coordinates of the original point have been
76 // asserted to be in the field, only that they are less than the smallest power of 2 greater than the field
77 // modulus (a la the bigfield(lo, hi) constructor with can_overflow == false).
78 BB_ASSERT_LTE(uint1024_t(point.x.get_maximum_value()), Fq::DEFAULT_MAXIMUM_REMAINDER);
79 BB_ASSERT_LTE(uint1024_t(point.y.get_maximum_value()), Fq::DEFAULT_MAXIMUM_REMAINDER);
80 x_lo.assert_equal(point.x.limbs[0]);
81 x_hi.assert_equal(point.x.limbs[1]);
82 y_lo.assert_equal(point.y.limbs[0]);
83 y_hi.assert_equal(point.y.limbs[1]);
84
85 // Add constraints demonstrating proper decomposition of scalar into endomorphism scalars
86 if (!scalar_is_constant_equal_one) {
87 auto z_1 = Fr::from_witness_index(builder, op_tuple.z_1);
88 auto z_2 = Fr::from_witness_index(builder, op_tuple.z_2);
89 auto beta = G::Fr::cube_root_of_unity();
90 scalar.assert_equal(z_1 - z_2 * beta);
91 }
92 }
93
94 // Populate equality gates based on the internal accumulator point
95 auto op_tuple = builder->queue_ecc_eq();
96
97 // Reconstruct the result of the batch mul using indices into the variables array
98 auto x_lo = Fr::from_witness_index(builder, op_tuple.x_lo);
99 auto x_hi = Fr::from_witness_index(builder, op_tuple.x_hi);
100 auto y_lo = Fr::from_witness_index(builder, op_tuple.y_lo);
101 auto y_hi = Fr::from_witness_index(builder, op_tuple.y_hi);
102 Fq point_x(x_lo, x_hi);
103 Fq point_y(y_lo, y_hi);
104 goblin_element result = goblin_element(point_x, point_y);
105
106 // NOTE: this used to be set as a circuit constant from `op_tuple.return_is_infinity
107 // I do not see how this was secure as it meant a circuit constant could change depending on witness values
108 // e.g. x*[P] + y*[Q] where `x = y` and `[P] = -[Q]`
109 // TODO(@zac-williamson) what is op_queue.return_is_infinity actually used for? I don't see its value
110 auto op2_is_infinity = (x_lo.add_two(x_hi, y_lo) + y_hi).is_zero();
111 result.set_point_at_infinity(op2_is_infinity);
112
113 // Set the tag of the result
114 result.set_origin_tag(tag_union);
115
116 return result;
117}
118
119} // namespace bb::stdlib::element_goblin
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:129
#define ASSERT(expression,...)
Definition assert.hpp:49
Custom element class for when using goblin.
void set_origin_tag(const OriginTag &tag) 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.
void set_point_at_infinity(const bool_ct &is_infinity)
AluTraceBuilder builder
Definition alu.test.cpp:123
uintx< uint512_t > uint1024_t
Definition uintx.hpp:309
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...
static constexpr field cube_root_of_unity()