24#include <gtest/gtest.h>
36template <
typename F> F create_element_with_limbs(uint64_t l0, uint64_t l1, uint64_t l2, uint64_t l3)
40 result.self_from_montgomery_form_reduced();
44#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
46 EXPECT_EQ(
result.data[0], l0);
47 EXPECT_EQ(
result.data[1], l1);
48 EXPECT_EQ(
result.data[2], l2);
49 EXPECT_EQ(
result.data[3], l3);
63 while (res >= F::modulus) {
71using PrimeFieldTypes = ::testing::Types<bb::fq, bb::fr, secp256k1::fq, secp256k1::fr, secp256r1::fq, secp256r1::fr>;
74using SqrtFieldTypes = ::testing::Types<bb::fq, bb::fr, secp256k1::fq, secp256r1::fq>;
106 constexpr F
a{ 0x01, 0x02, 0x03, 0x04 };
107 constexpr F
b{ 0x01, 0x02, 0x03, 0x04 };
109 constexpr F c{ 0x01, 0x02, 0x03, 0x05 };
110 constexpr F d{ 0x01, 0x02, 0x04, 0x04 };
111 constexpr F e{ 0x01, 0x03, 0x03, 0x04 };
112 constexpr F f{ 0x02, 0x02, 0x03, 0x04 };
113 static_assert(
a ==
b);
114 static_assert(!(
a == c));
115 static_assert(!(
a == d));
116 static_assert(!(
a == e));
117 static_assert(!(
a == f));
124 F modulus_form{ F::modulus.
data[0], F::modulus.data[1], F::modulus.data[2], F::modulus.data[3] };
125 EXPECT_TRUE(modulus_form.is_zero());
127 F prefix_match{ F::modulus.data[0], F::modulus.data[1], F::modulus.data[2], F::modulus.data[3] - 1 };
128 EXPECT_FALSE(prefix_match.is_zero());
130 F first_limb_only{ F::modulus.data[0], 0, 0, 0 };
131 EXPECT_FALSE(first_limb_only.is_zero());
138 constexpr F
a{ 0x01, 0x02, 0x03, 0x04 };
139 constexpr F
b{ 0x05, 0x06, 0x07, 0x08 };
142 constexpr F
sum =
a +
b;
143 constexpr F diff =
a -
b;
144 constexpr F prod =
a *
b;
145 constexpr F sq =
a.
sqr();
148 EXPECT_EQ(
sum,
a +
b);
149 EXPECT_EQ(diff,
a -
b);
150 EXPECT_EQ(prod,
a *
b);
151 EXPECT_EQ(sq,
a.
sqr());
158 constexpr uint256_t a{ 0x1111, 0x2222, 0x3333, 0x4444 };
161 static_assert(
a == c ||
a == c - F::modulus);
174 for (
size_t i = 0; i < 256; ++i) {
177 const uint256_t value(seed.data[0], seed.data[1] & 0x7FFFFFFFFFFFFFFFULL, 0, 0);
179 const F reduced = F(
value).from_montgomery_form_reduced();
180 EXPECT_EQ(reduced.data[0],
value.
data[0]);
181 EXPECT_EQ(reduced.data[1],
value.
data[1]);
182 EXPECT_TRUE(((reduced.data[2] | reduced.data[3]) == 0) && ((reduced.data[1] >> 63) == 0))
183 <<
"from_montgomery_form_reduced() must be canonical (< 2^127) for a 127-bit value";
195 uint256_t a_raw = TestFixture::get_random_element_raw();
196 uint256_t b_raw = TestFixture::get_random_element_raw();
212 uint256_t a_raw = TestFixture::get_random_element_raw();
213 uint256_t b_raw = TestFixture::get_random_element_raw();
229 uint256_t a_raw = TestFixture::get_random_element_raw();
230 uint256_t b_raw = TestFixture::get_random_element_raw();
246 uint256_t a_raw = TestFixture::get_random_element_raw();
261 uint256_t original = TestFixture::get_random_element_raw();
262 F field_element(original);
265 EXPECT_EQ(original, recovered);
276 F
a = F::random_element();
290 auto [is_sqr, root] = one.sqrt();
293 EXPECT_EQ(root.sqr(), one);
300 F
a = F::random_element();
302 auto [is_sqr, root] = a_sqr.
sqrt();
305 EXPECT_EQ(root.sqr(), a_sqr);
306 EXPECT_TRUE((root ==
a) || (root == -
a));
318 F x = F::random_element();
319 F lambda = F::cube_root_of_unity();
320 F lambda_x = x * lambda;
322 F x_cubed = x * x * x;
323 F lambda_x_cubed = lambda_x * lambda_x * lambda_x;
325 EXPECT_EQ(x_cubed, lambda_x_cubed);
337 F
a = F::random_element();
345 F
a = F::random_element();
353 F
a = F::random_element();
361 F
a = F::random_element();
372 constexpr size_t batch_size = 10;
377 for (
size_t i = 0; i < batch_size; ++i) {
378 elements[i] = F::random_element();
379 inverses[i] = elements[i];
382 F::batch_invert(&inverses[0], batch_size);
384 for (
size_t i = 0; i < batch_size; ++i) {
385 F product = elements[i] * inverses[i];
386 product = product.reduce_once().reduce_once();
387 EXPECT_EQ(product, F::one());
399 F
a = F::random_element();
403 F expected = a_copy + F(2);
404 EXPECT_EQ(
a, expected);
407 expected = a_copy + F(5);
408 EXPECT_EQ(
a, expected);
415 F
a = F::random_element();
421 EXPECT_EQ(
a, a_before + F(1));
428 F
a = F::random_element();
434 EXPECT_EQ(
a, a_old + F(1));
447 auto small_number = 10;
448 F small_field_elt = F(small_number).from_montgomery_form();
450 small_field_elt.data[0], small_field_elt.data[1], small_field_elt.data[2], small_field_elt.data[3]);
452 F big_field_elt = F(big_number).from_montgomery_form();
454 big_field_elt.data[0], big_field_elt.data[1], big_field_elt.data[2], big_field_elt.data[3]);
458 EXPECT_EQ(small_number_from_limbs, small_number);
459 EXPECT_EQ(big_number, big_number_from_limbs);
461 F
result = small_field_elt + big_field_elt;
467 bool is_gte_modulus = result_from_limbs >= F::modulus;
468 EXPECT_EQ(is_gte_modulus,
true);
485 0xDEADBEEFCAFEBABEULL, 0xFEDCBA9876543210ULL, 0x123456789ABCDEF0ULL, F::modulus.data[3] / 2
488 for (
size_t limb_idx = 0; limb_idx < 4; ++limb_idx) {
490 limbs[limb_idx] = limb_values[limb_idx];
492 F
a = create_element_with_limbs<F>(limbs[0], limbs[1], limbs[2], limbs[3]);
493 F
b = F::random_element();
500 EXPECT_EQ(
uint256_t(
sum), expected_sum.
lo) <<
"Add failed for limb " << limb_idx;
505 EXPECT_EQ(
uint256_t(diff), expected_diff.
lo) <<
"Sub failed for limb " << limb_idx;
510 EXPECT_EQ(
uint256_t(prod), expected_prod.
lo) <<
"Mul failed for limb " << limb_idx;
515 EXPECT_EQ(
uint256_t(sq), expected_sq.
lo) <<
"Sqr failed for limb " << limb_idx;
527 { { 0, 0x9876543210FEDCBAULL, 0, 0 } },
528 { { 0, 0, 0x1111222233334444ULL, 0 } },
529 { { 0, 0, 0, F::modulus.data[3] / 2 } } } };
534 for (
size_t i = 0; i < 4; ++i) {
535 elems[i] = create_element_with_limbs<F>(
536 limb_patterns[i][0], limb_patterns[i][1], limb_patterns[i][2], limb_patterns[i][3]);
541 for (
size_t i = 0; i < 4; ++i) {
542 for (
size_t j = 0; j < 4; ++j) {
543 F prod = elems[i] * elems[j];
545 EXPECT_EQ(
uint256_t(prod), expected_prod.
lo) <<
"Failed for limb " << i <<
" * limb " << j;
567 EXPECT_EQ(
uint256_t(sq), expected_sq.
lo) <<
"Sqr failed for (p - " <<
offset <<
")^2";
570 F a_plus_one =
a + F(1);
572 F prod =
a * a_plus_one;
575 <<
"Mul failed for (p - " <<
offset <<
") * (p - " <<
offset <<
" + 1)";
591 for (uint64_t
offset : offsets) {
593 if constexpr (F::modulus.data[3] >= MODULUS_TOP_LIMB_LARGE_THRESHOLD) {
597 F two_256_minus_p_elt(two_256_minus_p);
598 two_256_minus_p_elt.self_from_montgomery_form_reduced();
599 F p_minus_offset(F::modulus -
offset);
600 p_minus_offset.self_from_montgomery_form_reduced();
601 a = p_minus_offset + two_256_minus_p_elt;
605 for (
size_t i = 0; i < 4; ++i) {
606 EXPECT_EQ(
a.
data[i], 0xFFFFFFFFFFFFFFFFULL);
612 F p_minus_one(F::modulus - 1);
613 p_minus_one.self_from_montgomery_form_reduced();
614 F p_minus_offset(F::modulus -
offset);
615 p_minus_offset.self_from_montgomery_form_reduced();
616 a = p_minus_one + p_minus_offset;
620 F
b = F::random_element();
630 EXPECT_EQ(
uint256_t(diff), expected_diff.
lo) <<
"Sub failed for offset " <<
offset;
634 EXPECT_EQ(
uint256_t(prod), expected_prod.
lo) <<
"Mul failed for offset " <<
offset;
650 F
a = F::random_element();
652 EXPECT_EQ(actual, expected);
657#ifndef BB_NO_EXCEPTIONS
670 uint8_t* buf =
reinterpret_cast<uint8_t*
>(
buffer.data());
671 size_t buf_size =
buffer.size();
672 uint8_t* field_bytes =
nullptr;
673 for (
size_t i = 0; i + 33 <= buf_size; i++) {
674 if (buf[i] == 0xc4 && buf[i + 1] == 0x20) {
675 field_bytes = &buf[i + 2];
679 ASSERT_NE(field_bytes,
nullptr) <<
"Could not find 32-byte bin payload in msgpack buffer";
683 for (
int i = 31; i >= 0; i--) {
684 field_bytes[i] =
static_cast<uint8_t
>(non_canonical.
data[0] & 0xFF);
691 msgpack::object_handle oh = msgpack::unpack(
buffer.data(),
buffer.size());
700 GTEST_SKIP() <<
"Skipping: throw_or_abort calls abort() when BB_NO_EXCEPTIONS is defined";
714 constexpr uint256_t two_p = F::modulus + F::modulus;
717 for (
size_t i = 0; i < 100; i++) {
718 F
a = F::random_element();
724 ASSERT_LT(a_internal, two_p) <<
"Input not in coarse form";
730 EXPECT_LT(result_internal, two_p) <<
"Result of from_montgomery_form exceeds [0, 2p) range";
738 F p_minus_one(F::modulus - 1);
739 p_minus_one.self_from_montgomery_form();
740 F p_minus_offset_plus_one(F::modulus -
offset + 1);
741 p_minus_offset_plus_one.self_from_montgomery_form();
742 F
a = p_minus_one + p_minus_offset_plus_one;
746 ASSERT_LT(a_internal, two_p) <<
"Test setup: element not in valid range";
751 EXPECT_LT(result_internal, two_p)
752 <<
"Edge case: Result of from_montgomery_form exceeds [0, 2p) for offset " <<
offset;
762 constexpr uint256_t two_p = F::modulus + F::modulus;
765 for (
size_t i = 0; i < 100; i++) {
766 F
a = F::random_element();
772 ASSERT_LT(a_internal, two_p) <<
"Input not in coarse form";
778 EXPECT_LT(result_internal, two_p) <<
"Result of to_montgomery_form exceeds [0, 2p) range";
786 F p_minus_one(F::modulus - 1);
787 p_minus_one.self_from_montgomery_form();
788 F p_minus_offset_plus_one(F::modulus -
offset + 1);
789 p_minus_offset_plus_one.self_from_montgomery_form();
790 F
a = p_minus_one + p_minus_offset_plus_one;
794 ASSERT_LT(a_internal, two_p) <<
"Test setup: element not in valid range";
799 EXPECT_LT(result_internal, two_p)
800 <<
"Edge case: Result of to_montgomery_form exceeds [0, 2p) for offset " <<
offset;
static uint256_t get_random_element_raw()
virtual uint256_t get_random_uint256()=0
std::unique_ptr< uint8_t[]> buffer
uintx< uint256_t > uint512_t
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Entry point for Barretenberg command-line interface.
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
Inner sum(Cont< Inner, Args... > const &in)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
::testing::Types< bb::fq, bb::fr > TwoFiftyFourBitFieldTypes
::testing::Types< bb::fq, bb::fr, secp256k1::fq, secp256r1::fq > SqrtFieldTypes
::testing::Types< secp256k1::fq, secp256k1::fr > TwoFiftySixBitFieldTypes
::testing::Types< bb::fq, bb::fr, secp256k1::fq, secp256k1::fr, secp256r1::fq, secp256r1::fr > PrimeFieldTypes
::testing::Types< bb::fq, bb::fr, secp256k1::fq, secp256k1::fr > CubeRootFieldTypes
Field get(size_t i) const noexcept
BB_INLINE constexpr field from_montgomery_form_reduced() const noexcept
BB_INLINE constexpr field to_montgomery_form() const noexcept
BB_INLINE constexpr field pow(const uint256_t &exponent) const noexcept
BB_INLINE constexpr field sqr() const noexcept
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
BB_INLINE constexpr field from_montgomery_form() const noexcept
std::pair< T, T > msgpack_roundtrip(const T &object)