5#include <gtest/gtest.h>
51 std::array<uint32_t, 4> limb_indices;
52 limb_indices[0] =
builder.add_variable(limbs[0]);
53 limb_indices[1] =
builder.add_variable(limbs[1]);
54 limb_indices[2] =
builder.add_variable(limbs[2]);
55 limb_indices[3] =
builder.add_variable(limbs[3]);
78 a_indices, b_indices, q_indices, r_indices, modulus_limbs,
80 const auto [lo_1_idx, hi_1_idx] =
builder.evaluate_non_native_field_multiplication(
inputs);
82 return { lo_1_idx, hi_1_idx };
124 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
125 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
126 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
136 std::array<uint32_t, 4> x_idx, y_idx;
137 for (
size_t i = 0; i < 4; i++) {
141 uint32_t x_p_idx =
builder.add_variable(
data.x_prime);
142 uint32_t y_p_idx =
builder.add_variable(
data.y_prime);
149 auto limbp = std::make_tuple(x_p_idx, y_p_idx,
data.addconstp);
151 return { limb0, limb1, limb2, limb3, limbp };
163 return builder.queue_partial_non_native_field_multiplication(input);
186 fr lo_0 =
a[0] *
b[0] + ((
a[1] *
b[0] +
a[0] *
b[1]) * LIMB_SHIFT);
187 fr hi_0 =
a[2] *
b[0] +
a[0] *
b[2] + ((
a[0] *
b[3] +
a[3] *
b[0]) * LIMB_SHIFT);
188 fr hi_1 = hi_0 +
a[1] *
b[1] + ((
a[1] *
b[2] +
a[2] *
b[1]) * LIMB_SHIFT);
190 return { lo_0, hi_1 };
197 const size_t num_iterations = 50;
198 for (
size_t i = 0; i < num_iterations; i++) {
205 auto [q, r] = compute_quotient_remainder(
a,
b, modulus);
206 const auto [lo_1_idx, hi_1_idx] = create_non_native_multiplication(
builder,
a,
b, q, r, modulus);
211 if (is_low_70_bits && is_high_70_bits) {
213 builder.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70);
216 builder.create_limbed_range_constraint(lo_1_idx, 72);
217 builder.create_limbed_range_constraint(hi_1_idx, 72);
230 uint256_t a =
uint256_t(
"0x00ab1504deacff852326adf4a01099e9340f232e2a631042852fce3c4eb8a51b");
231 uint256_t b =
uint256_t(
"0x1be457323502cfcd85f8cfa54c8c4fea146b9db2a7d86b29d966d61b714ee249");
232 uint256_t q_expected =
uint256_t(
"0x00629b9d576dfc6b5c28a4a254d5e8e3384124f6a898858e95265254a01414d5");
233 uint256_t r_expected =
uint256_t(
"0x2c1590eb70a48dce72f7686bbf79b59bf7926c99bc16aba92e474c65a04ea2a0");
237 auto [q_computed, r_computed] = compute_quotient_remainder(
a,
b, modulus);
238 EXPECT_EQ(q_computed, q_expected);
239 EXPECT_EQ(r_computed, r_expected);
243 const auto [lo_1_idx, hi_1_idx] = create_non_native_multiplication(
builder,
a,
b, q_expected, r_expected, modulus);
250 builder.create_limbed_range_constraint(lo_1_idx, 72);
251 builder.create_limbed_range_constraint(hi_1_idx, 72);
255 builder.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70);
257 EXPECT_EQ(
builder.err(),
"range_constrain_two_limbs: hi limb.");
266 auto data = create_random_add_sub_data();
267 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
268 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
275 auto data = create_random_add_sub_data();
278 data.addconsts = {
fr(100),
fr(200),
fr(300),
fr(400) };
281 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
282 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
289 auto data = create_random_add_sub_data();
293 data.addconstp =
fr(-100);
295 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
296 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
304 .x_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
305 .y_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
308 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
309 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
310 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
313 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
314 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
327 .x_limbs = { val0, val1, val2, val3 },
328 .y_limbs = { val0, val1, val2, val3 },
331 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
332 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
333 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
336 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
337 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
348 auto data = create_random_add_sub_data();
349 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
350 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
357 auto data = create_random_add_sub_data();
360 data.addconsts = {
fr(100),
fr(200),
fr(300),
fr(400) };
363 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
364 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
371 auto data = create_random_add_sub_data();
375 data.addconstp =
fr(-100);
377 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
378 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
386 .x_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
387 .y_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
390 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
391 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
392 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
395 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
396 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
409 .x_limbs = { val0, val1, val2, val3 },
410 .y_limbs = { val0, val1, val2, val3 },
413 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
414 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
415 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
418 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
419 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
428 auto test_incorrect_qr = [](
bool tamper_q,
size_t limb_idx) {
434 auto [q, r] = compute_quotient_remainder(
a,
b, modulus);
439 auto q_limbs = split_into_limbs(
uint256_t(q));
440 q_limbs[limb_idx] +=
fr(1);
442 (
uint256_t(q_limbs[2]) << (LIMB_BITS * 2)) + (
uint256_t(q_limbs[3]) << (LIMB_BITS * 3));
445 auto r_limbs = split_into_limbs(
uint256_t(r));
446 r_limbs[limb_idx] +=
fr(1);
448 (
uint256_t(r_limbs[2]) << (LIMB_BITS * 2)) + (
uint256_t(r_limbs[3]) << (LIMB_BITS * 3));
452 const auto [lo_idx, hi_idx] = create_non_native_multiplication(
builder,
a,
b, q, r, modulus);
455 builder.create_limbed_range_constraint(lo_idx, 72);
456 builder.create_limbed_range_constraint(hi_idx, 72);
462 for (
size_t limb = 0; limb < 4; limb++) {
463 test_incorrect_qr(
true, limb);
464 test_incorrect_qr(
false, limb);
471 const size_t num_iterations = 10;
472 for (
size_t i = 0; i < num_iterations; i++) {
478 const auto [lo_0_idx, hi_1_idx] = create_and_queue_partial_multiplication(
builder, a_limbs, b_limbs);
481 auto [expected_lo_0, expected_hi_1] = compute_expected_partial_products(a_limbs, b_limbs);
482 EXPECT_EQ(
builder.get_variable(lo_0_idx), expected_lo_0);
483 EXPECT_EQ(
builder.get_variable(hi_1_idx), expected_hi_1);
498 const auto a_indices = get_limb_witness_indices(
builder, a_limbs);
499 const auto b_indices = get_limb_witness_indices(
builder, b_limbs);
502 const size_t num_duplicates = 5;
504 for (
size_t i = 0; i < num_duplicates; i++) {
506 results.push_back(
builder.queue_partial_non_native_field_multiplication(input));
510 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), num_duplicates);
519 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 1U);
522 EXPECT_EQ(
builder.blocks.nnf.size(), NNF_GATES_PER_PARTIAL_MUL + NNF_ENSURE_NONZERO_PADDING);
525 auto [expected_lo_0, expected_hi_1] = compute_expected_partial_products(a_limbs, b_limbs);
526 for (
const auto& result : results) {
527 EXPECT_EQ(
builder.get_variable(result[0]), expected_lo_0);
528 EXPECT_EQ(
builder.get_variable(result[1]), expected_hi_1);
540 const auto a1_indices = get_limb_witness_indices(
builder, a_limbs);
541 const auto b1_indices = get_limb_witness_indices(
builder, b_limbs);
542 const auto a2_indices = get_limb_witness_indices(
builder, a_limbs);
543 const auto b2_indices = get_limb_witness_indices(
builder, b_limbs);
547 for (
size_t i = 0; i < 4; i++) {
548 builder.assert_equal(a1_indices[i], a2_indices[i]);
549 builder.assert_equal(b1_indices[i], b2_indices[i]);
555 builder.queue_partial_non_native_field_multiplication(input1);
556 builder.queue_partial_non_native_field_multiplication(input2);
559 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 2U);
568 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 1U);
571 EXPECT_EQ(
builder.blocks.nnf.size(), NNF_GATES_PER_PARTIAL_MUL + NNF_ENSURE_NONZERO_PADDING);
579 const size_t num_multiplications = 5;
585 for (
size_t i = 0; i < num_multiplications; i++) {
586 a_values[i] = random_limbs();
587 b_values[i] = random_limbs();
588 results[i] = create_and_queue_partial_multiplication(
builder, a_values[i], b_values[i]);
592 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), num_multiplications);
601 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), num_multiplications);
604 EXPECT_EQ(
builder.blocks.nnf.size(), num_multiplications * NNF_GATES_PER_PARTIAL_MUL + NNF_ENSURE_NONZERO_PADDING);
607 for (
size_t i = 0; i < num_multiplications; i++) {
608 auto [expected_lo_0, expected_hi_1] = compute_expected_partial_products(a_values[i], b_values[i]);
609 EXPECT_EQ(
builder.get_variable(results[i][0]), expected_lo_0);
610 EXPECT_EQ(
builder.get_variable(results[i][1]), expected_hi_1);
622 uint32_t a_idx =
builder.add_variable(
a);
623 uint32_t b_idx =
builder.add_variable(
b);
624 uint32_t c_idx =
builder.add_variable(
a +
b);
625 builder.create_add_gate({ a_idx, b_idx, c_idx,
fr(1),
fr(1),
fr(-1),
fr(0) });
628 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 0U);
637 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 0U);
640 EXPECT_EQ(
builder.blocks.nnf.size(), NNF_ENSURE_NONZERO_PADDING);
#define BB_ASSERT(expression,...)
Test suite for UltraCircuitBuilder non-native field methods.
static AddSubData create_random_add_sub_data()
static const uint512_t BINARY_BASIS_MODULUS
static std::array< fr, 4 > random_limbs()
std::tuple< scaled_witness, scaled_witness, fr > add_simple
static std::pair< uint256_t, uint256_t > compute_quotient_remainder(const uint256_t &a, const uint256_t &b, const uint256_t &modulus)
static std::array< uint32_t, 2 > create_and_queue_partial_multiplication(UltraCircuitBuilder &builder, const std::array< fr, 4 > &a_limbs, const std::array< fr, 4 > &b_limbs)
static std::tuple< add_simple, add_simple, add_simple, add_simple, std::tuple< uint32_t, uint32_t, fr > > create_add_sub_inputs(UltraCircuitBuilder &builder, const AddSubData &data)
static std::array< uint32_t, 2 > create_non_native_multiplication(UltraCircuitBuilder &builder, const uint256_t &a, const uint256_t &b, const uint256_t &q, const uint256_t &r, const uint256_t &modulus)
std::pair< uint32_t, fr > scaled_witness
static std::pair< fr, fr > compute_expected_partial_products(const std::array< fr, 4 > &a, const std::array< fr, 4 > &b)
static std::array< fr, 4 > split_into_limbs(const uint512_t &input)
static constexpr size_t NNF_ENSURE_NONZERO_PADDING
static std::array< uint32_t, 4 > get_limb_witness_indices(UltraCircuitBuilder &builder, const std::array< fr, 4 > &limbs)
static constexpr size_t LIMB_BITS
static constexpr size_t NNF_GATES_PER_PARTIAL_MUL
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS
constexpr uint64_t get_msb() const
constexpr uintx slice(const uint64_t start, const uint64_t end) const
const std::vector< MemoryValue > data
uintx< uint256_t > uint512_t
Entry point for Barretenberg command-line interface.
field< Bn254FrParams > fr
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::array< fr, 4 > addconsts
std::array< fr, 4 > x_scales
std::array< fr, 4 > y_limbs
std::array< fr, 4 > y_scales
std::array< fr, 4 > x_limbs
static constexpr uint256_t modulus
static field random_element(numeric::RNG *engine=nullptr) noexcept
std::array< uint32_t, 4 > a
TEST_F(UltraCircuitBuilderNonNative, Multiplication)