8#include "../bool/bool.hpp"
9#include "../byte_array/byte_array.hpp"
10#include "../field/field.hpp"
24#include <gtest/gtest.h>
48template <
template <
typename,
typename>
class BigField,
typename Builder,
typename Params>
53template <
template <
typename,
typename>
class BigField,
typename Builder,
typename Params>
89 uint512_t(fq_ct::get_maximum_unreduced_value()) - 1,
90 uint512_t(fq_ct::get_maximum_unreduced_value()),
91 uint512_t(fq_ct::get_maximum_unreduced_value()) + 1,
92 (
uint512_t(1) << (stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 4)) - 1,
102 EXPECT_EQ(val.get_value() >= fq_ct::modulus,
true);
105 EXPECT_EQ(result_check,
true);
127 fq_ct combined_a = fq_ct::unsafe_construct_from_limbs(limb_0, limb_1, limb_2, limb_3,
true);
128 combined_a.binary_basis_limbs[3].maximum_value = other_mask;
131 const bool limbs_less_than_max = (limb_0_native <= fq_ct::get_maximum_unreduced_limb_value()) &&
132 (limb_1_native <= fq_ct::get_maximum_unreduced_limb_value()) &&
133 (limb_2_native <= fq_ct::get_maximum_unreduced_limb_value()) &&
134 (limb_3_native <= fq_ct::get_maximum_unreduced_limb_value());
135 EXPECT_EQ(limbs_less_than_max,
true);
138 EXPECT_GT(combined_a.get_maximum_value(),
139 fq_ct::get_maximum_unreduced_value()
143 EXPECT_EQ(combined_a.get_value() > fq_ct::modulus,
true);
148 EXPECT_EQ(combined_a.get_maximum_value() <= fq_ct::get_maximum_unreduced_value(),
true);
151 EXPECT_EQ(result,
true);
173 fq_ct combined_a = fq_ct::unsafe_construct_from_limbs(limb_0, limb_1, limb_2, limb_3);
176 combined_a.binary_basis_limbs[0].maximum_value =
177 (
uint256_t(1) << fq_ct::MAX_UNREDUCED_LIMB_BITS) + 1000;
180 EXPECT_EQ(combined_a.get_maximum_value() <= fq_ct::get_maximum_unreduced_value(),
true);
187 EXPECT_EQ(combined_a.get_maximum_value() <= fq_ct::get_maximum_unreduced_value(),
true);
191 EXPECT_EQ(result,
true);
216 fq_ct combined_a = fq_ct::unsafe_construct_from_limbs(limb_0, limb_1, limb_2, limb_3);
217 combined_a.binary_basis_limbs[3].maximum_value = other_mask;
221 for (
size_t i = 0; i < 11; ++i) {
222 const uint64_t msb_index_before = combined_a.binary_basis_limbs[0].maximum_value.
get_msb();
223 combined_a = combined_a + combined_a;
224 const uint64_t msb_index_after = combined_a.binary_basis_limbs[0].maximum_value.get_msb();
227 EXPECT_EQ(msb_index_after, msb_index_before + 1ULL);
229 EXPECT_EQ(combined_a.binary_basis_limbs[0].maximum_value.get_msb(), fq_ct::MAX_UNREDUCED_LIMB_BITS);
230 EXPECT_EQ(combined_a.binary_basis_limbs[0].maximum_value > fq_ct::get_maximum_unreduced_limb_value(),
true);
233 combined_a = combined_a + combined_a;
234 EXPECT_EQ(combined_a.binary_basis_limbs[0].maximum_value.get_msb(), fq_ct::NUM_LIMB_BITS);
238 EXPECT_EQ(result,
true);
249 fr elt_native_hi =
fr(
uint256_t(elt_native).
slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4));
257 for (
size_t i = 0; i < 4; ++i) {
258 uint256_t witness_value =
uint256_t(field_element.binary_basis_limbs[i].element.get_value());
259 uint256_t max_value = field_element.binary_basis_limbs[i].maximum_value;
261 EXPECT_GE(max_value, witness_value)
262 <<
"invariant violation in " << operation_name <<
":\n limb[" << i <<
"] max_value:\n " << max_value
263 <<
" < \n witness_value\n " << witness_value;
267 uint256_t computed_prime = field_element.binary_basis_limbs[0].element.get_value();
268 computed_prime += field_element.binary_basis_limbs[1].element.get_value() * fq_ct::shift_1;
269 computed_prime += field_element.binary_basis_limbs[2].element.get_value() * fq_ct::shift_2;
270 computed_prime += field_element.binary_basis_limbs[3].element.get_value() * fq_ct::shift_3;
271 uint256_t actual_prime = field_element.prime_basis_limb.get_value();
273 EXPECT_EQ(
fr(computed_prime),
fr(actual_prime))
274 <<
"invariant violation in " << operation_name <<
":\n computed prime:\n " <<
fr(computed_prime)
275 <<
" != \n actual prime:\n " <<
fr(actual_prime);
278 for (
size_t i = 0; i < 4; ++i) {
279 uint64_t max_bits = field_element.binary_basis_limbs[i].maximum_value.get_msb() + 1;
281 EXPECT_LT(max_bits, fq_ct::PROHIBITED_LIMB_BITS)
282 <<
"invariant violation in " << operation_name <<
":\n limb[" << i <<
"] has " << max_bits
283 <<
" bits, which exceeds PROHIBITED_LIMB_BITS (" << fq_ct::PROHIBITED_LIMB_BITS <<
")";
288 template <
typename BinaryOp,
typename NativeOp>
291 const std::string& operation_name,
292 const bool skip_zero =
false)
300 fq_ct c_ct = binary_op(a_ct, b_ct);
301 fq_native c_native = native_op(a_native, b_native);
309 if (skip_zero && (is_fq_value_zero || is_fr_value_zero)) {
315 fq_ct edge_case = fq_ct::create_from_u512_as_witness(&
builder, edge_value,
true);
318 fq_ct result_ct = binary_op(c_ct, edge_case);
319 fq_native result_native = native_op(c_native, edge_native);
323 c_native = result_native;
330 if (skip_zero && (is_fq_value_zero || is_fr_value_zero)) {
336 fq_ct large_case = fq_ct::create_from_u512_as_witness(&
builder, large_value,
true);
339 fq_ct result_ct = binary_op(c_ct, large_case);
340 fq_native result_native = native_op(c_native, large_native);
344 c_native = result_native;
352 EXPECT_EQ(c_ct.get_value(),
uint512_t(c_native)) <<
"native check failed for " << operation_name <<
" (final)";
356 EXPECT_EQ(result,
true);
359#define INVARIANT_BINARY_OP_TEST(op_name, op_symbol, skip_zero) \
360 static void test_invariants_during_##op_name() \
362 test_invariants_during_binary_operation([](const fq_ct& a, const fq_ct& b) { return a op_symbol b; }, \
363 [](const fq_native& a, const fq_native& b) { return a op_symbol b; }, \
397 edge_case.assert_is_in_field();
401 EXPECT_EQ(result,
true);
411 fq_ct large_case = fq_ct::create_from_u512_as_witness(&
builder, large_value,
true);
412 large_case.assert_is_in_field();
415 EXPECT_EQ(result,
false);
420 EXPECT_EQ(
builder.err(),
"bigfield::unsafe_assert_less_than: r2 or r3 too large: hi limb.");
424 EXPECT_EQ(
builder.err(),
"bigfield::assert_less_than: limb 2 or 3 too large: hi limb.");
444 EXPECT_EQ(result,
true);
456 larger_value.assert_less_than(smaller_value);
459 EXPECT_EQ(result,
false);
460 EXPECT_EQ(
builder.err(),
"bigfield::unsafe_assert_less_than: r2 or r3 too large: hi limb.");
473 edge_case.reduce_mod_target_modulus();
476 EXPECT_EQ(edge_case.get_value() < fq_ct::modulus,
true);
477 EXPECT_EQ(edge_case.get_value(),
uint512_t(edge_case_native));
481 fq_ct large_case = fq_ct::create_from_u512_as_witness(&
builder, large_value,
true);
484 large_case.reduce_mod_target_modulus();
487 EXPECT_EQ(large_case.get_value() < fq_ct::modulus,
true);
488 EXPECT_EQ(large_case.get_value(),
uint512_t(large_case_native));
492 EXPECT_EQ(result,
true);
504 value_p_plus_n.assert_equal(value_n);
508 fq_ct random_plus_p =
510 random_plus_p.assert_equal(random_ct);
513 EXPECT_EQ(result,
true);
527 fq_ct output = a_ct / zero;
528 fq_ct output_modulus = a_ct / zero_modulus;
531 EXPECT_EQ(output.get_value(), 0);
532 EXPECT_EQ(output_modulus.get_value(), 0);
535 EXPECT_EQ(result,
false);
536 EXPECT_EQ(
builder.err(),
"bigfield: prime limb diff is zero, but expected non-zero");
547 fq_ct output = a_ct / zero;
550 EXPECT_EQ(output.get_value(), 0);
553 EXPECT_EQ(result,
false);
554 EXPECT_EQ(
builder.err(),
"bigfield: prime limb diff is zero, but expected non-zero");
563 fq_ct output = fq_ct::div_check_denominator_nonzero({}, zero);
566 EXPECT_EQ(output.get_value(), 0);
569 EXPECT_EQ(result,
false);
570 EXPECT_EQ(
builder.err(),
"bigfield: prime limb diff is zero, but expected non-zero");
581 EXPECT_THROW_OR_ABORT(a_ct / constant_zero,
"bigfield: prime limb diff is zero, but expected non-zero");
603 "bigfield: prime limb diff is zero, but expected non-zero");
610using CircuitTypes = testing::Types<typename bb::stdlib::bn254<UltraCircuitBuilder>::BaseField,
621 TestFixture::test_larger_than_bigfield_allowed();
625 TestFixture::test_reduction_check_works();
629 TestFixture::test_reduction_works_on_limb_overflow();
633 TestFixture::test_maximum_value_tracking_during_addition();
639 TestFixture::test_invariants_during_addition();
643 TestFixture::test_invariants_during_subtraction();
647 TestFixture::test_invariants_during_multiplication();
651 TestFixture::test_invariants_during_division();
655 TestFixture::test_invariants_during_squaring();
659 TestFixture::test_invariants_during_negation();
665 TestFixture::test_assert_is_in_field();
669 TestFixture::test_assert_is_in_field_fails();
673 TestFixture::test_assert_less_than();
677 TestFixture::test_assert_less_than_fails();
681 TestFixture::test_reduce_mod_target_modulus();
685 TestFixture::test_assert_equal_edge_case();
690 TestFixture::test_divide_by_zero_fails();
#define EXPECT_THROW_OR_ABORT(statement, matcher)
typename extract_builder< BigField >::type builder_t
typename extract_fq_params< BigField >::type params_t
typename extract_builder< BigField >::type builder_t
constexpr InputType operator!(InputType type)
#define INVARIANT_BINARY_OP_TEST(op_name, op_symbol, skip_zero)
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Represents a dynamic array of bytes in-circuit.
static void test_larger_than_bigfield_allowed()
stdlib::witness_t< Builder > witness_ct
static void test_invariants_during_negation()
static std::pair< fq_native, fq_ct > get_random_witness(Builder *builder, bool reduce_input=false)
static void test_assert_less_than_fails()
builder_t< BigField > Builder
static void test_invariants_during_binary_operation(BinaryOp binary_op, NativeOp native_op, const std::string &operation_name, const bool skip_zero=false)
static void test_assert_is_in_field_fails()
typename bb::stdlib::bn254< Builder >::ScalarField fr_ct
static void test_assert_less_than()
static void test_maximum_value_tracking_during_addition()
static const std::array< uint512_t, 10 > values_larger_than_bigfield
static void test_assert_equal_edge_case()
static void test_reduction_check_works()
static void test_reduce_mod_target_modulus()
static void test_reduction_works_on_limb_overflow()
static void test_assert_is_in_field()
static constexpr std::array< uint512_t, 5 > edge_case_values
static constexpr uint512_t reduction_upper_bound
static void test_invariants_during_squaring()
static void check_invariants(const fq_ct &field_element, const std::string &operation_name)
static void test_divide_by_zero_fails()
bb::field< params_t< BigField > > fq_native
ECCVMCircuitBuilder Builder
testing::Types< bb::UltraCircuitBuilder, bb::MegaCircuitBuilder > CircuitTypes
crypto::Poseidon2Bn254ScalarFieldParams Params
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(ShpleminiTest, TestSettings)
field< Bn254FrParams > fr
C slice(C const &container, size_t start)
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
#define STANDARD_TESTING_TAGS
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field reduce_once() const noexcept