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: 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
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 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 }
204
205 // Concept to detect if Fq is a field2 type
206 template <typename T>
207 static constexpr bool is_field2_v = requires(T t) {
208 t.c0;
209 t.c1;
210 };
211
212 // Msgpack serialization optimized for single uint256_t or array of uint256_t
214 // For regular fields (uint256_t), use uint256_t directly
215 // For field2 types, use std::array<uint256_t, 2>
217
221 };
222
223 void msgpack_pack(auto& packer) const
224 {
225 MsgpackRawAffineElement raw_element{};
226
227 if (is_point_at_infinity()) {
228 // Set all bits to 1 for infinity representation
229 constexpr uint256_t all_ones = {
230 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL
231 };
232
233 if constexpr (is_field2_v<Fq>) {
234 raw_element.x = { all_ones, all_ones };
235 raw_element.y = { all_ones, all_ones };
236 } else {
237 raw_element.x = all_ones;
238 raw_element.y = all_ones;
239 }
240 } else {
241 // Note: field assignment operators internally call from_montgomery_form()
242 if constexpr (is_field2_v<Fq>) {
243 raw_element.x = { x.c0, x.c1 };
244 raw_element.y = { y.c0, y.c1 };
245 } else {
246 raw_element.x = x;
247 raw_element.y = y;
248 }
249 }
250 packer.pack(raw_element);
251 }
252
253 void msgpack_unpack(auto o)
254 {
255 MsgpackRawAffineElement raw_element = o;
256
257 // Check if this is point at infinity (all bits set)
258 constexpr uint256_t all_ones = {
259 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL, 0xffffffffffffffffUL
260 };
261
262 bool is_infinity;
263 if constexpr (is_field2_v<Fq>) {
264 is_infinity = (raw_element.x[0] == all_ones && raw_element.x[1] == all_ones &&
265 raw_element.y[0] == all_ones && raw_element.y[1] == all_ones);
266 } else {
267 is_infinity = (raw_element.x == all_ones && raw_element.y == all_ones);
268 }
269
270 if (is_infinity) {
272 } else {
273 // Note: field assignment operators internally call to_montgomery_form()
274 if constexpr (is_field2_v<Fq>) {
275 x.c0 = raw_element.x[0];
276 x.c1 = raw_element.x[1];
277 y.c0 = raw_element.y[0];
278 y.c1 = raw_element.y[1];
279 } else {
280 x = raw_element.x;
281 y = raw_element.y;
282 }
283 }
284 }
285 void msgpack_schema(auto& packer) const
286 {
287 std::string schema_name = msgpack_schema_name(*this);
288 if (packer.set_emitted(schema_name)) {
289 packer.pack(schema_name);
290 return; // already emitted
291 }
292 packer.pack_map(3);
293 packer.pack("__typename");
294 packer.pack(schema_name);
295 packer.pack("x");
296 packer.pack_schema(x);
297 packer.pack("y");
298 packer.pack_schema(y);
299 }
300};
301
302template <typename B, typename Fq_, typename Fr_, typename Params>
304{
305 using namespace serialize;
306 std::array<uint8_t, sizeof(element)> buffer;
307 read(it, buffer);
309 buffer.data(), /* use legacy field order */ true);
310}
311
312template <typename B, typename Fq_, typename Fr_, typename Params>
314{
315 using namespace serialize;
316 std::array<uint8_t, sizeof(element)> buffer;
318 element, buffer.data(), /* use legacy field order */ true);
319 write(it, buffer);
320}
321} // namespace bb::group_elements
322
#define BB_ASSERT(expression,...)
Definition assert.hpp:67
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 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
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