Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
pairing_points.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
13
14namespace bb::stdlib::recursion {
15
16static constexpr bb::fq DEFAULT_PAIRING_POINTS_P0_X(
17 "0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf");
18static constexpr bb::fq DEFAULT_PAIRING_POINTS_P0_Y(
19 "0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4");
20static constexpr bb::fq DEFAULT_PAIRING_POINTS_P1_X(
21 "0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38");
22static constexpr bb::fq DEFAULT_PAIRING_POINTS_P1_Y(
23 "0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f");
24
34template <typename Curve> struct PairingPoints {
35 using Builder = typename Curve::Builder;
41
42 bool has_data = false;
43 uint32_t tag_index = 0; // Index of the tag for tracking pairing point aggregation
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 = PAIRING_POINTS_SIZE;
47
48 PairingPoints() = default;
49
50 PairingPoints(const Group& P0, const Group& P1)
51 : P0(P0)
52 , P1(P1)
53 , has_data(true)
54 {
55 // Get the builder from the group elements and assign a new tag
56 Builder* builder = P0.get_context();
57 if (builder != nullptr) {
58 tag_index = builder->pairing_points_tagging.create_pairing_point_tag();
59 }
60
61#ifndef NDEBUG
62 bb::PairingPoints<typename Curve::NativeCurve> native_pp(P0.get_value(), P1.get_value());
63 info("Are Pairing Points with tag ", tag_index, " valid? ", native_pp.check() ? "true" : "false");
64#endif
65 }
66
68 : PairingPoints(points[0], points[1])
69 {}
70
71 Group& operator[](size_t idx)
72 {
73 BB_ASSERT(idx < 2, "Index out of bounds");
74 return idx == 0 ? P0 : P1;
75 }
76
77 const Group& operator[](size_t idx) const
78 {
79 BB_ASSERT(idx < 2, "Index out of bounds");
80 return idx == 0 ? P0 : P1;
81 }
82
83 typename Curve::bool_ct operator==(PairingPoints const& other) const { return P0 == other.P0 && P1 == other.P1; };
84
92 {
93 size_t num_points = pairing_points.size();
94 BB_ASSERT_GT(num_points, 1UL, "This method should be used only with more than one pairing point.");
95
96 std::vector<Group> first_components;
97 first_components.reserve(num_points);
98 std::vector<Group> second_components;
99 second_components.reserve(num_points);
100 for (const auto& points : pairing_points) {
101 first_components.emplace_back(points.P0);
102 second_components.emplace_back(points.P1);
103 }
104
105 // Fiat-Shamir
106 StdlibTranscript<Builder> transcript{};
107 std::vector<std::string> labels;
108 labels.reserve(num_points);
109 for (size_t idx = 0; auto [first, second] : zip_view(first_components, second_components)) {
110 transcript.add_to_hash_buffer("first_component_" + std::to_string(idx), first);
111 transcript.add_to_hash_buffer("second_component_" + std::to_string(idx), second);
112 labels.emplace_back("pp_aggregation_challenge_" + std::to_string(idx));
113 idx++;
114 }
115
116 std::vector<Fr> challenges = transcript.template get_challenges<Fr>(labels);
117
118 // Batch mul
119 auto P0 = Group::batch_mul(first_components, challenges);
120 auto P1 = Group::batch_mul(second_components, challenges);
121
122 PairingPoints aggregated_points(P0, P1);
123
124 // Merge tags
125 Builder* builder = P0.get_context();
126 if (builder != nullptr) {
127 for (const auto& points : pairing_points) {
128 builder->pairing_points_tagging.merge_pairing_point_tags(aggregated_points.tag_index, points.tag_index);
129 }
130 }
131
132 return aggregated_points;
133 }
134
142 void aggregate(PairingPoints const& other)
143 {
144 BB_ASSERT(other.has_data, "Cannot aggregate null pairing points.");
145
146 // If LHS is empty, simply set it equal to the incoming pairing points
147 if (!this->has_data && other.has_data) {
148 *this = other;
149 return;
150 }
151 // We use a Transcript because it provides us an easy way to hash to get a "random" separator.
152 StdlibTranscript<Builder> transcript{};
153 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1375): Sometimes unnecesarily hashing constants
154 transcript.add_to_hash_buffer("Accumulator_P0", P0);
155 transcript.add_to_hash_buffer("Accumulator_P1", P1);
156 transcript.add_to_hash_buffer("Aggregated_P0", other.P0);
157 transcript.add_to_hash_buffer("Aggregated_P1", other.P1);
158 auto recursion_separator =
159 transcript.template get_challenge<typename Curve::ScalarField>("recursion_separator");
160 // If Mega Builder is in use, the EC operations are deferred via Goblin
162 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1385): Can we improve efficiency here?
163 P0 = Group::batch_mul({ P0, other.P0 }, { 1, recursion_separator });
164 P1 = Group::batch_mul({ P1, other.P1 }, { 1, recursion_separator });
165 } else {
166 // Save gates using short scalars.
167 Group point_to_aggregate = other.P0.scalar_mul(recursion_separator, 128);
168 P0 += point_to_aggregate;
169 point_to_aggregate = other.P1.scalar_mul(recursion_separator, 128);
170 P1 += point_to_aggregate;
171 }
172
173 // Merge the tags in the builder
174 Builder* builder = P0.get_context();
175 if (builder != nullptr) {
176 builder->pairing_points_tagging.merge_pairing_point_tags(this->tag_index, other.tag_index);
177 }
178
179#ifndef NDEBUG
180 bb::PairingPoints<typename Curve::NativeCurve> native_pp(P0.get_value(), P1.get_value());
181 info("Aggregated Pairing Points with tag ", tag_index, ": valid: ", native_pp.check() ? "true" : "false");
182#endif
183 }
184
190 uint32_t set_public()
191 {
192 BB_ASSERT(this->has_data, "Calling set_public on empty pairing points.");
193 uint32_t start_idx = P0.set_public();
194 P1.set_public();
195
196 return start_idx;
197 }
198
205 {
206 uint32_t start_idx = 0;
207 for (size_t idx = 0; auto const& coordinate : { DEFAULT_PAIRING_POINTS_P0_X,
208 DEFAULT_PAIRING_POINTS_P0_Y,
209 DEFAULT_PAIRING_POINTS_P1_X,
210 DEFAULT_PAIRING_POINTS_P1_Y }) {
211 bigfield<Builder, bb::Bn254FqParams> bigfield_coordinate(coordinate);
212 bigfield_coordinate.convert_constant_to_fixed_witness(builder);
213 uint32_t index = bigfield_coordinate.set_public();
214 start_idx = idx == 0 ? index : start_idx;
215 idx++;
216 }
217
218 return start_idx;
219 }
220
228 {
229 const size_t FRS_PER_POINT = Group::PUBLIC_INPUTS_SIZE;
230 std::span<const Fr, FRS_PER_POINT> P0_limbs{ limbs.data(), FRS_PER_POINT };
231 std::span<const Fr, FRS_PER_POINT> P1_limbs{ limbs.data() + FRS_PER_POINT, FRS_PER_POINT };
232 Group P0 = Group::reconstruct_from_public(P0_limbs);
233 Group P1 = Group::reconstruct_from_public(P1_limbs);
234 return { P0, P1 };
235 }
236
243 {
244 // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted from a
245 // valid proof. This is a workaround because we can't represent the point at infinity in biggroup yet.
246 Fq x0(DEFAULT_PAIRING_POINTS_P0_X);
247 Fq y0(DEFAULT_PAIRING_POINTS_P0_Y);
248 Fq x1(DEFAULT_PAIRING_POINTS_P1_X);
249 Fq y1(DEFAULT_PAIRING_POINTS_P1_Y);
250
251 // These are known, valid points, so we can skip the curve checks.
252 Group P0(x0, y0, /*assert_on_curve=*/false);
253 Group P1(x1, y1, /*assert_on_curve=*/false);
254
255 return { P0, P1 };
256 }
257};
258
259template <typename NCT> std::ostream& operator<<(std::ostream& os, PairingPoints<NCT> const& as)
260{
261 return os << "P0: " << as.P0 << "\n"
262 << "P1: " << as.P1 << "\n"
263 << "has_data: " << as.has_data << "\n"
264 << "tag_index: " << as.tag_index << "\n";
265}
266
267} // namespace bb::stdlib::recursion
#define BB_ASSERT(expression,...)
Definition assert.hpp:67
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:107
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
void add_to_hash_buffer(const std::string &label, const T &element)
Adds an element to the transcript.
An object storing two EC points that represent the inputs to a pairing check.
bool check() const
Perform the pairing check.
typename grumpkin::g1 Group
Definition grumpkin.hpp:61
void convert_constant_to_fixed_witness(Builder *builder)
Definition bigfield.hpp:661
uint32_t set_public() const
Set the witness indices of the binary basis limbs to public.
Definition bigfield.hpp:737
void info(Args... args)
Definition log.hpp:75
AluTraceBuilder builder
Definition alu.test.cpp:124
std::ostream & operator<<(std::ostream &os, PairingPoints< NCT > const &as)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
An object storing two EC points that represent the inputs to a pairing check.
static constexpr size_t PUBLIC_INPUTS_SIZE
Curve::bool_ct operator==(PairingPoints const &other) const
static uint32_t set_default_to_public(Builder *builder)
Set the witness indices for the default limbs of the pairing points to public.
void aggregate(PairingPoints const &other)
Compute a linear combination of the present pairing points with an input set of pairing points.
uint32_t set_public()
Set the witness indices for the limbs of the pairing points to public.
static PairingPoints aggregate_multiple(std::vector< PairingPoints > &pairing_points)
Aggregate multiple PairingPoints.
static PairingPoints< Curve > reconstruct_from_public(const std::span< const Fr, PUBLIC_INPUTS_SIZE > &limbs)
Reconstruct an PairingPoints from its representation as limbs (generally stored in the public inputs)
static PairingPoints construct_default()
Construct default pairing points.
PairingPoints(std::array< Group, 2 > const &points)
const Group & operator[](size_t idx) const
PairingPoints(const Group &P0, const Group &P1)