From b61dacee47f57a8fce6657f28b64e7a3128d0dba Mon Sep 17 00:00:00 2001 From: guipublic <47281315+guipublic@users.noreply.github.com> Date: Fri, 2 Feb 2024 16:54:37 +0100 Subject: [PATCH] feat: implementation for bigint opcodes (#4288) This PR implements bigint opcodes in barretenberg. It mainly implements a wrapper around the bigint ids that Noir uses, through a map id -> bigfield However, because you can use custom bigint modulus in Noir, and because modulus is hardcoded through template types in Barretenberg, the code (and the id->bigfield map) is duplicated for the 6 modulus type (base and scalar fields for bn254, secp256r1/k1) --------- Co-authored-by: ludamad Co-authored-by: kevaundray --- .../dsl/acir_format/acir_format.cpp | 14 +- .../dsl/acir_format/acir_format.hpp | 2 + .../dsl/acir_format/acir_format.test.cpp | 6 + .../acir_format/acir_to_constraint_buf.hpp | 7 +- .../dsl/acir_format/bigint_constraint.cpp | 461 +++++++++++++++++- .../dsl/acir_format/bigint_constraint.hpp | 176 ++++++- .../acir_format/bigint_constraint.test.cpp | 356 ++++++++++++-- .../dsl/acir_format/block_constraint.test.cpp | 1 + .../dsl/acir_format/ec_operations.test.cpp | 1 + .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 3 + .../dsl/acir_format/ecdsa_secp256r1.test.cpp | 4 + .../acir_format/recursion_constraint.test.cpp | 2 + 12 files changed, 982 insertions(+), 51 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index dfe00b03703..6831103c3c3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -1,10 +1,14 @@ #include "acir_format.hpp" #include "barretenberg/common/log.hpp" +#include "barretenberg/dsl/acir_format/bigint_constraint.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include namespace acir_format { +template class DSLBigInts; +template class DSLBigInts; + template void build_constraints(Builder& builder, AcirFormat const& constraint_system, bool has_valid_witness_assignments) { @@ -90,11 +94,15 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo } // Add big_int constraints + DSLBigInts dsl_bigints; + for (const auto& constraint : constraint_system.bigint_from_le_bytes_constraints) { + create_bigint_from_le_bytes_constraint(builder, constraint, dsl_bigints); + } for (const auto& constraint : constraint_system.bigint_operations) { - create_bigint_operations_constraint(builder, constraint); + create_bigint_operations_constraint(constraint, dsl_bigints); } - for (const auto& constraint : constraint_system.bigint_from_le_bytes_constraints) { - create_bigint_from_le_bytes_constraint(builder, constraint); + for (const auto& constraint : constraint_system.bigint_to_le_bytes_constraints) { + create_bigint_to_le_bytes_constraint(builder, constraint, dsl_bigints); } // TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 3c053d83814..6ccf0371774 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -48,6 +48,7 @@ struct AcirFormat { std::vector ec_add_constraints; std::vector recursion_constraints; std::vector bigint_from_le_bytes_constraints; + std::vector bigint_to_le_bytes_constraints; std::vector bigint_operations; // A standard plonk arithmetic constraint, as defined in the poly_triple struct, consists of selector values @@ -80,6 +81,7 @@ struct AcirFormat { constraints, block_constraints, bigint_from_le_bytes_constraints, + bigint_to_le_bytes_constraints, bigint_operations); friend bool operator==(AcirFormat const& lhs, AcirFormat const& rhs) = default; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 8908b348096..fe34de33aca 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -48,6 +48,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = { constraint }, .block_constraints = {}, @@ -161,6 +162,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = { expr_a, expr_b, expr_c, expr_d }, .block_constraints = {} }; @@ -226,6 +228,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = { poly_triple{ .a = schnorr_constraint.result, @@ -319,6 +322,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = { poly_triple{ .a = schnorr_constraint.result, @@ -431,6 +435,7 @@ TEST_F(AcirFormatTests, TestVarKeccak) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = { dummy }, .block_constraints = {}, @@ -475,6 +480,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {} }; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index 52dd9935241..a967b01b647 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -256,6 +256,11 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .modulus = map(arg.modulus, [](auto& e) -> uint32_t { return e; }), .result = arg.output, }); + } else if constexpr (std::is_same_v) { + af.bigint_to_le_bytes_constraints.push_back(BigIntToLeBytes{ + .input = arg.input, + .result = map(arg.outputs, [](auto& e) { return e.value; }), + }); } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ .lhs = arg.lhs, @@ -268,7 +273,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .lhs = arg.lhs, .rhs = arg.rhs, .result = arg.output, - .opcode = BigIntOperationType::Neg, + .opcode = BigIntOperationType::Sub, }); } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp index 4780e5ca36c..f4d5ea9def0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp @@ -1,33 +1,464 @@ #include "bigint_constraint.hpp" +#include "barretenberg/common/assert.hpp" #include "barretenberg/dsl/types.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" +#include +#include namespace acir_format { -template void create_bigint_operations_constraint(Builder& builder, const BigIntOperation& input) +ModulusId modulus_param_to_id(ModulusParam param) { - // TODO - (void)builder; - info(input); + if (Bn254FqParams::modulus_0 == param.modulus_0 && Bn254FqParams::modulus_1 == param.modulus_1 && + Bn254FqParams::modulus_2 == param.modulus_2 && Bn254FqParams::modulus_3 == param.modulus_3) { + return ModulusId::BN254_FQ; + } + if (Bn254FrParams::modulus_0 == param.modulus_0 && Bn254FrParams::modulus_1 == param.modulus_1 && + Bn254FrParams::modulus_2 == param.modulus_2 && Bn254FrParams::modulus_3 == param.modulus_3) { + return ModulusId::BN254_FR; + } + if (secp256k1::Secp256k1FqParams::modulus_0 == param.modulus_0 && + secp256k1::Secp256k1FqParams::modulus_1 == param.modulus_1 && + secp256k1::Secp256k1FqParams::modulus_2 == param.modulus_2 && + secp256k1::Secp256k1FqParams::modulus_3 == param.modulus_3) { + return ModulusId::SECP256K1_FQ; + } + if (secp256k1::Secp256k1FrParams::modulus_0 == param.modulus_0 && + secp256k1::Secp256k1FrParams::modulus_1 == param.modulus_1 && + secp256k1::Secp256k1FrParams::modulus_2 == param.modulus_2 && + secp256k1::Secp256k1FrParams::modulus_3 == param.modulus_3) { + return ModulusId::SECP256K1_FR; + } + if (secp256r1::Secp256r1FqParams::modulus_0 == param.modulus_0 && + secp256r1::Secp256r1FqParams::modulus_1 == param.modulus_1 && + secp256r1::Secp256r1FqParams::modulus_2 == param.modulus_2 && + secp256r1::Secp256r1FqParams::modulus_3 == param.modulus_3) { + return ModulusId::SECP256R1_FQ; + } + if (secp256r1::Secp256r1FrParams::modulus_0 == param.modulus_0 && + secp256r1::Secp256r1FrParams::modulus_1 == param.modulus_1 && + secp256r1::Secp256r1FrParams::modulus_2 == param.modulus_2 && + secp256r1::Secp256r1FrParams::modulus_3 == param.modulus_3) { + return ModulusId::SECP256R1_FR; + } + + return ModulusId::UNKNOWN; +} + +template void create_bigint_operations_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint); +template void create_bigint_operations_constraint( + const BigIntOperation& input, DSLBigInts& dsl_bigint); +template void create_bigint_addition_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint); +template void create_bigint_addition_constraint( + const BigIntOperation& input, DSLBigInts& dsl_bigint); +template void create_bigint_sub_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint); +template void create_bigint_sub_constraint( + const BigIntOperation& input, DSLBigInts& dsl_bigint); +template void create_bigint_mul_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint); +template void create_bigint_mul_constraint( + const BigIntOperation& input, DSLBigInts& dsl_bigint); +template void create_bigint_div_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint); +template void create_bigint_div_constraint( + const BigIntOperation& input, DSLBigInts& dsl_bigint); + +template +void create_bigint_addition_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +{ + switch (dsl_bigint.get_modulus_id(input.lhs)) { + case ModulusId::BN254_FR: { + auto lhs = dsl_bigint.bn254_fr(input.lhs); + auto rhs = dsl_bigint.bn254_fr(input.rhs); + dsl_bigint.set_bn254_fr(lhs + rhs, input.result); + break; + } + case ModulusId::BN254_FQ: { + auto lhs = dsl_bigint.bn254_fq(input.lhs); + auto rhs = dsl_bigint.bn254_fq(input.rhs); + dsl_bigint.set_bn254_fq(lhs + rhs, input.result); + break; + } + case ModulusId::SECP256K1_FQ: { + auto lhs = dsl_bigint.secp256k1_fq(input.lhs); + auto rhs = dsl_bigint.secp256k1_fq(input.rhs); + dsl_bigint.set_secp256k1_fq(lhs + rhs, input.result); + break; + } + case ModulusId::SECP256K1_FR: { + auto lhs = dsl_bigint.secp256k1_fr(input.lhs); + auto rhs = dsl_bigint.secp256k1_fr(input.rhs); + dsl_bigint.set_secp256k1_fr(lhs + rhs, input.result); + break; + } + case ModulusId::SECP256R1_FQ: { + auto lhs = dsl_bigint.secp256r1_fq(input.lhs); + auto rhs = dsl_bigint.secp256r1_fq(input.rhs); + dsl_bigint.set_secp256r1_fq(lhs + rhs, input.result); + break; + } + case ModulusId::SECP256R1_FR: { + auto lhs = dsl_bigint.secp256r1_fr(input.lhs); + auto rhs = dsl_bigint.secp256r1_fr(input.rhs); + dsl_bigint.set_secp256r1_fr(lhs + rhs, input.result); + break; + } + default: { + ASSERT(false); + } + } +} + +template +void create_bigint_sub_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +{ + switch (dsl_bigint.get_modulus_id(input.lhs)) { + case ModulusId::BN254_FR: { + auto lhs = dsl_bigint.bn254_fr(input.lhs); + auto rhs = dsl_bigint.bn254_fr(input.rhs); + dsl_bigint.set_bn254_fr(lhs - rhs, input.result); + break; + } + case ModulusId::BN254_FQ: { + auto lhs = dsl_bigint.bn254_fq(input.lhs); + auto rhs = dsl_bigint.bn254_fq(input.rhs); + dsl_bigint.set_bn254_fq(lhs - rhs, input.result); + break; + } + case ModulusId::SECP256K1_FQ: { + auto lhs = dsl_bigint.secp256k1_fq(input.lhs); + auto rhs = dsl_bigint.secp256k1_fq(input.rhs); + dsl_bigint.set_secp256k1_fq(lhs - rhs, input.result); + break; + } + case ModulusId::SECP256K1_FR: { + auto lhs = dsl_bigint.secp256k1_fr(input.lhs); + auto rhs = dsl_bigint.secp256k1_fr(input.rhs); + dsl_bigint.set_secp256k1_fr(lhs - rhs, input.result); + break; + } + case ModulusId::SECP256R1_FQ: { + auto lhs = dsl_bigint.secp256r1_fq(input.lhs); + auto rhs = dsl_bigint.secp256r1_fq(input.rhs); + dsl_bigint.set_secp256r1_fq(lhs - rhs, input.result); + break; + } + case ModulusId::SECP256R1_FR: { + auto lhs = dsl_bigint.secp256r1_fr(input.lhs); + auto rhs = dsl_bigint.secp256r1_fr(input.rhs); + dsl_bigint.set_secp256r1_fr(lhs - rhs, input.result); + break; + } + default: { + ASSERT(false); + } + } +} + +template +void create_bigint_mul_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +{ + switch (dsl_bigint.get_modulus_id(input.lhs)) { + case ModulusId::BN254_FR: { + auto lhs = dsl_bigint.bn254_fr(input.lhs); + auto rhs = dsl_bigint.bn254_fr(input.rhs); + dsl_bigint.set_bn254_fr(lhs * rhs, input.result); + break; + } + case ModulusId::BN254_FQ: { + auto lhs = dsl_bigint.bn254_fq(input.lhs); + auto rhs = dsl_bigint.bn254_fq(input.rhs); + dsl_bigint.set_bn254_fq(lhs * rhs, input.result); + break; + } + case ModulusId::SECP256K1_FQ: { + auto lhs = dsl_bigint.secp256k1_fq(input.lhs); + auto rhs = dsl_bigint.secp256k1_fq(input.rhs); + dsl_bigint.set_secp256k1_fq(lhs * rhs, input.result); + break; + } + case ModulusId::SECP256K1_FR: { + auto lhs = dsl_bigint.secp256k1_fr(input.lhs); + auto rhs = dsl_bigint.secp256k1_fr(input.rhs); + dsl_bigint.set_secp256k1_fr(lhs * rhs, input.result); + break; + } + case ModulusId::SECP256R1_FQ: { + auto lhs = dsl_bigint.secp256r1_fq(input.lhs); + auto rhs = dsl_bigint.secp256r1_fq(input.rhs); + dsl_bigint.set_secp256r1_fq(lhs * rhs, input.result); + break; + } + case ModulusId::SECP256R1_FR: { + auto lhs = dsl_bigint.secp256r1_fr(input.lhs); + auto rhs = dsl_bigint.secp256r1_fr(input.rhs); + dsl_bigint.set_secp256r1_fr(lhs * rhs, input.result); + break; + } + default: { + ASSERT(false); + } + } +} + +template +void create_bigint_div_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +{ + switch (dsl_bigint.get_modulus_id(input.lhs)) { + case ModulusId::BN254_FR: { + auto lhs = dsl_bigint.bn254_fr(input.lhs); + auto rhs = dsl_bigint.bn254_fr(input.rhs); + dsl_bigint.set_bn254_fr(lhs / rhs, input.result); + break; + } + case ModulusId::BN254_FQ: { + auto lhs = dsl_bigint.bn254_fq(input.lhs); + auto rhs = dsl_bigint.bn254_fq(input.rhs); + dsl_bigint.set_bn254_fq(lhs / rhs, input.result); + break; + } + case ModulusId::SECP256K1_FQ: { + auto lhs = dsl_bigint.secp256k1_fq(input.lhs); + auto rhs = dsl_bigint.secp256k1_fq(input.rhs); + dsl_bigint.set_secp256k1_fq(lhs / rhs, input.result); + break; + } + case ModulusId::SECP256K1_FR: { + auto lhs = dsl_bigint.secp256k1_fr(input.lhs); + auto rhs = dsl_bigint.secp256k1_fr(input.rhs); + dsl_bigint.set_secp256k1_fr(lhs / rhs, input.result); + break; + } + case ModulusId::SECP256R1_FQ: { + auto lhs = dsl_bigint.secp256r1_fq(input.lhs); + auto rhs = dsl_bigint.secp256r1_fq(input.rhs); + dsl_bigint.set_secp256r1_fq(lhs / rhs, input.result); + break; + } + case ModulusId::SECP256R1_FR: { + auto lhs = dsl_bigint.secp256r1_fr(input.lhs); + auto rhs = dsl_bigint.secp256r1_fr(input.rhs); + dsl_bigint.set_secp256r1_fr(lhs / rhs, input.result); + break; + } + default: { + ASSERT(false); + } + } +} + +template +void create_bigint_operations_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +{ + switch (input.opcode) { + case BigIntOperationType::Add: { + create_bigint_addition_constraint(input, dsl_bigint); + break; + } + case BigIntOperationType::Sub: { + create_bigint_sub_constraint(input, dsl_bigint); + break; + } + case BigIntOperationType::Mul: { + create_bigint_mul_constraint(input, dsl_bigint); + break; + } + case BigIntOperationType::Div: { + create_bigint_div_constraint(input, dsl_bigint); + break; + } + default: { + ASSERT(false); + } + } } -template void create_bigint_operations_constraint(UltraCircuitBuilder& builder, - const BigIntOperation& input); -template void create_bigint_operations_constraint(GoblinUltraCircuitBuilder& builder, - const BigIntOperation& input); +template +void create_bigint_from_le_bytes_constraint(Builder& builder, + const BigIntFromLeBytes& input, + DSLBigInts& dsl_bigints) +{ + using big_bn254_fq = bb::stdlib::bigfield; + using big_bn254_fr = bb::stdlib::bigfield; + using big_secp256k1_fq = bb::stdlib::bigfield; + using big_secp256k1_fr = bb::stdlib::bigfield; + using big_secp256r1_fq = bb::stdlib::bigfield; + using big_secp256r1_fr = bb::stdlib::bigfield; + using field_ct = bb::stdlib::field_t; + using byte_array_ct = bb::stdlib::byte_array; + + // Construct the modulus from its bytes + uint64_t modulus_64 = 0; + uint64_t base = 1; + std::vector modulus_limbs; + for (std::size_t i = 0; i < 32; ++i) { + if (i < input.modulus.size()) { + modulus_64 += input.modulus[i] * base; + base = base * 256; + if ((i + 1) % 8 == 0) { + modulus_limbs.push_back(modulus_64); + modulus_64 = 0; + base = 1; + } + } + } + auto modulus = ModulusParam{ .modulus_0 = modulus_limbs[0], + .modulus_1 = modulus_limbs[1], + .modulus_2 = modulus_limbs[2], + .modulus_3 = modulus_limbs[3] }; + bb::stdlib::byte_array rev_bytes = bb::stdlib::byte_array(&builder, 32); + for (size_t i = 0; i < 32; ++i) { + if (i < input.inputs.size()) { + field_ct element = field_ct::from_witness_index(&builder, input.inputs[i]); + byte_array_ct element_bytes(element, 1); + rev_bytes.write_at(element_bytes, i); + } else { + rev_bytes[i] = 0; + } + } + bb::stdlib::byte_array bytes = rev_bytes.reverse(); + + auto modulus_id = modulus_param_to_id(modulus); + + switch (modulus_id) { + case BN254_FQ: { + auto big = big_bn254_fq(bytes); + dsl_bigints.set_bn254_fq(big, input.result); + break; + } + case BN254_FR: { + auto big = big_bn254_fr(bytes); + dsl_bigints.set_bn254_fr(big, input.result); + break; + } + case SECP256K1_FQ: { + auto big = big_secp256k1_fq(bytes); + dsl_bigints.set_secp256k1_fq(big, input.result); + break; + } + case SECP256K1_FR: { + auto big = big_secp256k1_fr(bytes); + dsl_bigints.set_secp256k1_fr(big, input.result); + break; + } + case SECP256R1_FQ: { + auto big = big_secp256r1_fq(bytes); + dsl_bigints.set_secp256r1_fq(big, input.result); + break; + } + case SECP256R1_FR: { + auto big = big_secp256r1_fr(bytes); + dsl_bigints.set_secp256r1_fr(big, input.result); + break; + } + case UNKNOWN: + default: + ASSERT(false); + break; + } +} template -void create_bigint_from_le_bytes_constraint(Builder& builder, const BigIntFromLeBytes& input) +void create_bigint_to_le_bytes_constraint(Builder& builder, + const BigIntToLeBytes& input, + DSLBigInts& dsl_bigints) { - // TODO - (void)builder; - info(input); + using big_bn254_fq = bb::stdlib::bigfield; + using big_bn254_fr = bb::stdlib::bigfield; + using big_secp256k1_fq = bb::stdlib::bigfield; + using big_secp256k1_fr = bb::stdlib::bigfield; + using big_secp256r1_fq = bb::stdlib::bigfield; + using big_secp256r1_fr = bb::stdlib::bigfield; + + auto modulus_id = dsl_bigints.get_modulus_id(input.input); + bb::stdlib::byte_array byte_array; + switch (modulus_id) { + case BN254_FQ: { + big_bn254_fq big = dsl_bigints.bn254_fq(input.input); + big.self_reduce(); + byte_array = big.to_byte_array(); + + break; + } + case BN254_FR: { + big_bn254_fr big = dsl_bigints.bn254_fr(input.input); + big.self_reduce(); + byte_array = big.to_byte_array(); + break; + } + case SECP256K1_FQ: { + big_secp256k1_fq big = dsl_bigints.secp256k1_fq(input.input); + big.self_reduce(); + byte_array = big.to_byte_array(); + break; + } + case SECP256K1_FR: { + big_secp256k1_fr big = dsl_bigints.secp256k1_fr(input.input); + big.self_reduce(); + byte_array = big.to_byte_array(); + break; + } + case SECP256R1_FQ: { + big_secp256r1_fq big = dsl_bigints.secp256r1_fq(input.input); + big.self_reduce(); + byte_array = big.to_byte_array(); + break; + } + case SECP256R1_FR: { + big_secp256r1_fr big = dsl_bigints.secp256r1_fr(input.input); + big.self_reduce(); + byte_array = big.to_byte_array(); + break; + } + case UNKNOWN: + default: + ASSERT(false); + break; + } + byte_array = byte_array.reverse(); + ASSERT(input.result.size() <= byte_array.size()); + for (size_t i = 0; i < byte_array.size(); ++i) { + if (i < input.result.size()) { + + // This should instead use assert_equal: builder.assert_equal(byte_array[i].normalize().witness_index, + // input.result[i]); but unit tests require this because they do not constraint the witness, and then if we + // use assert_equal in that case, we can generate a proof for non matching values (cf test_assert_equal in + // field.test.cpp). We should check that Noir always constraint the results of to_bytes + poly_triple assert_equal{ + .a = byte_array[i].normalize().witness_index, + .b = input.result[i], + .c = 0, + .q_m = 0, + .q_l = 1, + .q_r = -1, + .q_o = 0, + .q_c = 0, + }; + builder.create_poly_gate(assert_equal); + } else { + byte_array[i].normalize().is_zero(); + } + } } template void create_bigint_from_le_bytes_constraint(UltraCircuitBuilder& builder, - const BigIntFromLeBytes& input); -template void create_bigint_from_le_bytes_constraint(GoblinUltraCircuitBuilder& builder, - const BigIntFromLeBytes& input); + const BigIntFromLeBytes& input, + DSLBigInts& dsl_bigints); +template void create_bigint_from_le_bytes_constraint( + GoblinUltraCircuitBuilder& builder, + const BigIntFromLeBytes& input, + DSLBigInts& dsl_bigints); +template void create_bigint_to_le_bytes_constraint(UltraCircuitBuilder& builder, + const BigIntToLeBytes& input, + DSLBigInts& dsl_bigints); + +template void create_bigint_to_le_bytes_constraint( + GoblinUltraCircuitBuilder& builder, + const BigIntToLeBytes& input, + DSLBigInts& dsl_bigints); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp index 8b21ee5e784..1feb0fffce1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp @@ -16,7 +16,7 @@ struct BigIntFromLeBytes { friend bool operator==(BigIntFromLeBytes const& lhs, BigIntFromLeBytes const& rhs) = default; }; -enum BigIntOperationType { Add, Neg, Mul, Div }; +enum BigIntOperationType { Add, Sub, Mul, Div }; struct BigIntOperation { uint32_t lhs; @@ -29,7 +29,177 @@ struct BigIntOperation { friend bool operator==(BigIntOperation const& lhs, BigIntOperation const& rhs) = default; }; -template void create_bigint_operations_constraint(Builder& builder, const BigIntOperation& input); +struct BigIntToLeBytes { + uint32_t input; + std::vector result; + + // For serialization, update with any new fields + MSGPACK_FIELDS(input, result); + friend bool operator==(BigIntToLeBytes const& lhs, BigIntToLeBytes const& rhs) = default; +}; + +/// Enumerates the supported modulus types for big integer operations. +/// Specifies whether a bigint refers to a BN254/SECP256K1/SECP256R1 Fq or Fr modulus. +enum ModulusId { + BN254_FQ = 0, + BN254_FR, + SECP256K1_FQ, + SECP256K1_FR, + SECP256R1_FQ, + SECP256R1_FR, + UNKNOWN, +}; + +/// 256-bit modulus value for a field element +/// The modulus is represented by 4 64-bits limbs +/// Used to define the modulus for big integer operations. +class ModulusParam { + public: + uint64_t modulus_0; + uint64_t modulus_1; + uint64_t modulus_2; + uint64_t modulus_3; +}; + +template class DSLBigInts { + using big_bn254_fq = bb::stdlib::bigfield; + using big_bn254_fr = bb::stdlib::bigfield; + using big_secp256k1_fq = bb::stdlib::bigfield; + using big_secp256k1_fr = bb::stdlib::bigfield; + using big_secp256r1_fq = bb::stdlib::bigfield; + using big_secp256r1_fr = bb::stdlib::bigfield; + + private: + std::map m_bn254_fq; + std::map m_bn254_fr; + std::map m_secp256k1_fq; + std::map m_secp256k1_fr; + std::map m_secp256r1_fq; + std::map m_secp256r1_fr; + + public: + DSLBigInts() = default; + + ModulusId get_modulus_id(uint32_t bigint_id) + { + if (this->m_bn254_fq.contains(bigint_id)) { + return ModulusId::BN254_FQ; + } + if (this->m_bn254_fr.contains(bigint_id)) { + return ModulusId::BN254_FR; + } + if (this->m_secp256k1_fq.contains(bigint_id)) { + return ModulusId::SECP256K1_FQ; + } + if (this->m_secp256k1_fr.contains(bigint_id)) { + return ModulusId::SECP256K1_FR; + } + if (this->m_secp256r1_fq.contains(bigint_id)) { + return ModulusId::SECP256R1_FQ; + } + if (this->m_secp256r1_fr.contains(bigint_id)) { + return ModulusId::SECP256R1_FR; + } + + return ModulusId::UNKNOWN; + } + + big_bn254_fr bn254_fr(uint32_t bigint_id) + { + if (this->m_bn254_fr.contains(bigint_id)) { + return this->m_bn254_fr[bigint_id]; + } + ASSERT(false); + return { 0 }; + } + + void set_bn254_fr(const big_bn254_fr& bigint, uint32_t bigint_id) { this->m_bn254_fr[bigint_id] = bigint; } + + big_bn254_fq bn254_fq(uint32_t bigint_id) + { + if (this->m_bn254_fq.contains(bigint_id)) { + return this->m_bn254_fq[bigint_id]; + } + ASSERT(false); + return { 0 }; + } + + void set_bn254_fq(const big_bn254_fq& bigint, uint32_t bigint_id) { this->m_bn254_fq[bigint_id] = bigint; } + + big_secp256r1_fq secp256r1_fq(uint32_t bigint_id) + { + if (this->m_secp256r1_fq.contains(bigint_id)) { + return this->m_secp256r1_fq[bigint_id]; + } + ASSERT(false); + return { 0 }; + } + + void set_secp256r1_fq(const big_secp256r1_fq& bigint, uint32_t bigint_id) + { + this->m_secp256r1_fq[bigint_id] = bigint; + } + + big_secp256r1_fr secp256r1_fr(uint32_t bigint_id) + { + if (this->m_secp256r1_fr.contains(bigint_id)) { + return this->m_secp256r1_fr[bigint_id]; + } + ASSERT(false); + return { 0 }; + } + + void set_secp256r1_fr(const big_secp256r1_fr& bigint, uint32_t bigint_id) + { + this->m_secp256r1_fr[bigint_id] = bigint; + } + + big_secp256k1_fq secp256k1_fq(uint32_t bigint_id) + { + if (this->m_secp256k1_fq.contains(bigint_id)) { + return this->m_secp256k1_fq[bigint_id]; + } + ASSERT(false); + return { 0 }; + } + + void set_secp256k1_fq(const big_secp256k1_fq& bigint, uint32_t bigint_id) + { + this->m_secp256k1_fq[bigint_id] = bigint; + } + + big_secp256k1_fr secp256k1_fr(uint32_t bigint_id) + { + if (this->m_secp256k1_fr.contains(bigint_id)) { + return this->m_secp256k1_fr[bigint_id]; + } + return { 0 }; + } + + void set_secp256k1_fr(const big_secp256k1_fr& bigint, uint32_t bigint_id) + { + this->m_secp256k1_fr[bigint_id] = bigint; + } +}; + template -void create_bigint_from_le_bytes_constraint(Builder& builder, const BigIntFromLeBytes& input); +void create_bigint_from_le_bytes_constraint(Builder& builder, + const BigIntFromLeBytes& input, + DSLBigInts& dsl_bigints); +template +void create_bigint_to_le_bytes_constraint(Builder& builder, + const BigIntToLeBytes& input, + DSLBigInts& dsl_bigints); + +template +void create_bigint_operations_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); +template +void create_bigint_addition_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); +template +void create_bigint_sub_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); +template +void create_bigint_mul_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); +template +void create_bigint_div_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); + } // namespace acir_format \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 77717980a4e..161c6076692 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -1,8 +1,10 @@ #include "bigint_constraint.hpp" #include "acir_format.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include #include #include @@ -12,42 +14,225 @@ class BigIntTests : public ::testing::Test { protected: static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } }; +using fr = field; -TEST_F(BigIntTests, TestBigIntConstraintDummy) +std::tuple +generate_big_int_op_constraint_with_modulus( + BigIntOperationType op, fr lhs, fr rhs, WitnessVector& witness_values, const std::vector& modulus) { - // Dummy Test: to be updated when big ints opcodes are implemented - BigIntOperation add_constraint{ - .lhs = 1, - .rhs = 2, - .result = 3, - .opcode = BigIntOperationType::Add, + // CAUTION We assume here the operands and the result fit into one byte! + // So trying to divide 7/2 won't work, but 8/2 will do. + auto lhs_id = static_cast(witness_values.size()); + witness_values.push_back(lhs); + auto rhs_id = static_cast(witness_values.size()); + witness_values.push_back(rhs); + BigIntFromLeBytes from_le_bytes_constraint_bigint_lhs{ + .inputs = { lhs_id }, + .modulus = modulus, + .result = lhs_id, }; - BigIntOperation neg_constraint{ - .lhs = 1, - .rhs = 2, - .result = 3, - .opcode = BigIntOperationType::Neg, + BigIntFromLeBytes from_le_bytes_constraint_bigint_rhs{ + .inputs = { rhs_id }, + .modulus = modulus, + .result = rhs_id, }; - BigIntOperation mul_constraint{ - .lhs = 1, - .rhs = 2, - .result = 3, - .opcode = BigIntOperationType::Mul, + + auto result = static_cast(witness_values.size()); + BigIntOperation constraint{ + .lhs = lhs_id, + .rhs = rhs_id, + .result = result, + .opcode = op, + }; + // Expecting the result to be just one byte long + BigIntToLeBytes to_bytes{ + .input = result, + .result = { static_cast(witness_values.size()) }, + }; + // overflow is NOT supported, you have to make sure there is no overflow/underflow. + fr value = 0; + switch (op) { + case Add: + value = witness_values[lhs_id] + witness_values[rhs_id]; + break; + case Sub: + value = witness_values[lhs_id] - witness_values[rhs_id]; + break; + case Mul: + value = witness_values[lhs_id] * witness_values[rhs_id]; + break; + case Div: + value = witness_values[lhs_id] / witness_values[rhs_id]; + break; + default: + ASSERT(false); + break; + } + + witness_values.push_back(value); + return { from_le_bytes_constraint_bigint_lhs, from_le_bytes_constraint_bigint_rhs, constraint, to_bytes }; +} + +std::tuple generate_big_int_op_constraint( + BigIntOperationType op, fr lhs, fr rhs, WitnessVector& witness_values) +{ + // modulus is bn254/fq + return generate_big_int_op_constraint_with_modulus( + op, + lhs, + rhs, + witness_values, + { + 0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, + 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30, + }); +} + +std::tuple +generate_big_int_op_constraint_secpk1_fr(BigIntOperationType op, fr lhs, fr rhs, WitnessVector& witness_values) +{ + return generate_big_int_op_constraint_with_modulus( + op, lhs, rhs, witness_values, { 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, + 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); +} + +std::tuple +generate_big_int_op_constraint_secpk1_fq(BigIntOperationType op, fr lhs, fr rhs, WitnessVector& witness_values) +{ + return generate_big_int_op_constraint_with_modulus( + op, lhs, rhs, witness_values, { 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); +} +void apply_constraints(AcirFormat& constraint_system, + std::tuple constraints) +{ + constraint_system.bigint_from_le_bytes_constraints.push_back(get<0>(constraints)); + constraint_system.bigint_from_le_bytes_constraints.push_back(get<1>(constraints)); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<3>(constraints)); + constraint_system.bigint_operations.push_back(get<2>(constraints)); +} + +std::tuple generate_big_int_op_constraint_with_id(BigIntOperationType op, + uint32_t lhs_id, + uint32_t rhs_id, + WitnessVector& witness_values) +{ + // lhs_id, rhs_id are big int it, so we can generate the operation directly + auto result = static_cast(witness_values.size()); + BigIntOperation constraint{ + .lhs = lhs_id, + .rhs = rhs_id, + .result = result, + .opcode = op, + }; + // Expecting the result to be just one byte long + BigIntToLeBytes to_bytes{ + .input = result, + .result = { static_cast(witness_values.size()) }, }; - BigIntOperation div_constraint{ + // overflow is NOT supported, you have to make sure there is no overflow/underflow. + fr value = 0; + switch (op) { + case Add: + value = witness_values[lhs_id] + witness_values[rhs_id]; + break; + case Sub: + value = witness_values[lhs_id] - witness_values[rhs_id]; + break; + case Mul: + value = witness_values[lhs_id] * witness_values[rhs_id]; + break; + case Div: + value = witness_values[lhs_id] / witness_values[rhs_id]; + break; + default: + ASSERT(false); + break; + } + + witness_values.push_back(value); + return { constraint, to_bytes }; +} + +// Based on TestBigIntConstraintSimple, we generate constraints for multiple operations at the same time. +TEST_F(BigIntTests, TestBigIntConstraintMultiple) +{ + WitnessVector witness; + auto contraints = generate_big_int_op_constraint(BigIntOperationType::Add, fr(3), fr(1), witness); + auto contraints2 = generate_big_int_op_constraint(BigIntOperationType::Add, fr(3), fr(1), witness); + auto contraints3 = generate_big_int_op_constraint(BigIntOperationType::Sub, fr(5), fr(2), witness); + auto contraints4 = generate_big_int_op_constraint(BigIntOperationType::Mul, fr(5), fr(3), witness); + auto contraints5 = generate_big_int_op_constraint(BigIntOperationType::Div, fr(8), fr(2), witness); + AcirFormat constraint_system{ + .varnum = static_cast(witness.size() + 1), + .recursive = false, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .fixed_base_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .constraints = {}, + .block_constraints = {}, + }; + apply_constraints(constraint_system, contraints); + apply_constraints(constraint_system, contraints2); + apply_constraints(constraint_system, contraints3); + apply_constraints(constraint_system, contraints4); + apply_constraints(constraint_system, contraints5); + constraint_system.varnum = static_cast(witness.size() + 1); + + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + + auto composer = Composer(); + auto prover = composer.create_ultra_with_keccak_prover(builder); + auto proof = prover.construct_proof(); + EXPECT_TRUE(builder.check_circuit()); + auto verifier = composer.create_ultra_with_keccak_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST_F(BigIntTests, TestBigIntConstraintSimple) +{ + // 3 + 3 = 6 + // 3 = bigint(1) = from_bytes(w(1)) + // 6 = bigint(2) = to_bytes(w(2)) + BigIntOperation add_constraint{ .lhs = 1, - .rhs = 2, - .result = 3, - .opcode = BigIntOperationType::Div, + .rhs = 1, + .result = 2, + .opcode = BigIntOperationType::Add, }; - BigIntFromLeBytes from_le_bytes_constraint{ - .inputs = { 0 }, - .modulus = { 23 }, + + BigIntFromLeBytes from_le_bytes_constraint_bigint1{ + .inputs = { 1 }, + .modulus = { 0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, + 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30, }, .result = 1, }; + BigIntToLeBytes result2_to_le_bytes{ + .input = 2, .result = { 2 }, // 3+3=6 + }; + AcirFormat constraint_system{ - .varnum = 4, + .varnum = 5, .recursive = false, .public_inputs = {}, .logic_constraints = {}, @@ -66,22 +251,135 @@ TEST_F(BigIntTests, TestBigIntConstraintDummy) .fixed_base_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, - .bigint_from_le_bytes_constraints = { from_le_bytes_constraint }, - .bigint_operations = { add_constraint, neg_constraint, mul_constraint, div_constraint }, + .bigint_from_le_bytes_constraints = { from_le_bytes_constraint_bigint1 }, + .bigint_to_le_bytes_constraints = { result2_to_le_bytes }, + .bigint_operations = { add_constraint }, .constraints = {}, .block_constraints = {}, }; - WitnessVector witness{ 0, 0, 1 }; + WitnessVector witness{ + 0, 3, 6, 3, 0, + }; + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto composer = Composer(); + auto prover = composer.create_ultra_with_keccak_prover(builder); + auto proof = prover.construct_proof(); + EXPECT_TRUE(builder.check_circuit()); + auto verifier = composer.create_ultra_with_keccak_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +// Based on TestBigIntConstraintMultiple, we generate constraints re-using the bigfields created by the first two +// operations +TEST_F(BigIntTests, TestBigIntConstraintReuse) +{ + WitnessVector witness; + auto contraints = generate_big_int_op_constraint_secpk1_fr(BigIntOperationType::Add, fr(3), fr(1), witness); + auto contraints2 = generate_big_int_op_constraint_secpk1_fr(BigIntOperationType::Sub, fr(5), fr(2), witness); + auto contraints3 = generate_big_int_op_constraint_with_id(BigIntOperationType::Mul, 0, 5, witness); + auto contraints4 = generate_big_int_op_constraint_with_id(BigIntOperationType::Div, 0, 1, witness); + auto contraints5 = generate_big_int_op_constraint_with_id(BigIntOperationType::Sub, 7, 1, witness); + + AcirFormat constraint_system{ + .varnum = static_cast(witness.size() + 1), + .recursive = false, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .fixed_base_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .constraints = {}, + .block_constraints = {}, + }; + apply_constraints(constraint_system, contraints); + apply_constraints(constraint_system, contraints2); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<1>(contraints3)); + constraint_system.bigint_operations.push_back(get<0>(contraints3)); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<1>(contraints4)); + constraint_system.bigint_operations.push_back(get<0>(contraints4)); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<1>(contraints5)); + constraint_system.bigint_operations.push_back(get<0>(contraints5)); + constraint_system.varnum = static_cast(witness.size() + 1); + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); - + EXPECT_TRUE(builder.check_circuit()); auto verifier = composer.create_ultra_with_keccak_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} +TEST_F(BigIntTests, TestBigIntConstraintReuse2) +{ + WitnessVector witness; + auto contraints = generate_big_int_op_constraint_secpk1_fq(BigIntOperationType::Add, fr(3), fr(1), witness); + auto contraints2 = generate_big_int_op_constraint_secpk1_fq(BigIntOperationType::Sub, fr(5), fr(2), witness); + auto contraints3 = generate_big_int_op_constraint_with_id(BigIntOperationType::Add, 0, 5, witness); + auto contraints4 = generate_big_int_op_constraint_with_id(BigIntOperationType::Sub, 0, 1, witness); + auto contraints5 = generate_big_int_op_constraint_with_id(BigIntOperationType::Sub, 7, 1, witness); + + AcirFormat constraint_system{ + .varnum = static_cast(witness.size() + 1), + .recursive = false, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .fixed_base_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .constraints = {}, + .block_constraints = {}, + }; + apply_constraints(constraint_system, contraints); + apply_constraints(constraint_system, contraints2); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<1>(contraints3)); + constraint_system.bigint_operations.push_back(get<0>(contraints3)); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<1>(contraints4)); + constraint_system.bigint_operations.push_back(get<0>(contraints4)); + constraint_system.bigint_to_le_bytes_constraints.push_back(get<1>(contraints5)); + constraint_system.bigint_operations.push_back(get<0>(contraints5)); + constraint_system.varnum = static_cast(witness.size() + 1); + + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + + auto composer = Composer(); + auto prover = composer.create_ultra_with_keccak_prover(builder); + auto proof = prover.construct_proof(); + EXPECT_TRUE(builder.check_circuit()); + auto verifier = composer.create_ultra_with_keccak_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index a88e89de566..90daa030f6e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -129,6 +129,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = { block }, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index d64110d938d..67af3597c9a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -68,6 +68,7 @@ TEST_F(EcOperations, TestECOperations) .ec_add_constraints = { ec_add_constraint }, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index ba6c67b2162..e0ea17fb13b 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -108,6 +108,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, @@ -154,6 +155,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, @@ -195,6 +197,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index ee9f4e2faff..86ed2428d67 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -143,6 +143,7 @@ TEST(ECDSASecp256r1, test_hardcoded) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, @@ -190,6 +191,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, @@ -235,6 +237,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, @@ -275,6 +278,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index cc8fde631b4..0a22466ce88 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -101,6 +101,7 @@ Builder create_inner_circuit() .ec_add_constraints = {}, .recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = { expr_a, expr_b, expr_c, expr_d }, .block_constraints = {} }; @@ -255,6 +256,7 @@ Builder create_outer_circuit(std::vector& inner_circuits) .ec_add_constraints = {}, .recursion_constraints = recursion_constraints, .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, .constraints = {}, .block_constraints = {} };