6#include <gtest/gtest.h>
20using simulation::Instruction;
21using testing::BytecodeBuilder;
22using testing::InstructionBuilder;
23using testing::PublicTxSimulationTester;
25using testing::TestEnqueuedCall;
29struct CustomBytecodeCase {
38constexpr uint8_t INVALID_TAG =
static_cast<uint8_t
>(
MemoryTag::MAX) + 1;
64Instruction ret(uint16_t copy_size_offset, uint16_t return_offset)
66 return InstructionBuilder(
WireOpCode::RETURN).operand(copy_size_offset).operand(return_offset).build();
73CustomBytecodeCase avm_minimal()
89CustomBytecodeCase addressing_with_base_tag_issue(
bool is_indirect)
92 cdc.operand<uint16_t>(1).relative();
96 cdc.operand<uint16_t>(0);
97 cdc.operand<uint16_t>(0);
98 auto bytecode = BytecodeBuilder().add(cdc).add(ret(0, 0)).build();
99 return { is_indirect ?
"AddressingWithBaseTagIssueIndirect" :
"AddressingWithBaseTagIssueDirect",
105CustomBytecodeCase addressing_with_indirect_tag_issue()
108 cdc.operand<uint16_t>(1).indirect();
109 cdc.operand<uint16_t>(0);
110 cdc.operand<uint16_t>(1);
112 BytecodeBuilder().add(set64(0,
MemoryTag::U64, 100)).add(cdc).add(ret(0, 0)).build();
117CustomBytecodeCase addressing_with_indirect_then_relative_tag_issue()
120 add.operand<uint16_t>(1).indirect();
121 add.operand<uint16_t>(2).relative();
122 add.operand<uint16_t>(3);
124 BytecodeBuilder().add(set32(1,
MemoryTag::U32, 10)).add(add).add(ret(0, 0)).build();
125 return {
"AddressingWithIndirectThenRelativeTagIssue",
std::move(
bytecode),
true };
129CustomBytecodeCase addressing_with_relative_overflow_and_indirect_tag_issue()
132 add.operand<uint8_t>(1).indirect().relative();
133 add.operand<uint8_t>(2).indirect();
134 add.operand<uint8_t>(3);
136 BytecodeBuilder().add(set32(0,
MemoryTag::U32, 0xffffffff)).add(add).add(ret(0, 0)).build();
137 return {
"AddressingWithRelativeOverflowAndIndirectTagIssue",
std::move(
bytecode),
true };
140CustomBytecodeCase pc_out_of_range()
142 auto bytecode = BytecodeBuilder().add(jump(123)).add(ret(0, 0)).build();
146CustomBytecodeCase invalid_opcode()
148 const auto set_bytes = BytecodeBuilder().add(set8(0,
MemoryTag::U32, 0)).build();
149 const size_t return_opcode_offset = set_bytes.size();
152 bytecode[return_opcode_offset] = MAX_OPCODE_VALUE + 1;
156CustomBytecodeCase invalid_byte()
158 const uint8_t invalid_opcode = MAX_OPCODE_VALUE + 7;
159 return {
"InvalidByte", { invalid_opcode },
true };
162CustomBytecodeCase instruction_truncated()
169CustomBytecodeCase invalid_tag_value()
177CustomBytecodeCase invalid_tag_value_and_instruction_truncated()
186CustomBytecodeCase set_truncation()
192 const uint64_t large_u64 = (uint64_t(1) << 40) + 0xdeadbeef;
211CustomBytecodeCase cast_truncation()
215 const uint64_t large_u64 = (uint64_t(1) << 40) + 0xdeadbeef;
242CustomBytecodeCase set_field_overflow()
253 const size_t set8_size = BytecodeBuilder().add(set8(0,
MemoryTag::U32, 0)).size();
254 const size_t setff_size = BytecodeBuilder().add(setff(1,
MemoryTag::FF,
FF(25))).size();
255 const size_t ff_offset = set8_size + (setff_size - ff_width);
259 for (
size_t i = 0; i < ff_width; ++i) {
260 bytecode[ff_offset + (ff_width - 1 - i)] =
static_cast<uint8_t
>(
value);
272 cases.push_back(avm_minimal());
273 cases.push_back(addressing_with_base_tag_issue(
true));
274 cases.push_back(addressing_with_base_tag_issue(
false));
275 cases.push_back(addressing_with_indirect_tag_issue());
276 cases.push_back(addressing_with_indirect_then_relative_tag_issue());
277 cases.push_back(addressing_with_relative_overflow_and_indirect_tag_issue());
278 cases.push_back(pc_out_of_range());
279 cases.push_back(invalid_opcode());
280 cases.push_back(invalid_byte());
281 cases.push_back(instruction_truncated());
282 cases.push_back(invalid_tag_value());
283 cases.push_back(invalid_tag_value_and_instruction_truncated());
284 cases.push_back(set_truncation());
285 cases.push_back(cast_truncation());
286 cases.push_back(set_field_overflow());
290PublicSimulatorConfig proving_config()
292 PublicSimulatorConfig config = PublicTxSimulationTester::default_config();
293 config.collect_hints =
true;
294 config.collect_public_inputs =
true;
298class CustomBytecodeSimulation :
public ::testing::TestWithParam<CustomBytecodeCase> {};
302TEST_P(CustomBytecodeSimulation, SimulateAndProve)
304 const CustomBytecodeCase& test_case = GetParam();
305 PublicTxSimulationTester tester;
306 const auto deployed = tester.deploy_contract(test_case.bytecode);
309 const TxSimulationResult fast_result =
310 tester.simulate_tx({ TestEnqueuedCall{ .contract_address = deployed.address } });
311 EXPECT_EQ(fast_result.revert_code !=
RevertCode::OK, test_case.expect_revert);
314 const TxSimulationResult hint_result =
315 tester.simulate_tx({ TestEnqueuedCall{ .contract_address = deployed.address } }, proving_config());
316 ASSERT_TRUE(hint_result.public_inputs.has_value());
317 ASSERT_TRUE(hint_result.hints.has_value());
320 const AvmProvingInputs proving_inputs{ .public_inputs = *hint_result.public_inputs, .hints = *hint_result.hints };
322 EXPECT_TRUE(api.check_circuit(proving_inputs));
326 CustomBytecodeSimulation,
327 ::testing::ValuesIn(get_custom_bytecode_cases()),
328 [](const ::testing::TestParamInfo<CustomBytecodeCase>&
info) {
return info.param.label; });
INSTANTIATE_TEST_SUITE_P(All, KernelIOTamperingTests, testing::Values(KernelIOField::PAIRING_INPUTS, KernelIOField::ACCUMULATOR_HASH, KernelIOField::KERNEL_RETURN_DATA, KernelIOField::APP_RETURN_DATA, KernelIOField::ECC_OP_HASH), [](const testing::TestParamInfo< KernelIOField > &info) { switch(info.param) { case KernelIOField::PAIRING_INPUTS:return "PairingInputs";case KernelIOField::ACCUMULATOR_HASH:return "AccumulatorHash";case KernelIOField::KERNEL_RETURN_DATA:return "KernelReturnData";case KernelIOField::APP_RETURN_DATA:return "AppReturnData";case KernelIOField::ECC_OP_HASH:return "EccOpHash";} return "Unknown";})
TEST_P(KernelIOTamperingTests, CausesVerificationFailure)
std::vector< uint8_t > bytecode
const std::unordered_map< OperandType, uint32_t > & get_operand_type_sizes()
size_t tag_byte_offset(WireOpCode opcode)
Instruction
Enumeration of VM instructions that can be executed.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
unsigned __int128 uint128_t
static constexpr uint256_t modulus