Skip to content

Commit

Permalink
feat!: Add big int opcodes (without implementation) (AztecProtocol#4050)
Browse files Browse the repository at this point in the history
Adds the biginteger opcode skeleton
noir-lang/noir#4040

The PR adds ACIR opcodes for bigint operations. It does not provide any
implantation of the opcodes, neither in BB, in the solver or in Brillig.

---------

Co-authored-by: kevaundray <kevtheappdev@gmail.com>
  • Loading branch information
guipublic and kevaundray authored Jan 24, 2024
1 parent bef65c3 commit bcab9ce
Show file tree
Hide file tree
Showing 23 changed files with 2,338 additions and 277 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo
create_block_constraints(builder, constraint, has_valid_witness_assignments);
}

// Add big_int constraints
for (const auto& constraint : constraint_system.bigint_operations) {
create_bigint_operations_constraint(builder, constraint);
}
for (const auto& constraint : constraint_system.bigint_from_le_bytes_constraints) {
create_bigint_from_le_bytes_constraint(builder, constraint);
}

// TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet
// dealing with proper recursion
if constexpr (IsGoblinBuilder<Builder>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include "barretenberg/common/slab_allocator.hpp"
#include "barretenberg/serialize/msgpack.hpp"
#include "bigint_constraint.hpp"
#include "blake2s_constraint.hpp"
#include "blake3_constraint.hpp"
#include "block_constraint.hpp"
Expand Down Expand Up @@ -41,6 +42,8 @@ struct AcirFormat {
std::vector<EcAdd> ec_add_constraints;
std::vector<EcDouble> ec_double_constraints;
std::vector<RecursionConstraint> recursion_constraints;
std::vector<BigIntFromLeBytes> bigint_from_le_bytes_constraints;
std::vector<BigIntOperation> bigint_operations;

// A standard plonk arithmetic constraint, as defined in the poly_triple struct, consists of selector values
// for q_M,q_L,q_R,q_O,q_C and indices of three variables taking the role of left, right and output wire
Expand Down Expand Up @@ -69,7 +72,9 @@ struct AcirFormat {
fixed_base_scalar_mul_constraints,
recursion_constraints,
constraints,
block_constraints);
block_constraints,
bigint_from_le_bytes_constraints,
bigint_operations);

friend bool operator==(AcirFormat const& lhs, AcirFormat const& rhs) = default;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = { constraint },
.block_constraints = {},
};
Expand Down Expand Up @@ -158,6 +160,8 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = { expr_a, expr_b, expr_c, expr_d },
.block_constraints = {} };

