Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
affine_element.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8
15#include <cstring>
16#include <type_traits>
17#include <vector>
18
20template <typename T>
21concept SupportsHashToCurve = T::can_hash_to_curve;
22template <typename Fq_, typename Fr_, typename Params_> class alignas(64) affine_element {
23 public:
24 using Fq = Fq_;
25 using Fr = Fr_;
26 using Params = Params_;
27
28 using in_buf = const uint8_t*;
29 using vec_in_buf = const uint8_t*;
30 using out_buf = uint8_t*;
31 using vec_out_buf = uint8_t**;
32
40
41 affine_element() noexcept = default;
42 ~affine_element() noexcept = default;
43
44 constexpr affine_element(const Fq& x, const Fq& y) noexcept;
45
46 constexpr affine_element(const affine_element& other) noexcept = default;
47
48 constexpr affine_element(affine_element&& other) noexcept = default;
49
50 static constexpr affine_element one() noexcept { return { Params::one_x, Params::one_y }; };
51
61 template <typename BaseField = Fq,
62 typename CompileTimeEnabled = std::enable_if_t<(BaseField::modulus >> 255) == uint256_t(0), void>>
63 static constexpr affine_element from_compressed(const uint256_t& compressed) noexcept;
64
74 template <typename BaseField = Fq,
75 typename CompileTimeEnabled = std::enable_if_t<(BaseField::modulus >> 255) == uint256_t(1), void>>
76 static constexpr std::array<affine_element, 2> from_compressed_unsafe(const uint256_t& compressed) noexcept;
77
78 constexpr affine_element& operator=(const affine_element& other) noexcept = default;
79
80 constexpr affine_element& operator=(affine_element&& other) noexcept = default;
81
82 constexpr affine_element operator+(const affine_element& other) const noexcept;
83
84 constexpr affine_element operator*(const Fr& exponent) const noexcept;
85
86 template <typename BaseField = Fq,
87 typename CompileTimeEnabled = std::enable_if_t<(BaseField::modulus >> 255) == uint256_t(0), void>>
88 [[nodiscard]] constexpr uint256_t compress() const noexcept;
89
90 static constexpr affine_element infinity();
91 constexpr affine_element set_infinity() const noexcept;
92 constexpr void self_set_infinity() noexcept;
93
94 [[nodiscard]] constexpr bool is_point_at_infinity() const noexcept;
95
96 [[nodiscard]] constexpr bool on_curve() const noexcept;
97
98 static constexpr std::optional<affine_element> derive_from_x_coordinate(const Fq& x, bool sign_bit) noexcept;
99
105 static affine_element random_element(numeric::RNG* engine = nullptr) noexcept;
106 static constexpr affine_element hash_to_curve(const std::vector<uint8_t>& seed, uint8_t attempt_count = 0) noexcept
107 requires SupportsHashToCurve<Params>;
108
109 constexpr bool operator==(const affine_element& other) const noexcept;
110
111 constexpr affine_element operator-() const noexcept { return { x, -y }; }
112
113 constexpr bool operator>(const affine_element& other) const noexcept;
114 constexpr bool operator<(const affine_element& other) const noexcept { return (other > *this); }
115
125 static void serialize_to_buffer(const affine_element& value, uint8_t* buffer, bool write_x_first = false)
126 {
127 using namespace serialize;
128 if (value.is_point_at_infinity()) {
129 // if we are infinity, just set all buffer bits to 1
130 // we only need this case because the below gets mangled converting from montgomery for infinity points
131 memset(buffer, 255, sizeof(Fq) * 2);
132 } else {
133 // Note: for historic reasons we will need to redo downstream hashes if we want this to always be written in
134 // the same order in our various serialization flows
135 write(buffer, write_x_first ? value.x : value.y);
136 write(buffer, write_x_first ? value.y : value.x);
137 }
138 }
139
152 static affine_element serialize_from_buffer(const uint8_t* buffer, bool write_x_first = false)
153 {
154 using namespace serialize;
155 // Does the buffer consist entirely of set bits? If so, we have a point at infinity
156 // Note that if it isn't, this loop should end early.
157 // We only need this case because the below gets mangled converting to montgomery for infinity points
159 std::all_of(buffer, buffer + sizeof(Fq) * 2, [](uint8_t val) { return val == 255; });
162 }
163 affine_element result;
164 // Note: for historic reasons we will need to redo downstream hashes if we want this to always be read in the
165 // same order in our various serialization flows
166 read(buffer, write_x_first ? result.x : result.y);
167 read(buffer, write_x_first ? result.y : result.x);
168 return result;
169 }
170
176 [[nodiscard]] inline std::vector<uint8_t> to_buffer() const
177 {
178 std::vector<uint8_t> buffer(sizeof(affine_element));
180 return buffer;
181 }
182
184 {
188
189 affine_element result;
190 result.x = Fq::reconstruct_from_public(x_limbs);
191 result.y = Fq::reconstruct_from_public(y_limbs);
192
193 BB_ASSERT(result.on_curve());
194 return result;
195 }
196
197 friend std::ostream& operator<<(std::ostream& os, const affine_element& a)
198 {
199 os << "{ " << a.x << ", " << a.y << " }";
200 return os;
201 }
202
214 std::span<const Fr> scalars,
215 size_t max_num_bits = 0,
216 bool with_edgecases = true,
217 const Fr& masking_scalar = Fr(1)) noexcept;
218
221
222 // Concept to detect if Fq is a field2 type
223 template <typename T>
224 static constexpr bool is_field2_v = requires(T t) {
225 t.c0;
226 t.c1;
227 };
228
229 // Msgpack serialization optimized for single uint256_t or array of uint256_t
231 // For regular fields (uint256_t), use uint256_t directly
232 // For field2 types, use std::array<uint256_t, 2>
234
238 };
239
240 void msgpack_pack(auto& packer) const
241 {
242 MsgpackRawAffineElement raw_element{};
243
244 if (is_point_at_infinity()) {
245 // Set all bits to 1 for infinity representation
246 constexpr uint256_t all_ones = {
247 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL
248 };
249
250 if constexpr (is_field2_v<Fq>) {
251 raw_element.x = { all_ones, all_ones };
252 raw_element.y = { all_ones, all_ones };
253 } else {
254 raw_element.x = all_ones;
255 raw_element.y = all_ones;
256 }
257 } else {
258 // Note: field assignment operators internally call from_montgomery_form()
259 if constexpr (is_field2_v<Fq>) {
260 raw_element.x = { x.c0, x.c1 };
261 raw_element.y = { y.c0, y.c1 };
262 } else {
263 raw_element.x = x;
264 raw_element.y = y;
265 }
266 }
267 packer.pack(raw_element);
268 }
269
270 void msgpack_unpack(auto o)
271 {
272 MsgpackRawAffineElement raw_element = o;
273
274 // Check if this is point at infinity (all bits set)
275 constexpr uint256_t all_ones = {
276 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL
277 };
278
279 bool is_infinity;
280 if constexpr (is_field2_v<Fq>) {
281 is_infinity = (raw_element.x[0] == all_ones && raw_element.x[1] == all_ones &&
282 raw_element.y[0] == all_ones && raw_element.y[1] == all_ones);
283 } else {
284 is_infinity = (raw_element.x == all_ones && raw_element.y == all_ones);
285 }
286
287 if (is_infinity) {
289 } else {
290 // Note: field assignment operators internally call to_montgomery_form()
291 if constexpr (is_field2_v<Fq>) {
292 x.c0 = raw_element.x[0];
293 x.c1 = raw_element.x[1];
294 y.c0 = raw_element.y[0];
295 y.c1 = raw_element.y[1];
296 } else {
297 x = raw_element.x;
298 y = raw_element.y;
299 }
300 }
301 }
302 void msgpack_schema(auto& packer) const
303 {
304 std::string schema_name = msgpack_schema_name(*this);
305 if (packer.set_emitted(schema_name)) {
306 packer.pack(schema_name);
307 return; // already emitted
308 }
309 packer.pack_map(3);
310 packer.pack("__typename");
311 packer.pack(schema_name);
312 packer.pack("x");
313 packer.pack_schema(x);
314 packer.pack("y");
315 packer.pack_schema(y);
316 }
317};
318
319template <typename B, typename Fq_, typename Fr_, typename Params>
321{
322 using namespace serialize;
323 std::array<uint8_t, sizeof(element)> buffer;
324 read(it, buffer);
326 buffer.data(), /* use legacy field order */ true);
327}
328
329template <typename B, typename Fq_, typename Fr_, typename Params>
331{
332 using namespace serialize;
333 std::array<uint8_t, sizeof(element)> buffer;
335 element, buffer.data(), /* use legacy field order */ true);
336 write(it, buffer);
337}
338} // namespace bb::group_elements
339
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
friend std::ostream & operator<<(std::ostream &os, const affine_element &a)
static constexpr std::array< affine_element, 2 > from_compressed_unsafe(const uint256_t &compressed) noexcept
Reconstruct a point in affine coordinates from compressed form.
constexpr bool is_point_at_infinity() const noexcept
constexpr affine_element & operator=(const affine_element &other) noexcept=default
static constexpr affine_element hash_to_curve(const std::vector< uint8_t > &seed, uint8_t attempt_count=0) noexcept
Hash a seed buffer into a point.
static affine_element batch_mul(std::span< const affine_element > points, std::span< const Fr > scalars, size_t max_num_bits=0, bool with_edgecases=true, const Fr &masking_scalar=Fr(1)) noexcept
Multi-scalar multiplication: compute sum_i(scalars[i] * points[i])
static affine_element random_element(numeric::RNG *engine=nullptr) noexcept
Samples a random point on the curve.
std::vector< uint8_t > to_buffer() const
Serialize the point to a byte vector.
void msgpack_pack(auto &packer) const
constexpr uint256_t compress() const noexcept
static affine_element serialize_from_buffer(const uint8_t *buffer, bool write_x_first=false)
Restore point from a buffer.
constexpr void self_set_infinity() noexcept
constexpr affine_element & operator=(affine_element &&other) noexcept=default
static constexpr affine_element infinity()
constexpr bool operator<(const affine_element &other) const noexcept
static affine_element reconstruct_from_public(const std::span< const bb::fr, PUBLIC_INPUTS_SIZE > &limbs)
constexpr affine_element operator+(const affine_element &other) const noexcept
static constexpr affine_element from_compressed(const uint256_t &compressed) noexcept
Reconstruct a point in affine coordinates from compressed form.
constexpr bool on_curve() const noexcept
static constexpr affine_element one() noexcept
static constexpr size_t PUBLIC_INPUTS_SIZE
static constexpr std::optional< affine_element > derive_from_x_coordinate(const Fq &x, bool sign_bit) noexcept
static void serialize_to_buffer(const affine_element &value, uint8_t *buffer, bool write_x_first=false)
Serialize the point to the given buffer.
constexpr bool operator>(const affine_element &other) const noexcept
constexpr affine_element operator*(const Fr &exponent) const noexcept
void msgpack_schema(auto &packer) const
constexpr affine_element set_infinity() const noexcept
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
FF a
numeric::RNG & engine
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:34
void read(B &it, group_elements::affine_element< Fq_, Fr_, Params > &element)
void write(B &it, group_elements::affine_element< Fq_, Fr_, Params > const &element)
std::string msgpack_schema_name(g1::affine_element const &)
Definition g1.hpp:37
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr size_t PUBLIC_INPUTS_SIZE
static field reconstruct_from_public(const std::span< const field< V >, PUBLIC_INPUTS_SIZE > &limbs)
std::conditional_t< is_field2_v< Fq >, std::array< uint256_t, 2 >, uint256_t > FieldType