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.decompose_into_default_range(lo_1_idx, 72);
217 builder.decompose_into_default_range(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.decompose_into_default_range(lo_1_idx, 72);
251 builder.decompose_into_default_range(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.");
269 auto [q, r] = compute_quotient_remainder(
a,
b, modulus);
270 const auto [lo_1_idx, hi_1_idx] = create_non_native_multiplication(
builder,
a,
b, q, r, modulus);
275 if (is_low_70_bits && is_high_70_bits) {
276 builder.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70);
278 builder.decompose_into_default_range(lo_1_idx, 72);
279 builder.decompose_into_default_range(hi_1_idx, 72);
285 for (
size_t i = 0; i <
builder.blocks.nnf.size(); ++i) {
286 EXPECT_EQ(
builder.blocks.nnf.q_arith()[i], 0);
287 EXPECT_EQ(
builder.blocks.nnf.q_delta_range()[i], 0);
288 EXPECT_EQ(
builder.blocks.nnf.q_elliptic()[i], 0);
289 EXPECT_EQ(
builder.blocks.nnf.q_lookup()[i], 0);
290 EXPECT_EQ(
builder.blocks.nnf.q_poseidon2_external()[i], 0);
291 EXPECT_EQ(
builder.blocks.nnf.q_poseidon2_internal()[i], 0);
301 auto data = create_random_add_sub_data();
302 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
303 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
310 auto data = create_random_add_sub_data();
313 data.addconsts = {
fr(100),
fr(200),
fr(300),
fr(400) };
316 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
317 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
324 auto data = create_random_add_sub_data();
328 data.addconstp =
fr(-100);
330 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
331 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
339 .x_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
340 .y_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
343 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
344 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
345 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
348 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
349 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
362 .x_limbs = { val0, val1, val2, val3 },
363 .y_limbs = { val0, val1, val2, val3 },
366 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
367 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
368 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
371 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
372 builder.evaluate_non_native_field_addition(limb0, limb1, limb2, limb3, limbp);
383 auto data = create_random_add_sub_data();
384 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
385 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
392 auto data = create_random_add_sub_data();
395 data.addconsts = {
fr(100),
fr(200),
fr(300),
fr(400) };
398 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
399 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
406 auto data = create_random_add_sub_data();
410 data.addconstp =
fr(-100);
412 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
413 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
421 .x_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
422 .y_limbs = {
fr(0),
fr(0),
fr(0),
fr(0) },
425 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
426 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
427 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
430 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
431 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
444 .x_limbs = { val0, val1, val2, val3 },
445 .y_limbs = { val0, val1, val2, val3 },
448 .x_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
449 .y_scales = {
fr(1),
fr(1),
fr(1),
fr(1) },
450 .addconsts = {
fr(0),
fr(0),
fr(0),
fr(0) },
453 auto [limb0, limb1, limb2, limb3, limbp] = create_add_sub_inputs(
builder,
data);
454 builder.evaluate_non_native_field_subtraction(limb0, limb1, limb2, limb3, limbp);
463 auto test_incorrect_qr = [](
bool tamper_q,
size_t limb_idx) {
469 auto [q, r] = compute_quotient_remainder(
a,
b, modulus);
474 auto q_limbs = split_into_limbs(
uint256_t(q));
475 q_limbs[limb_idx] +=
fr(1);
477 (
uint256_t(q_limbs[2]) << (LIMB_BITS * 2)) + (
uint256_t(q_limbs[3]) << (LIMB_BITS * 3));
480 auto r_limbs = split_into_limbs(
uint256_t(r));
481 r_limbs[limb_idx] +=
fr(1);
483 (
uint256_t(r_limbs[2]) << (LIMB_BITS * 2)) + (
uint256_t(r_limbs[3]) << (LIMB_BITS * 3));
487 const auto [lo_idx, hi_idx] = create_non_native_multiplication(
builder,
a,
b, q, r, modulus);
490 builder.decompose_into_default_range(lo_idx, 72);
491 builder.decompose_into_default_range(hi_idx, 72);
497 for (
size_t limb = 0; limb < 4; limb++) {
498 test_incorrect_qr(
true, limb);
499 test_incorrect_qr(
false, limb);
506 const size_t num_iterations = 10;
507 for (
size_t i = 0; i < num_iterations; i++) {
513 const auto [lo_0_idx, hi_1_idx] = create_and_queue_partial_multiplication(
builder, a_limbs, b_limbs);
516 auto [expected_lo_0, expected_hi_1] = compute_expected_partial_products(a_limbs, b_limbs);
517 EXPECT_EQ(
builder.get_variable(lo_0_idx), expected_lo_0);
518 EXPECT_EQ(
builder.get_variable(hi_1_idx), expected_hi_1);
533 const auto a_indices = get_limb_witness_indices(
builder, a_limbs);
534 const auto b_indices = get_limb_witness_indices(
builder, b_limbs);
537 const size_t num_duplicates = 5;
539 for (
size_t i = 0; i < num_duplicates; i++) {
541 results.push_back(
builder.queue_partial_non_native_field_multiplication(input));
545 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), num_duplicates);
551 builder.finalize_circuit(
true);
554 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 1U);
557 EXPECT_EQ(
builder.blocks.nnf.size(), NNF_GATES_PER_PARTIAL_MUL + NNF_ENSURE_NONZERO_PADDING);
560 auto [expected_lo_0, expected_hi_1] = compute_expected_partial_products(a_limbs, b_limbs);
561 for (
const auto& result : results) {
562 EXPECT_EQ(
builder.get_variable(result[0]), expected_lo_0);
563 EXPECT_EQ(
builder.get_variable(result[1]), expected_hi_1);
575 const auto a1_indices = get_limb_witness_indices(
builder, a_limbs);
576 const auto b1_indices = get_limb_witness_indices(
builder, b_limbs);
577 const auto a2_indices = get_limb_witness_indices(
builder, a_limbs);
578 const auto b2_indices = get_limb_witness_indices(
builder, b_limbs);
582 for (
size_t i = 0; i < 4; i++) {
583 builder.assert_equal(a1_indices[i], a2_indices[i]);
584 builder.assert_equal(b1_indices[i], b2_indices[i]);
590 builder.queue_partial_non_native_field_multiplication(input1);
591 builder.queue_partial_non_native_field_multiplication(input2);
594 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 2U);
600 builder.finalize_circuit(
true);
603 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 1U);
606 EXPECT_EQ(
builder.blocks.nnf.size(), NNF_GATES_PER_PARTIAL_MUL + NNF_ENSURE_NONZERO_PADDING);
614 const size_t num_multiplications = 5;
620 for (
size_t i = 0; i < num_multiplications; i++) {
621 a_values[i] = random_limbs();
622 b_values[i] = random_limbs();
623 results[i] = create_and_queue_partial_multiplication(
builder, a_values[i], b_values[i]);
627 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), num_multiplications);
633 builder.finalize_circuit(
true);
636 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), num_multiplications);
639 EXPECT_EQ(
builder.blocks.nnf.size(), num_multiplications * NNF_GATES_PER_PARTIAL_MUL + NNF_ENSURE_NONZERO_PADDING);
642 for (
size_t i = 0; i < num_multiplications; i++) {
643 auto [expected_lo_0, expected_hi_1] = compute_expected_partial_products(a_values[i], b_values[i]);
644 EXPECT_EQ(
builder.get_variable(results[i][0]), expected_lo_0);
645 EXPECT_EQ(
builder.get_variable(results[i][1]), expected_hi_1);
657 uint32_t a_idx =
builder.add_variable(
a);
658 uint32_t b_idx =
builder.add_variable(
b);
659 uint32_t c_idx =
builder.add_variable(
a +
b);
660 builder.create_add_gate({ a_idx, b_idx, c_idx,
fr(1),
fr(1),
fr(-1),
fr(0) });
663 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 0U);
669 builder.finalize_circuit(
true);
672 EXPECT_EQ(
builder.cached_partial_non_native_field_multiplications.size(), 0U);
675 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)