Expand Down Expand Up @@ -221,6 +225,8 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = { poly_triple{
.a = schnorr_constraint.result,
.b = schnorr_constraint.result,
Expand Down Expand Up @@ -312,6 +318,8 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = { poly_triple{
.a = schnorr_constraint.result,
.b = schnorr_constraint.result,
Expand Down Expand Up @@ -422,6 +430,8 @@ TEST_F(AcirFormatTests, TestVarKeccak)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = { dummy },
.block_constraints = {},
};
Expand Down Expand Up @@ -464,6 +474,8 @@ TEST_F(AcirFormatTests, TestKeccakPermutation)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {} };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "acir_format.hpp"
#include "barretenberg/common/container.hpp"
#include "barretenberg/common/throw_or_abort.hpp"
#include "barretenberg/dsl/acir_format/bigint_constraint.hpp"
#include "barretenberg/dsl/acir_format/blake2s_constraint.hpp"
#include "barretenberg/dsl/acir_format/blake3_constraint.hpp"
#include "barretenberg/dsl/acir_format/block_constraint.hpp"
Expand Down Expand Up @@ -240,6 +241,40 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci
.key_hash = arg.key_hash.witness.value,
};
af.recursion_constraints.push_back(c);
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::BigIntFromLeBytes>) {
af.bigint_from_le_bytes_constraints.push_back(BigIntFromLeBytes{
.inputs = map(arg.inputs, [](auto& e) { return e.witness.value; }),
.modulus = map(arg.modulus, [](auto& e) -> uint32_t { return e; }),
.result = arg.output,
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::BigIntAdd>) {
af.bigint_operations.push_back(BigIntOperation{
.lhs = arg.lhs,
.rhs = arg.rhs,
.result = arg.output,
.opcode = BigIntOperationType::Add,
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::BigIntNeg>) {
af.bigint_operations.push_back(BigIntOperation{
.lhs = arg.lhs,
.rhs = arg.rhs,
.result = arg.output,
.opcode = BigIntOperationType::Neg,
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::BigIntMul>) {
af.bigint_operations.push_back(BigIntOperation{
.lhs = arg.lhs,
.rhs = arg.rhs,
.result = arg.output,
.opcode = BigIntOperationType::Mul,
});
} else if constexpr (std::is_same_v<T, Circuit::BlackBoxFuncCall::BigIntDiv>) {
af.bigint_operations.push_back(BigIntOperation{
.lhs = arg.lhs,
.rhs = arg.rhs,
.result = arg.output,
.opcode = BigIntOperationType::Div,
});
}
},
arg.value.value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "bigint_constraint.hpp"
#include "barretenberg/dsl/types.hpp"
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp"

namespace acir_format {

template <typename Builder> void create_bigint_operations_constraint(Builder& builder, const BigIntOperation& input)
{
// TODO
(void)builder;
info(input);
}

template void create_bigint_operations_constraint<UltraCircuitBuilder>(UltraCircuitBuilder& builder,
const BigIntOperation& input);
template void create_bigint_operations_constraint<GoblinUltraCircuitBuilder>(GoblinUltraCircuitBuilder& builder,
const BigIntOperation& input);

template <typename Builder>
void create_bigint_from_le_bytes_constraint(Builder& builder, const BigIntFromLeBytes& input)
{
// TODO
(void)builder;
info(input);
}

template void create_bigint_from_le_bytes_constraint<UltraCircuitBuilder>(UltraCircuitBuilder& builder,
const BigIntFromLeBytes& input);
template void create_bigint_from_le_bytes_constraint<GoblinUltraCircuitBuilder>(GoblinUltraCircuitBuilder& builder,
const BigIntFromLeBytes& input);

} // namespace acir_format
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once
#include "barretenberg/dsl/types.hpp"
#include "barretenberg/serialize/msgpack.hpp"
#include <cstdint>
#include <vector>

namespace acir_format {

struct BigIntFromLeBytes {
std::vector<uint32_t> inputs;
std::vector<uint32_t> modulus;
uint32_t result;

// For serialization, update with any new fields
MSGPACK_FIELDS(inputs, result);
friend bool operator==(BigIntFromLeBytes const& lhs, BigIntFromLeBytes const& rhs) = default;
};

enum BigIntOperationType { Add, Neg, Mul, Div };

struct BigIntOperation {
uint32_t lhs;
uint32_t rhs;
uint32_t result;
BigIntOperationType opcode;

// For serialization, update with any new fields
MSGPACK_FIELDS(lhs, rhs, opcode, result);
friend bool operator==(BigIntOperation const& lhs, BigIntOperation const& rhs) = default;
};

template <typename Builder> void create_bigint_operations_constraint(Builder& builder, const BigIntOperation& input);
template <typename Builder>
void create_bigint_from_le_bytes_constraint(Builder& builder, const BigIntFromLeBytes& input);
} // namespace acir_format
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "bigint_constraint.hpp"
#include "acir_format.hpp"
#include "barretenberg/plonk/proof_system/types/proof.hpp"
#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp"

#include <gtest/gtest.h>
#include <vector>

namespace acir_format::tests {

class BigIntTests : public ::testing::Test {
protected:
static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); }
};

TEST_F(BigIntTests, TestBigIntConstraintDummy)
{
// Dummy Test: to be updated when big ints opcodes are implemented
BigIntOperation add_constraint{
.lhs = 1,
.rhs = 2,
.result = 3,
.opcode = BigIntOperationType::Add,
};
BigIntOperation neg_constraint{
.lhs = 1,
.rhs = 2,
.result = 3,
.opcode = BigIntOperationType::Neg,
};
BigIntOperation mul_constraint{
.lhs = 1,
.rhs = 2,
.result = 3,
.opcode = BigIntOperationType::Mul,
};
BigIntOperation div_constraint{
.lhs = 1,
.rhs = 2,
.result = 3,
.opcode = BigIntOperationType::Div,
};
BigIntFromLeBytes from_le_bytes_constraint{
.inputs = { 0 },
.modulus = { 23 },
.result = 1,
};

AcirFormat constraint_system{
.varnum = 4,
.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 = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = { from_le_bytes_constraint },
.bigint_operations = { add_constraint, neg_constraint, mul_constraint, div_constraint },
.constraints = {},
.block_constraints = {},

};

WitnessVector witness{ 0, 0, 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();

auto verifier = composer.create_ultra_with_keccak_verifier(builder);

EXPECT_EQ(verifier.verify_proof(proof), true);
}

} // namespace acir_format::tests
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = { block },
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down Expand Up @@ -151,6 +153,8 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down Expand Up @@ -190,6 +194,8 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ TEST(ECDSASecp256r1, test_hardcoded)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down Expand Up @@ -187,6 +189,8 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down Expand Up @@ -230,6 +234,8 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down Expand Up @@ -268,6 +274,8 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ Builder create_inner_circuit()
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = { expr_a, expr_b, expr_c, expr_d },
.block_constraints = {} };

Expand Down Expand Up @@ -252,6 +254,8 @@ Builder create_outer_circuit(std::vector<Builder>& inner_circuits)
.ec_add_constraints = {},
.ec_double_constraints = {},
.recursion_constraints = recursion_constraints,
.bigint_from_le_bytes_constraints = {},
.bigint_operations = {},
.constraints = {},
.block_constraints = {} };

Expand Down
Loading

0 comments on commit bcab9ce

Please sign in to comment.