Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field_conversion.test.cpp
Go to the documentation of this file.
4#include <gtest/gtest.h>
5
7
8class FieldConversionTest : public ::testing::Test {
9 public:
10 template <typename T> void check_conversion(T x)
11 {
12 size_t len = FrCodec::calc_num_fields<T>();
13 auto frs = FrCodec::serialize_to_fields(x);
14 EXPECT_EQ(len, frs.size());
15 auto y = FrCodec::deserialize_from_fields<T>(frs);
16 EXPECT_EQ(x, y);
17 }
18};
19
23TEST_F(FieldConversionTest, FieldConversionUint32)
24{
25 auto x = static_cast<uint32_t>(1) << 31;
26 check_conversion(x);
27}
28
32TEST_F(FieldConversionTest, FieldConversionFr)
33{
34 bb::fr x1(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); // 256 bits
35 check_conversion(x1);
36
37 bb::fr x2(bb::fr::modulus_minus_two); // modulus - 2
38 check_conversion(x2);
39}
40
45TEST_F(FieldConversionTest, FieldConversionGrumpkinFr)
46{
47 grumpkin::fr x1(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); // 256 bits
48 check_conversion(x1);
49}
50
51namespace {
52bb::fq derive_bn254_y(bb::fq x)
53{
54 auto [found, y] = (x.sqr() * x + Bn254G1Params::b).sqrt();
55 EXPECT_TRUE(found);
56 return y;
57}
58} // namespace
59
64TEST_F(FieldConversionTest, FieldConversionBN254AffineElement)
65{
66 curve::BN254::AffineElement x1(1, derive_bn254_y(1));
67 check_conversion(x1);
68
70 check_conversion(x2);
71}
72
73namespace {
74bb::grumpkin::fq derive_grumpkin_y(bb::grumpkin::fq x)
75{
76 auto [found, y] = (x.sqr() * x + grumpkin::G1Params::b + x * grumpkin::G1Params::a).sqrt();
77 EXPECT_TRUE(found);
78 return y;
79}
80} // namespace
81
85TEST_F(FieldConversionTest, FieldConversionGrumpkinAffineElement)
86{
87 curve::Grumpkin::AffineElement x1(1, derive_grumpkin_y(1));
88 check_conversion(x1);
89
91 check_conversion(x2);
92}
93
98TEST_F(FieldConversionTest, FieldConversionArrayBn254Fr)
99{
100 std::array<bb::fr, 4> x1{ 1, 2, 3, 4 };
101 check_conversion(x1);
102
105 215215125,
106 102701750,
107 367032,
108 12985028,
109 bb::fr::modulus_minus_two - 125015028 };
110 check_conversion(x2);
111}
112
117TEST_F(FieldConversionTest, FieldConversionArrayGrumpkinFr)
118{
119 std::array<grumpkin::fr, 4> x1{ 1, 2, 3, 4 };
120 check_conversion(x1);
121
124 215215125,
125 102701750,
126 367032,
127 12985028,
129 check_conversion(x2);
130}
131
136TEST_F(FieldConversionTest, FieldConversionUnivariateBn254Fr)
137{
138 std::array<bb::fr, 4> x1_arr{ 1, 2, 3, 4 };
139 bb::Univariate<bb::fr, 4> x1{ x1_arr };
140 check_conversion(x1);
141}
142
147TEST_F(FieldConversionTest, FieldConversionUnivariateGrumpkinFr)
148{
149 std::array<grumpkin::fr, 4> x1_arr{ 1, 2, 3, 4 };
151 check_conversion(x1);
152}
153
157TEST_F(FieldConversionTest, ConvertShortChallenge)
158{
159 constexpr size_t SHORT_BITS = 2 * stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION;
160 const uint256_t raw(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789"));
161 const bb::fr chal(raw.slice(0, SHORT_BITS));
162
163 EXPECT_EQ(FrCodec::convert_short_challenge<bb::fr>(chal), chal);
164 EXPECT_EQ(uint256_t(FrCodec::convert_short_challenge<grumpkin::fr>(chal)), uint256_t(chal));
165}
166
171TEST_F(FieldConversionTest, ConvertFullChallenge)
172{
173 const bb::fr chal = bb::fr::random_element();
174
175 EXPECT_EQ(FrCodec::convert_full_challenge<bb::fr>(chal), chal);
176 EXPECT_EQ(uint256_t(FrCodec::convert_full_challenge<grumpkin::fr>(chal)), uint256_t(chal));
177}
178
179// ============================================================================
180// Additional FrCodec-specific tests
181// Note: Most rejection/acceptance tests are in stdlib/primitives/field/field_conversion.test.cpp
182// which tests both FrCodec and StdlibCodec together for consistency.
183// ============================================================================
184
189TEST_F(FieldConversionTest, AcceptCanonicalPointAtInfinity)
190{
191 // Test for BN254 points
192 {
193 std::vector<bb::fr> fr_vec = { bb::fr(0), bb::fr(0), bb::fr(0), bb::fr(0) };
194 auto point = FrCodec::deserialize_from_fields<curve::BN254::AffineElement>(fr_vec);
195 EXPECT_TRUE(point.is_point_at_infinity());
196 }
197
198 // Test for Grumpkin points
199 {
200 std::vector<bb::fr> fr_vec = { bb::fr(0), bb::fr(0) };
201 auto point = FrCodec::deserialize_from_fields<curve::Grumpkin::AffineElement>(fr_vec);
202 EXPECT_TRUE(point.is_point_at_infinity());
203 }
204}
205
211#ifndef __wasm__
212TEST_F(FieldConversionTest, RejectNonCanonicalFieldElements)
213{
214 using BN254Point = curve::BN254::AffineElement;
218
219 // BN254: Reject x-coordinate >= modulus
220 {
221 std::vector<bb::fr> vec = { bb::fr(fq::modulus.data[0]), bb::fr(fq::modulus.data[1]), bb::fr(0), bb::fr(0) };
222 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<BN254Point>(vec), "canonical");
223 }
224
225 // BN254: Reject y-coordinate >= modulus
226 {
227 std::vector<bb::fr> vec = { bb::fr(0), bb::fr(0), bb::fr(fq::modulus.data[0]), bb::fr(fq::modulus.data[1]) };
228 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<BN254Point>(vec), "canonical");
229 }
230
231 // BN254: Reject both coordinates >= modulus
232 {
233 std::vector<bb::fr> vec = { bb::fr(fq::modulus.data[0]),
236 bb::fr(fq::modulus.data[1]) };
237 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<BN254Point>(vec), "canonical");
238 }
239
240 // Grumpkin: Reject coordinate >= modulus (uses 2-limb encoding: 136-bit + 118-bit)
241 {
242 constexpr uint64_t LIMB_BITS = 68;
243 uint256_t gq_lo = gq::modulus & ((uint256_t(1) << (LIMB_BITS * 2)) - 1);
244 uint256_t gq_hi = gq::modulus >> (LIMB_BITS * 2);
245 std::vector<bb::fr> vec = { bb::fr(gq_lo), bb::fr(gq_hi) };
246 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<GrumpkinPoint>(vec), "canonical");
247 }
248
249 // Grumpkin: Reject limb overflow (lower limb must be < 2^136)
250 {
251 constexpr uint64_t LIMB_BITS = 68;
252 std::vector<bb::fr> vec = { bb::fr(uint256_t(1) << (LIMB_BITS * 2)), bb::fr(0) };
253 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<GrumpkinPoint>(vec), "Conversion error");
254 }
255
256 // Grumpkin: Reject limb overflow (upper limb must be < 2^118)
257 {
258 constexpr uint64_t LIMB_BITS = 68;
259 std::vector<bb::fr> vec = { bb::fr(0), bb::fr(uint256_t(1) << (254 - LIMB_BITS * 2)) };
260 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<GrumpkinPoint>(vec), "Conversion error");
261 }
262}
263#endif
264
269#ifndef __wasm__
270TEST_F(FieldConversionTest, RejectPointNotOnCurve)
271{
272 // Test for BN254: (1, 4) is not on the curve
273 {
274 std::vector<bb::fr> fr_vec = { bb::fr(1), bb::fr(0), bb::fr(4), bb::fr(0) };
275 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<curve::BN254::AffineElement>(fr_vec), "on_curve");
276 }
277
278 // Test for Grumpkin: (12, 100) is not on the curve
279 {
280 std::vector<bb::fr> fr_vec = { bb::fr(12), bb::fr(100) };
281 EXPECT_THROW_OR_ABORT(FrCodec::deserialize_from_fields<curve::Grumpkin::AffineElement>(fr_vec), "on_curve");
282 }
283}
284#endif
285
286// ============================================================================
287// U256Codec canonical checks
288// ============================================================================
289
293TEST_F(FieldConversionTest, U256CodecAcceptsCanonicalFr)
294{
295 // Zero
296 {
298 auto result = U256Codec::deserialize_from_fields<bb::fr>(vec);
299 EXPECT_EQ(result, bb::fr(0));
300 }
301 // One
302 {
304 auto result = U256Codec::deserialize_from_fields<bb::fr>(vec);
305 EXPECT_EQ(result, bb::fr(1));
306 }
307 // modulus - 1 (largest canonical value)
308 {
310 auto result = U256Codec::deserialize_from_fields<bb::fr>(vec);
311 EXPECT_EQ(result, bb::fr(bb::fr::modulus - 1));
312 }
313}
314
318TEST_F(FieldConversionTest, U256CodecAcceptsCanonicalFq)
319{
320 using fq = grumpkin::fr;
322 auto result = U256Codec::deserialize_from_fields<fq>(vec);
323 EXPECT_EQ(result, fq(0));
324
325 vec = { uint256_t(fq::modulus) - 1 };
326 result = U256Codec::deserialize_from_fields<fq>(vec);
327 EXPECT_EQ(result, fq(fq::modulus - 1));
328}
329
334#ifndef __wasm__
335TEST_F(FieldConversionTest, U256CodecRejectsNonCanonicalFr)
336{
337 // fr::modulus itself (v + 0*p where v=0 but encoded as p)
338 {
340 EXPECT_THROW_OR_ABORT(U256Codec::deserialize_from_fields<bb::fr>(vec), "Non-canonical");
341 }
342 // fr::modulus + 1
343 {
345 EXPECT_THROW_OR_ABORT(U256Codec::deserialize_from_fields<bb::fr>(vec), "Non-canonical");
346 }
347 // 2 * fr::modulus (another alias for 0)
348 {
350 EXPECT_THROW_OR_ABORT(U256Codec::deserialize_from_fields<bb::fr>(vec), "Non-canonical");
351 }
352}
353
354TEST_F(FieldConversionTest, U256CodecRejectsNonCanonicalFq)
355{
356 using fq = grumpkin::fr;
357 // fq::modulus itself
358 {
360 EXPECT_THROW_OR_ABORT(U256Codec::deserialize_from_fields<fq>(vec), "Non-canonical");
361 }
362 // fq::modulus + 1
363 {
365 EXPECT_THROW_OR_ABORT(U256Codec::deserialize_from_fields<fq>(vec), "Non-canonical");
366 }
367}
368#endif
369
370} // namespace bb::field_conversion_tests
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:223
static std::vector< fr > serialize_to_fields(const T &val)
Conversion from transcript values to bb::frs.
A univariate polynomial represented by its values on {0, 1,..., domain_end - 1}.
bb::fq BaseField
Definition bn254.hpp:19
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
TEST_F(FieldConversionTest, FieldConversionUint32)
Field conversion test for uint32_t.
field< Bn254FqParams > fq
Definition fq.hpp:153
field< Bn254FrParams > fr
Definition fr.hpp:155
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
uint8_t len
std::byte * data
static constexpr fq b
Definition g1.hpp:30
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
static constexpr uint256_t modulus_minus_two
static constexpr bb::fr b
Definition grumpkin.hpp:30
static constexpr bb::fr a
Definition grumpkin.hpp:32
VectorField result