Skip to content

Commit

Permalink
refactor bytecode trace builder
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyasRidhuan committed Oct 18, 2024
1 parent 9dc3d6f commit b3882fc
Show file tree
Hide file tree
Showing 20 changed files with 764 additions and 2,080 deletions.
2,621 changes: 671 additions & 1,950 deletions barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.cpp

Large diffs are not rendered by default.

32 changes: 3 additions & 29 deletions barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp

Large diffs are not rendered by default.

14 changes: 1 addition & 13 deletions barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,19 +726,7 @@ template <typename FF> struct AvmFullRow {
RefVector<const FF> as_vector() const;

static std::vector<std::string> names();
<<<<<<< HEAD
<<<<<<< HEAD
static constexpr size_t SIZE = 708;
=======
<<<<<<< HEAD
static constexpr size_t SIZE = 699;
=======
static constexpr size_t SIZE = 702;
>>>>>>> 47c2f8135 (feat(avm): add pil + trace placeholders)
>>>>>>> dd7aaa51b (feat(avm): add pil + trace placeholders)
=======
static constexpr size_t SIZE = 703;
>>>>>>> 0df7dc0ca (trace changes)
static constexpr size_t SIZE = 712;
};

template <typename FF> std::ostream& operator<<(std::ostream& os, AvmFullRow<FF> const& row);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ class AvmExecutionTests : public ::testing::Test {
ExecutionHints execution_hints,
uint32_t side_effect_counter,
std::vector<FF> calldata,
std::vector<uint8_t> contract_bytecode) {
const std::vector<std::vector<uint8_t>>& all_contracts_bytecode) {
return AvmTraceBuilder(std::move(public_inputs),
std::move(execution_hints),
side_effect_counter,
std::move(calldata),
contract_bytecode)
all_contracts_bytecode)
.set_full_precomputed_tables(false)
.set_range_check_required(false);
});
Expand Down Expand Up @@ -1778,9 +1778,9 @@ TEST_F(AvmExecutionTests, ExecutorThrowsWithTooMuchGasAllocated)
auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

EXPECT_THROW_WITH_MESSAGE(
Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec),
"Cannot allocate more than MAX_L2_GAS_PER_ENQUEUED_CALL to the AVM for execution of an enqueued call");
EXPECT_THROW_WITH_MESSAGE(Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints()),
"Cannot allocate more than MAX_L2_GAS_PER_ENQUEUED_CALL to the AVM for "
"execution of an enqueued call");
}

// Should throw whenever the wrong number of public inputs are provided
Expand Down Expand Up @@ -2335,7 +2335,7 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcodes)
auto execution_hints =
ExecutionHints().with_contract_instance_hints({ { address, { address, 1, 2, 3, 4, 5, public_keys_hints } } });

auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
EXPECT_EQ(returndata, std::vector<FF>({ 1, 2, 3, 4, 5, returned_point.x })); // The first one represents true

validate_trace(std::move(trace), public_inputs, calldata, returndata);
Expand Down
47 changes: 24 additions & 23 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/bytecode_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,42 @@

