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: 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
17
18namespace bb::stdlib {
19
20template <typename Field> class StdlibCodec {
21 public:
22 using DataType = Field;
23 using Builder = typename Field::Builder;
28
39 template <typename T> static bool_t<Builder> check_point_at_infinity(std::span<const fr> fr_vec)
40 {
41 if constexpr (IsAnyOf<T, bn254_element>) {
42 // Sum the limbs and check whether the sum is 0
43 return (fr::accumulate(std::vector<fr>(fr_vec.begin(), fr_vec.end())).is_zero());
44 } else {
45 // Efficiently compute ((x^2 + 5 y^2) == 0)
46 const fr x_sqr = fr_vec[0].sqr();
47 const fr y = fr_vec[1];
48 const fr five_y = y * bb::fr(5);
49 return (y.madd(five_y, x_sqr).is_zero());
50 }
51 }
52
61 template <typename T> static T convert_challenge(const fr& challenge)
62 {
63 if constexpr (std::is_same_v<T, fr>) {
64 return challenge;
65 } else if constexpr (std::is_same_v<T, fq>) {
66 // Sanity check that the input challenge fits into the first 2 bigfield limbs.
67 BB_ASSERT_LT(static_cast<uint256_t>(challenge.get_value()).get_msb(),
68 T::NUM_LIMB_BITS * 2,
69 "field_conversion: convert_challenge");
70 Builder* builder = challenge.get_context();
71 // All challenges must be circuit witnesses.
73 ASSERT(!challenge.is_constant());
74 return T(challenge, fr::from_witness_index(builder, builder->zero_idx()));
75 }
76 }
77
78 static std::vector<fr> convert_goblin_fr_to_bn254_frs(const goblin_field<Builder>& input)
79 {
80 return { input.limbs[0], input.limbs[1] };
81 }
82
83 static std::vector<fr> convert_grumpkin_fr_to_bn254_frs(const fq& input)
84 {
85 static constexpr uint64_t NUM_LIMB_BITS = fq::NUM_LIMB_BITS;
86
87 static constexpr bb::fr shift(static_cast<uint256_t>(1) << NUM_LIMB_BITS);
88 std::vector<fr> result(2);
89 result[0] = input.binary_basis_limbs[0].element + (input.binary_basis_limbs[1].element * shift);
90 result[1] = input.binary_basis_limbs[2].element + (input.binary_basis_limbs[3].element * shift);
91 return result;
92 }
93
97 template <typename T> static constexpr size_t calc_num_fields()
98 {
99 if constexpr (IsAnyOf<T, fr>) {
101 } else if constexpr (IsAnyOf<T, fq, goblin_field<Builder>>) {
103 } else if constexpr (IsAnyOf<T, bn254_element, grumpkin_element>) {
104 return 2 * calc_num_fields<typename T::BaseField>();
105 } else {
106 // Array or Univariate
107 return calc_num_fields<typename T::value_type>() * (std::tuple_size<T>::value);
108 }
109 }
110
145 template <typename T> static T deserialize_from_fields(std::span<const fr> fr_vec)
146 {
147 using field_ct = fr;
148 using bigfield_ct = fq;
149
150 constexpr size_t expected_size = calc_num_fields<T>();
151 BB_ASSERT_EQ(fr_vec.size(), expected_size);
152
153 ASSERT(validate_context<Builder>(fr_vec));
154
155 if constexpr (IsAnyOf<T, field_ct>) {
156 // Case 1: input type matches the output type
157 return fr_vec[0];
158 } else if constexpr (IsAnyOf<T, bigfield_ct, goblin_field<Builder>>) {
159 // Cases 2 and 3: a bigfield/goblin_field element is reconstructed from low and high limbs.
160 return T(fr_vec[0], fr_vec[1]);
161 } else if constexpr (IsAnyOf<T, bn254_element, grumpkin_element>) {
162 // Case 4 and 5: Convert a vector of frs to a group element
163 using Basefield = typename T::BaseField;
164
165 constexpr size_t base_field_frs = expected_size / 2;
166
167 Basefield x = deserialize_from_fields<Basefield>(fr_vec.subspan(0, base_field_frs));
168 Basefield y = deserialize_from_fields<Basefield>(fr_vec.subspan(base_field_frs, base_field_frs));
169
170 T out(x, y, check_point_at_infinity<T>(fr_vec));
171 // Note that in the case of bn254 with Mega arithmetization, the check is delegated to ECCVM, see
172 // `on_curve_check` in `ECCVMTranscriptRelationImpl`.
173 out.validate_on_curve();
174 return out;
175 } else {
176 // Case 6: Array or Univariate
177 T val;
178 using element_type = typename T::value_type;
179 const size_t scalar_frs = calc_num_fields<element_type>();
180
181 size_t i = 0;
182 for (auto& x : val) {
183 x = deserialize_from_fields<element_type>(fr_vec.subspan(scalar_frs * i, scalar_frs));
184 ++i;
185 }
186 return val;
187 }
188 }
189
240 template <typename T> static std::vector<fr> serialize_to_fields(const T& val)
241 {
242 using field_ct = fr;
243 using bigfield_ct = fq;
244
245 if constexpr (IsAnyOf<T, field_ct>) {
246 return std::vector<T>{ val };
247 } else if constexpr (IsAnyOf<T, bigfield_ct>) {
249 } else if constexpr (IsAnyOf<T, goblin_field<Builder>>) {
251 } else if constexpr (IsAnyOf<T, bn254_element, grumpkin_element>) {
252 using BaseField = typename T::BaseField;
253
254 std::vector<field_ct> fr_vec_x = serialize_to_fields<BaseField>(val.x);
255 std::vector<field_ct> fr_vec_y = serialize_to_fields<BaseField>(val.y);
256 std::vector<field_ct> fr_vec(fr_vec_x.begin(), fr_vec_x.end());
257 fr_vec.insert(fr_vec.end(), fr_vec_y.begin(), fr_vec_y.end());
258 return fr_vec;
259 } else {
260 // Array or Univariate
262 for (auto& x : val) {
263 auto tmp_vec = serialize_to_fields<typename T::value_type>(x);
264 fr_vec.insert(fr_vec.end(), tmp_vec.begin(), tmp_vec.end());
265 }
266 return fr_vec;
267 }
268 }
277 static std::array<fr, 2> split_challenge(const fr& challenge)
278 {
279 const size_t lo_bits = fr::native::Params::MAX_BITS_PER_ENDOMORPHISM_SCALAR;
280 // Constuct a unique lo/hi decomposition of the challenge (hi_bits will be 254 - 128 = 126)
281 const auto [lo, hi] = split_unique(challenge, lo_bits);
282 return std::array<fr, 2>{ lo, hi };
283 }
284
295 template <typename TargetType> static TargetType deserialize_from_frs(std::span<fr> elements, size_t& num_frs_read)
296 {
297 constexpr size_t num_frs = calc_num_fields<TargetType>();
298 BB_ASSERT_GTE(elements.size(), num_frs_read + num_frs);
299 TargetType result = deserialize_from_fields<TargetType>(elements.subspan(num_frs_read, num_frs));
300 num_frs_read += num_frs;
301 return result;
302 }
303};
304} // namespace bb::stdlib
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:133
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:148
#define ASSERT(expression,...)
Definition assert.hpp:77
static constexpr size_t NUM_BN254_SCALARS
Definition fq.hpp:162
static constexpr size_t NUM_BN254_SCALARS
Definition fr.hpp:167
constexpr uint64_t get_msb() const
static constexpr size_t calc_num_fields()
Calculates the size of a type (in its native form) in terms of frs.
bigfield< Builder, bb::Bn254FqParams > fq
typename Field::Builder Builder
static std::vector< fr > convert_goblin_fr_to_bn254_frs(const goblin_field< Builder > &input)
static std::vector< fr > convert_grumpkin_fr_to_bn254_frs(const fq &input)
static bool_t< Builder > check_point_at_infinity(std::span< const fr > fr_vec)
Check whether a point corresponds to (0, 0), the conventional representation of the point infinity.
static T convert_challenge(const fr &challenge)
A stdlib Transcript method needed to convert an fr challenge to a bigfield one. Assumes that challeng...
static std::array< fr, 2 > split_challenge(const fr &challenge)
Split a challenge field element into two half-width challenges.
static T deserialize_from_fields(std::span< const fr > fr_vec)
Core stdlib Transcript deserialization method.
static TargetType deserialize_from_frs(std::span< fr > elements, size_t &num_frs_read)
A stdlib VerificationKey-specific method.
static std::vector< fr > serialize_to_fields(const T &val)
Core stdlib Transcript serialization method.
element< Builder, fq, fr, curve::BN254::Group > bn254_element
std::array< Limb, NUM_LIMBS > binary_basis_limbs
Represents a bigfield element in the binary basis. A bigfield element is represented as a combination...
Definition bigfield.hpp:80
Implements boolean logic in-circuit.
Definition bool.hpp:59
cycle_group represents a group Element of the proving system's embedded curve, i.e....
field_t madd(const field_t &to_mul, const field_t &to_add) const
Definition field.cpp:509
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:61
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
Definition field.cpp:1157
Builder * get_context() const
Definition field.hpp:397
field_t sqr() const
Definition field.hpp:258
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:829
bool_t< Builder > is_zero() const
Validate whether a field_t element is zero.
Definition field.cpp:776
bool is_constant() const
Definition field.hpp:407
goblin_field wraps x/y coordinates of bn254 group elements when using goblin
std::array< field_ct, 2 > limbs
AluTraceBuilder builder
Definition alu.test.cpp:123
std::pair< field_t< Builder >, field_t< Builder > > split_unique(const field_t< Builder > &field, const size_t lo_bits, const bool skip_range_constraints)
Split a bn254 scalar field element into unique lo and hi limbs.
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
field< Bn254FrParams > fr
Definition fr.hpp:174
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13