Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field_conversion.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [Raju], 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 "barretenberg/stdlib/primitives/bigfield/constants.hpp" // NUM_LIMB_BITS_IN_FIELD_SIMULATION
16
17namespace bb {
18
19class FrCodec {
20 public:
22 using fr = bb::fr;
26
27 // Size calculators
28 template <typename T> static constexpr size_t calc_num_fields()
29 {
31 return 1;
32 } else if constexpr (IsAnyOf<T, bb::fr, fq>) {
33 return T::Params::NUM_BN254_SCALARS;
35 return 2 * calc_num_fields<typename T::Fq>();
36 } else {
37 // Array or Univariate
38 return calc_num_fields<typename T::value_type>() * (std::tuple_size<T>::value);
39 }
40 }
41
49 template <typename T> static bool check_point_at_infinity(std::span<const bb::fr> fr_vec)
50 {
51 // Check if all limbs are zero - this is the only canonical representation of infinity
52 for (const auto& limb : fr_vec) {
53 if (!limb.is_zero()) {
54 return false;
55 }
56 }
57 return true;
58 }
59
66 {
67 // expects 2 fr limbs; caller already asserts size
68 constexpr uint64_t NUM_LIMB_BITS = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION; // 68
69 constexpr uint64_t TOTAL_BITS = 254;
70
71 BB_ASSERT_LT(uint256_t(fr_vec[0]),
72 (uint256_t(1) << (NUM_LIMB_BITS * 2)),
73 "Conversion error here usually implies some bad proof serde or parsing");
74 BB_ASSERT_LT(uint256_t(fr_vec[1]),
75 (uint256_t(1) << (TOTAL_BITS - NUM_LIMB_BITS * 2)),
76 "Conversion error here usually implies some bad proof serde or parsing");
77
78 const uint256_t value = uint256_t(fr_vec[0]) + (uint256_t(fr_vec[1]) << (NUM_LIMB_BITS * 2));
79
80 // Reject aliased values to ensure canonical representation.
81 // This matches the circuit behavior in StdlibCodec where assert_is_in_field is called.
82 BB_ASSERT_LT(value, fq::modulus, "Non-canonical field element: value >= fq::modulus");
83
84 return fq(value);
85 }
86
90 static std::vector<bb::fr> convert_grumpkin_fr_to_bn254_frs(const fq& val)
91 {
92 constexpr uint64_t NUM_LIMB_BITS = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION; // 68
93 constexpr uint64_t TOTAL_BITS = 254;
94
95 constexpr uint64_t LOWER_BITS = 2 * NUM_LIMB_BITS; // 136
96 constexpr uint256_t LOWER_MASK = (uint256_t(1) << LOWER_BITS) - 1;
97
98 const uint256_t value = uint256_t(val);
99 BB_ASSERT_LT(value, (uint256_t(1) << TOTAL_BITS));
100
101 std::vector<bb::fr> out(2);
102 out[0] = static_cast<uint256_t>(value & LOWER_MASK);
103 out[1] = static_cast<uint256_t>(value >> LOWER_BITS);
104
105 BB_ASSERT_LT(static_cast<uint256_t>(out[1]), (uint256_t(1) << (TOTAL_BITS - LOWER_BITS)));
106 return out;
107 }
108
109 // ---------------------------------------------------------------------
110 // Deserialize
111 // ---------------------------------------------------------------------
112 template <typename T> static T deserialize_from_fields(std::span<const fr> fr_vec)
113 {
114 BB_ASSERT_EQ(fr_vec.size(), calc_num_fields<T>());
115 if constexpr (IsAnyOf<T, bool>) {
116 return static_cast<bool>(fr_vec[0]);
117 } else if constexpr (IsAnyOf<T, uint32_t, uint64_t, bb::fr>) {
118 return static_cast<T>(fr_vec[0]);
119 } else if constexpr (IsAnyOf<T, fq>) {
122 using BaseField = typename T::Fq;
123 constexpr size_t BASE = calc_num_fields<BaseField>();
124
125 // Check for point at infinity BEFORE deserializing to avoid alias issues.
126 // Only canonical (0,0) with all-zero limbs is accepted as infinity.
127 // This matches circuit behavior in StdlibCodec::check_point_at_infinity.
128 if (check_point_at_infinity<T>(fr_vec)) {
129 return T::infinity();
130 }
131
132 // Deserialize coordinates (this will reject non-canonical values via BB_ASSERT)
133 T val;
134 val.x = deserialize_from_fields<BaseField>(fr_vec.subspan(0, BASE));
135 val.y = deserialize_from_fields<BaseField>(fr_vec.subspan(BASE, BASE));
136 if (!val.on_curve()) {
137 throw_or_abort("Deserialized point is not on the curve");
138 }
139 return val;
140 } else {
141 // Array or Univariate
142 T val;
143 constexpr size_t SZ = calc_num_fields<typename T::value_type>();
144 size_t i = 0;
145 for (auto& x : val) {
146 x = deserialize_from_fields<typename T::value_type>(fr_vec.subspan(SZ * i, SZ));
147 ++i;
148 }
149 return val;
150 }
151 }
152
156 template <typename T> static std::vector<fr> serialize_to_fields(const T& val)
157 {
159 return { val };
160 } else if constexpr (IsAnyOf<T, fq>) {
163 using BaseField = typename T::Fq;
164 std::vector<bb::fr> fr_vec_x =
165 val.is_point_at_infinity() ? serialize_to_fields(BaseField::zero()) : serialize_to_fields(val.x);
166 std::vector<bb::fr> fr_vec_y =
167 val.is_point_at_infinity() ? serialize_to_fields(BaseField::zero()) : serialize_to_fields(val.y);
168 // Use move + append to avoid iterator-based insert that triggers GCC false positive
169 std::vector<bb::fr> fr_vec = std::move(fr_vec_x);
170 fr_vec.reserve(fr_vec.size() + fr_vec_y.size());
171 for (auto& e : fr_vec_y) {
172 fr_vec.push_back(std::move(e));
173 }
174 return fr_vec;
175 } else {
176 // Array or Univariate
177 std::vector<fr> out;
178 for (auto& x : val) {
179 auto tmp = serialize_to_fields(x);
180 for (auto& e : tmp) {
181 out.push_back(std::move(e));
182 }
183 }
184 return out;
185 }
186 }
187
197 {
198 static constexpr size_t TOTAL_BITS = bb::fr::modulus.get_msb() + 1; // 254
199 static constexpr size_t LO_BITS = TOTAL_BITS / 2; // 127
200 static constexpr size_t HI_BITS = TOTAL_BITS - LO_BITS; // 127
201
202 const uint256_t u = static_cast<uint256_t>(challenge);
203 const uint256_t lo = u.slice(0, LO_BITS);
204 const uint256_t hi = u.slice(LO_BITS, LO_BITS + HI_BITS);
205
206 return { bb::fr(lo), bb::fr(hi) };
207 }
208
212 template <typename T> static T convert_challenge(const bb::fr& challenge)
213 {
214 if constexpr (std::is_same_v<T, bb::fr>) {
215 return challenge;
216 } else if constexpr (std::is_same_v<T, fq>) {
217 BB_ASSERT_LT(static_cast<uint256_t>(challenge).get_msb(),
218 2 * stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION,
219 "field_conversion: convert challenge");
220 return fq(challenge);
221 }
222 }
223};
224
226 public:
228 using fr = bb::fr;
232
233 // Size calculators
234 template <typename T> static constexpr size_t calc_num_fields()
235 {
237 return 1;
239 // In contrast to bb::fr, bn254 points can be represented by only 2 uint256_t elements
240 return 2;
241 } else {
242 // Array or Univariate
243 return calc_num_fields<typename T::value_type>() * (std::tuple_size<T>::value);
244 }
245 }
246
247 // ---------------------------------------------------------------------
248 // Deserialize
249 // ---------------------------------------------------------------------
250 template <typename T> static T deserialize_from_fields(std::span<const uint256_t> vec)
251 {
252 BB_ASSERT_EQ(vec.size(), calc_num_fields<T>());
253 if constexpr (IsAnyOf<T, bool>) {
254 return static_cast<bool>(vec[0]);
255 } else if constexpr (IsAnyOf<T, bb::fr>) {
257 vec[0], uint256_t(bb::fr::modulus), "Non-canonical scalar field element: value >= fr::modulus");
258 return static_cast<T>(vec[0]);
259 } else if constexpr (IsAnyOf<T, fq>) {
260 BB_ASSERT_LT(vec[0], uint256_t(fq::modulus), "Non-canonical base field element: value >= fq::modulus");
261 return static_cast<T>(vec[0]);
262 } else if constexpr (IsAnyOf<T, uint32_t, uint64_t, uint256_t>) {
263 return static_cast<T>(vec[0]);
265 using BaseField = typename T::Fq;
266 constexpr size_t N = calc_num_fields<BaseField>();
267 T val;
268 val.x = deserialize_from_fields<BaseField>(vec.subspan(0, N));
269 val.y = deserialize_from_fields<BaseField>(vec.subspan(N, N));
270 if (val.x == BaseField::zero() && val.y == BaseField::zero()) {
271 val.self_set_infinity();
272 }
273 if (!val.on_curve()) {
274 throw_or_abort("Deserialized point is not on the curve");
275 }
276 return val;
277 } else {
278 // Array or Univariate
279 T val;
280 constexpr size_t SZ = calc_num_fields<typename T::value_type>();
281 size_t i = 0;
282 for (auto& x : val) {
283 x = deserialize_from_fields<typename T::value_type>(vec.subspan(SZ * i, SZ));
284 ++i;
285 }
286 return val;
287 }
288 }
289
293 template <typename T> static std::vector<uint256_t> serialize_to_fields(const T& val)
294 {
296 return { val };
298 using BaseField = typename T::Fq;
299 std::vector<uint256_t> uint256_vec_x;
300 std::vector<uint256_t> uint256_vec_y;
301 // When encountering a point at infinity we pass a zero point in the proof to ensure that on the receiving
302 // size there are no inconsistencies whenre constructing and hashing.
303 if (val.is_point_at_infinity()) {
304 uint256_vec_x = serialize_to_fields(BaseField::zero());
305 uint256_vec_y = serialize_to_fields(BaseField::zero());
306 } else {
307 uint256_vec_x = serialize_to_fields<BaseField>(val.x);
308 uint256_vec_y = serialize_to_fields<BaseField>(val.y);
309 }
310 std::vector<uint256_t> uint256_vec(uint256_vec_x.begin(), uint256_vec_x.end());
311 uint256_vec.insert(uint256_vec.end(), uint256_vec_y.begin(), uint256_vec_y.end());
312 return uint256_vec;
313 } else {
314 // Array or Univariate
316 for (auto& e : val) {
317 auto tmp = serialize_to_fields(e);
318 out.insert(out.end(), tmp.begin(), tmp.end());
319 }
320 return out;
321 }
322 }
323
333 {
334 static constexpr size_t TOTAL_BITS = bb::fr::modulus.get_msb() + 1; // 254
335 static constexpr size_t LO_BITS = TOTAL_BITS / 2; // 127
336 static constexpr size_t HI_BITS = TOTAL_BITS - LO_BITS; // 127
337
338 const uint256_t u = static_cast<uint256_t>(challenge);
339 const uint256_t lo = u.slice(0, LO_BITS);
340 const uint256_t hi = u.slice(LO_BITS, LO_BITS + HI_BITS);
341
342 return { uint256_t(lo), uint256_t(hi) };
343 }
344
348 template <typename T> static T convert_challenge(const bb::fr& challenge)
349 {
350 if constexpr (std::is_same_v<T, bb::fr>) {
351 return challenge;
352 } else if constexpr (std::is_same_v<T, fq>) {
353 BB_ASSERT_LT(static_cast<uint256_t>(challenge).get_msb(),
354 2 * stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION,
355 "field_conversion: convert challenge");
356 return fq(challenge);
357 }
358 }
359};
360
361} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
curve::BN254::AffineElement bn254_commitment
grumpkin::fr fq
static std::vector< fr > serialize_to_fields(const T &val)
Conversion from transcript values to bb::frs.
static std::array< bb::fr, 2 > split_challenge(const bb::fr &challenge)
Split a challenge field element into two equal-width challenges.
static bool check_point_at_infinity(std::span< const bb::fr > fr_vec)
Check whether raw limbs represent the point at infinity (all limbs zero).
static T convert_challenge(const bb::fr &challenge)
Convert an fr challenge to a target type (fr or fq). Assumes challenge is "short".
static fq convert_grumpkin_fr_from_bn254_frs(std::span< const bb::fr > fr_vec)
Converts 2 bb::fr elements to fq.
static std::vector< bb::fr > convert_grumpkin_fr_to_bn254_frs(const fq &val)
Converts fq to 2 bb::fr elements (inverse of the above).
static T deserialize_from_fields(std::span< const fr > fr_vec)
curve::Grumpkin::AffineElement grumpkin_commitment
static constexpr size_t calc_num_fields()
curve::BN254::AffineElement bn254_commitment
curve::Grumpkin::AffineElement grumpkin_commitment
static constexpr size_t calc_num_fields()
static std::array< uint256_t, 2 > split_challenge(const uint256_t &challenge)
Split a challenge field element into two equal-width challenges.
static T convert_challenge(const bb::fr &challenge)
Convert an fr challenge to a target type (fr or fq). Assumes challenge is "short".
static std::vector< uint256_t > serialize_to_fields(const T &val)
Conversion from transcript values to uint256_ts.
static T deserialize_from_fields(std::span< const uint256_t > vec)
typename Group::affine_element AffineElement
Definition bn254.hpp:22
typename Group::affine_element AffineElement
Definition grumpkin.hpp:64
constexpr uint256_t slice(uint64_t start, uint64_t end) const
constexpr uint64_t get_msb() const
constexpr T get_msb(const T in)
Definition get_msb.hpp:50
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
field< Bn254FrParams > fr
Definition fr.hpp:155
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr uint256_t modulus
void throw_or_abort(std::string const &err)