namespace bb::avm_trace {
using poseidon2 = crypto::Poseidon2<crypto::Poseidon2Bn254ScalarFieldParams>;
AvmBytecodeTraceBuilder::AvmBytecodeTraceBuilder(const std::vector<uint8_t>& contract_bytecode,
const ExecutionHints& hints)
AvmBytecodeTraceBuilder::AvmBytecodeTraceBuilder(const std::vector<std::vector<uint8_t>>& all_contracts_bytecode)
: all_contracts_bytecode(all_contracts_bytecode)
{}

std::vector<FF> AvmBytecodeTraceBuilder::pack_bytecode(const std::vector<uint8_t>& contract_bytes)
{
// Do we need to pad contract_bytecode to be 31bytes?
std::vector<std::vector<uint8_t>> all_contracts_bytecode{ contract_bytecode };
for (const auto& hint : hints.externalcall_hints) {
all_contracts_bytecode.push_back(hint.bytecode);
}
for (auto& contract : all_contracts_bytecode) {
// To make from_buffer<uint256_t> work properly, we need to make sure the contract is a multiple of 31 bytes
// Otherwise we will end up over-reading the buffer
size_t padding = 31 - (contract.size() % 31);
contract.resize(contract.size() + padding, 0);
std::vector<FF> contract_bytecode_fields;
for (size_t i = 0; i < contract.size(); i += 31) {
uint256_t u256_elem = from_buffer<uint256_t>(contract, i);
// Drop the last byte
contract_bytecode_fields.emplace_back(u256_elem >> 8);
}
this->all_contracts_bytecode.push_back(contract_bytecode_fields);
// To make from_buffer<uint256_t> work properly, we need to make sure the contract is a multiple of 31 bytes
// Otherwise we will end up over-reading the buffer
size_t padding = 31 - (contract_bytes.size() % 31);
// We dont want to mutate the original contract bytes, since we will (probably) need them later in the trace
// unpadded
std::vector<uint8_t> contract_bytes_padded = contract_bytes;
contract_bytes_padded.resize(contract_bytes_padded.size() + padding, 0);
std::vector<FF> contract_bytecode_fields;
for (size_t i = 0; i < contract_bytes_padded.size(); i += 31) {
uint256_t u256_elem = from_buffer<uint256_t>(contract_bytes_padded, i);
// Drop the last byte
contract_bytecode_fields.emplace_back(u256_elem >> 8);
}
return contract_bytecode_fields;
}

void AvmBytecodeTraceBuilder::build_bytecode_columns()
{
// This is the main loop that will generate the bytecode trace
for (auto& contract_bytecode : all_contracts_bytecode) {
FF running_hash = FF::zero();
auto packed_bytecode = pack_bytecode(contract_bytecode);
// This size is already based on the number of fields
for (size_t i = 0; i < contract_bytecode.size(); ++i) {
for (size_t i = 0; i < packed_bytecode.size(); ++i) {
bytecode_trace.push_back(BytecodeTraceEntry{
.packed_bytecode = contract_bytecode[i],
.packed_bytecode = packed_bytecode[i],
.running_hash = running_hash,
.bytecode_length_remaining = static_cast<uint16_t>(contract_bytecode.size() - i),
.bytecode_length_remaining = static_cast<uint16_t>(packed_bytecode.size() - i),
});
running_hash = poseidon2::hash({ contract_bytecode[i], running_hash });
running_hash = poseidon2::hash({ packed_bytecode[i], running_hash });
}
// Now running_hash actually contains the bytecode hash
BytecodeTraceEntry last_entry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ class AvmBytecodeTraceBuilder {
// Derive the contract address
FF contract_address{};
};
AvmBytecodeTraceBuilder() = default;
// These interfaces will change when we start feeding in more inputs and hints
AvmBytecodeTraceBuilder(const std::vector<uint8_t>& contract_bytecode, const ExecutionHints& hints);
AvmBytecodeTraceBuilder(const std::vector<std::vector<uint8_t>>& all_contracts_bytecode);

size_t size() const { return bytecode_trace.size(); }
void reset();
Expand All @@ -32,9 +33,12 @@ class AvmBytecodeTraceBuilder {
void build_bytecode_columns();

private:
// Converts the bytecode into field elements (chunks of 31 bytes)
static std::vector<FF> pack_bytecode(const std::vector<uint8_t>& contract_bytes);

std::vector<BytecodeTraceEntry> bytecode_trace;
// This will contain the bytecode as field elements
std::vector<std::vector<FF>> all_contracts_bytecode;
// The first element is the main top-level contract, the rest are external calls
std::vector<std::vector<uint8_t>> all_contracts_bytecode;
// TODO: Come back to this
// VmPublicInputs public_inputs;
// ExecutionHints hints;
Expand Down
37 changes: 22 additions & 15 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,18 @@ void show_trace_info(const auto& trace)
} // namespace

// Needed for dependency injection in tests.
Execution::TraceBuilderConstructor Execution::trace_builder_constructor = [](VmPublicInputs public_inputs,
ExecutionHints execution_hints,
uint32_t side_effect_counter,
std::vector<FF> calldata,
std::vector<uint8_t> contract_bytecode) {
return AvmTraceBuilder(std::move(public_inputs),
std::move(execution_hints),
side_effect_counter,
std::move(calldata),
contract_bytecode);
};
Execution::TraceBuilderConstructor Execution::trace_builder_constructor =
[](VmPublicInputs public_inputs,
ExecutionHints execution_hints,
uint32_t side_effect_counter,
std::vector<FF> calldata,
std::vector<std::vector<uint8_t>> all_contract_bytecode) {
return AvmTraceBuilder(std::move(public_inputs),
std::move(execution_hints),
side_effect_counter,
std::move(calldata),
all_contract_bytecode);
};

/**
* @brief Temporary routine to generate default public inputs (gas values) until we get
Expand Down Expand Up @@ -253,7 +254,7 @@ bool Execution::verify(AvmFlavor::VerificationKey vk, HonkProof const& proof)
std::copy(returndata_offset, raw_proof_offset, std::back_inserter(returndata));
std::copy(raw_proof_offset, proof.end(), std::back_inserter(raw_proof));

VmPublicInputs public_inputs = convert_public_inputs(public_inputs_vec);
VmPublicInputs public_inputs = avm_trace::convert_public_inputs(public_inputs_vec);
std::vector<std::vector<FF>> public_inputs_columns =
copy_public_inputs_columns(public_inputs, calldata, returndata);
return verifier.verify_proof(raw_proof, public_inputs_columns);
Expand All @@ -279,13 +280,19 @@ std::vector<Row> Execution::gen_trace(std::vector<uint8_t> const& bytecode,
vinfo("------- GENERATING TRACE -------");
// TODO(https://github.com/AztecProtocol/aztec-packages/issues/6718): construction of the public input columns
// should be done in the kernel - this is stubbed and underconstrained
VmPublicInputs public_inputs = convert_public_inputs(public_inputs_vec);
VmPublicInputs public_inputs = avm_trace::convert_public_inputs(public_inputs_vec);
uint32_t start_side_effect_counter =
!public_inputs_vec.empty() ? static_cast<uint32_t>(public_inputs_vec[START_SIDE_EFFECT_COUNTER_PCPI_OFFSET])
: 0;

std::vector<std::vector<uint8_t>> all_contract_bytecode;
all_contract_bytecode.reserve(execution_hints.externalcall_hints.size() + 1);
// Start with the main, top-level contract bytecode
all_contract_bytecode.push_back(bytecode);
for (const auto& externalcall_hint : execution_hints.externalcall_hints) {
all_contract_bytecode.emplace_back(externalcall_hint.bytecode);
}
AvmTraceBuilder trace_builder = Execution::trace_builder_constructor(
public_inputs, execution_hints, start_side_effect_counter, calldata, bytecode);
public_inputs, execution_hints, start_side_effect_counter, calldata, all_contract_bytecode);

// Copied version of pc maintained in trace builder. The value of pc is evolving based
// on opcode logic and therefore is not maintained here. However, the next opcode in the execution
Expand Down
11 changes: 6 additions & 5 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ namespace bb::avm_trace {
class Execution {
public:
static constexpr size_t SRS_SIZE = 1 << 22;
using TraceBuilderConstructor = std::function<AvmTraceBuilder(VmPublicInputs public_inputs,
ExecutionHints execution_hints,
uint32_t side_effect_counter,
std::vector<FF> calldata,
std::vector<uint8_t> contract_bytecode)>;
using TraceBuilderConstructor =
std::function<AvmTraceBuilder(VmPublicInputs public_inputs,
ExecutionHints execution_hints,
uint32_t side_effect_counter,
std::vector<FF> calldata,
const std::vector<std::vector<uint8_t>>& all_contract_bytecode)>;

Execution() = default;

Expand Down
6 changes: 3 additions & 3 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,16 +259,16 @@ void AvmTraceBuilder::finalise_mem_trace_lookup_counts()
* underlying traces and initialize gas values.
*/
AvmTraceBuilder::AvmTraceBuilder(VmPublicInputs public_inputs,
const ExecutionHints& execution_hints_,
ExecutionHints execution_hints_,
uint32_t side_effect_counter,
std::vector<FF> calldata,
const std::vector<uint8_t>& contract_bytecode)
const std::vector<std::vector<uint8_t>>& all_contract_bytecode)
// NOTE: we initialise the environment builder here as it requires public inputs
: calldata(std::move(calldata))
, side_effect_counter(side_effect_counter)
, execution_hints(std::move(execution_hints_))
, kernel_trace_builder(side_effect_counter, public_inputs, execution_hints)
, bytecode_trace_builder(contract_bytecode, execution_hints)
, bytecode_trace_builder(all_contract_bytecode)
{
// TODO: think about cast
gas_trace_builder.set_initial_gas(
Expand Down
4 changes: 2 additions & 2 deletions barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ class AvmTraceBuilder {

public:
AvmTraceBuilder(VmPublicInputs public_inputs = {},
const ExecutionHints& execution_hints = {},
ExecutionHints execution_hints = {},
uint32_t side_effect_counter = 0,
std::vector<FF> calldata = {},
const std::vector<uint8_t>& contract_bytecode = {});
const std::vector<std::vector<uint8_t>>& all_contract_bytecode = {});

uint32_t getPc() const { return pc; }

Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/vm/aztec_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#define PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH 691
#define PUBLIC_CONTEXT_INPUTS_LENGTH 42
#define AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS 86
#define AVM_PROOF_LENGTH_IN_FIELDS 3848
#define AVM_PROOF_LENGTH_IN_FIELDS 3868
#define AVM_PUBLIC_COLUMN_MAX_SIZE 1024
#define AVM_PUBLIC_INPUTS_FLATTENED_SIZE 2739
#define MEM_TAG_FF 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ contract ContractClassRegisterer {
if (i < bytecode_length_in_fields) {
// We skip the first element when hashing since it is the length
computed_public_bytecode_commitment = std::hash::poseidon2::Poseidon2::hash([packed_public_bytecode[i + 1],computed_public_bytecode_commitment],2);
} else {
// Any bytes after the bytecode length must be 0
assert_eq(packed_public_bytecode[i + 1], 0);
}
}
assert_eq(computed_public_bytecode_commitment, public_bytecode_commitment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ global AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS: u32 = 2 + 21 * 4;
// `AVM_PROOF_LENGTH_IN_FIELDS` must be updated when AVM circuit changes.
// To determine latest value, hover `COMPUTED_AVM_PROOF_LENGTH_IN_FIELDS`
// in barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp
global AVM_PROOF_LENGTH_IN_FIELDS: u32 = 3848;
global AVM_PROOF_LENGTH_IN_FIELDS: u32 = 3868;
global AVM_PUBLIC_COLUMN_MAX_SIZE : u32 = 1024;
global AVM_PUBLIC_INPUTS_FLATTENED_SIZE : u32 = 2 * AVM_PUBLIC_COLUMN_MAX_SIZE + PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH;
/**
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export const TUBE_PROOF_LENGTH = 463;
export const HONK_VERIFICATION_KEY_LENGTH_IN_FIELDS = 128;
export const CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS = 145;
export const AVM_VERIFICATION_KEY_LENGTH_IN_FIELDS = 86;
export const AVM_PROOF_LENGTH_IN_FIELDS = 3848;
export const AVM_PROOF_LENGTH_IN_FIELDS = 3868;
export const AVM_PUBLIC_COLUMN_MAX_SIZE = 1024;
export const AVM_PUBLIC_INPUTS_FLATTENED_SIZE = 2739;
export const MEM_TAG_FF = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('ContractClass', () => {
};

expect(computeContractClassId(contractClass).toString()).toMatchInlineSnapshot(
`"0x174bf0daff21f2b8b88f7d2b7ef7ed6a7b083c979a2996a4e78963ad4b84ff8d"`,
`"0x2d5c712c483891d42e5bca539e8516fc52b5b024568ac71e4fe47c0c0157f851"`,
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ describe('ContractClassRegisteredEvent', () => {
);
expect(event.artifactHash.toString()).toEqual('0x072dce903b1a299d6820eeed695480fe9ec46658b1101885816aed6dd86037f0');
expect(event.packedPublicBytecode.length).toEqual(27090);
// TODO: #5860
expect(computePublicBytecodeCommitment(event.packedPublicBytecode).toString()).toEqual(
'0x0000000000000000000000000000000000000000000000000000000000000005',
'0x0378491b34825cd67d1e13e140bbc80f2cd3a9b52171ea577f8f11620d4198ba',
);
});
});
Loading

0 comments on commit b3882fc

Please sign in to comment.