Skip to content

Commit

Permalink
feat(avm): ecc
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyasRidhuan committed Jun 5, 2024
1 parent 00c3ee5 commit e8a754e
Show file tree
Hide file tree
Showing 15 changed files with 861 additions and 557 deletions.
6 changes: 3 additions & 3 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -844,14 +844,14 @@ fn handle_black_box_function(avm_instrs: &mut Vec<AvmInstruction>, operation: &B
result,
} => avm_instrs.push(AvmInstruction {
opcode: AvmOpcode::ECADD,
indirect: Some(ALL_DIRECT),
indirect: Some(0b1000000),
operands: vec![
AvmOperand::U32 { value: input1_x.0 as u32 },
AvmOperand::U32 { value: input1_y.0 as u32 },
AvmOperand::U8 { value: input1_infinite.0 as u8 },
AvmOperand::U32 { value: input1_infinite.0 as u32 },
AvmOperand::U32 { value: input2_x.0 as u32 },
AvmOperand::U32 { value: input2_y.0 as u32 },
AvmOperand::U8 { value: input2_infinite.0 as u8 },
AvmOperand::U32 { value: input2_infinite.0 as u32 },
AvmOperand::U32 { value: result.pointer.0 as u32 },
],
..Default::default()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const std::unordered_map<OpCode, std::vector<OperandType>> OPCODE_WIRE_FORMAT =
// DELEGATECALL, -- not in simulator
{ OpCode::RETURN, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } },
// REVERT,
{ OpCode::REVERT, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } },
// Misc
{ OpCode::DEBUGLOG,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
Expand All @@ -147,6 +148,16 @@ const std::unordered_map<OpCode, std::vector<OperandType>> OPCODE_WIRE_FORMAT =
{ OpCode::SHA256, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
{ OpCode::PEDERSEN,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
// TEMP ECADD without relative memory
{ OpCode::ECADD,
{ OperandType::INDIRECT,
OperandType::UINT32, // lhs.x
OperandType::UINT32, // lhs.y
OperandType::UINT32, // lhs.is_infinite
OperandType::UINT32, // rhs.x
OperandType::UINT32, // rhs.y
OperandType::UINT32, // rhs.is_infinite
OperandType::UINT32 } }, // res_offset
// Gadget - Conversion
{ OpCode::TORADIXLE,
{ OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } },
Expand Down Expand Up @@ -257,6 +268,9 @@ std::vector<Instruction> Deserialization::parse(std::vector<uint8_t> const& byte
case OperandType::TAG: {
uint8_t tag_u8 = bytecode.at(pos);
if (tag_u8 == static_cast<uint8_t>(AvmMemoryTag::U0) || tag_u8 > MAX_MEM_TAG) {
info("tag_u8: ", static_cast<int>(tag_u8));
info("pos: ", pos);
info("opcode: ", static_cast<int>(opcode));
throw_or_abort("Instruction tag is invalid at position " + std::to_string(pos) +
" value: " + std::to_string(tag_u8) + " for opcode: " + to_hex(opcode));
}
Expand Down
15 changes: 15 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,21 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
std::get<uint32_t>(inst.operands.at(3)),
std::get<uint32_t>(inst.operands.at(4)));
break;
case OpCode::ECADD:
trace_builder.op_embedded_ec_add(std::get<uint8_t>(inst.operands.at(0)),
std::get<uint32_t>(inst.operands.at(1)),
std::get<uint32_t>(inst.operands.at(2)),
std::get<uint32_t>(inst.operands.at(3)),
std::get<uint32_t>(inst.operands.at(4)),
std::get<uint32_t>(inst.operands.at(5)),
std::get<uint32_t>(inst.operands.at(6)),
std::get<uint32_t>(inst.operands.at(7)));
break;
case OpCode::REVERT:
trace_builder.op_revert(std::get<uint8_t>(inst.operands.at(0)),
std::get<uint32_t>(inst.operands.at(1)),
std::get<uint32_t>(inst.operands.at(2)));
break;
default:
throw_or_abort("Don't know how to execute opcode " + to_hex(inst.op_code) + " at pc " + std::to_string(pc) +
".");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ static const inline std::unordered_map<OpCode, GasTableEntry> GAS_COST_TABLE = {
{ OpCode::POSEIDON2, temp_default_gas_entry },
{ OpCode::SHA256, temp_default_gas_entry },
{ OpCode::PEDERSEN, temp_default_gas_entry },
{ OpCode::ECADD, temp_default_gas_entry },

// Conversions
{ OpCode::TORADIXLE, temp_default_gas_entry },
Expand Down Expand Up @@ -146,4 +147,4 @@ class AvmGasTraceBuilder {
uint32_t remaining_da_gas = 0;
};

} // namespace bb::avm_trace
} // namespace bb::avm_trace
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ enum class OpCode : uint8_t {
POSEIDON2,
SHA256,
PEDERSEN,
ECADD,
// Conversions
TORADIXLE,
// Future Gadgets -- pending changes in noir
Expand Down
112 changes: 112 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1843,6 +1843,10 @@ void AvmTraceBuilder::calldata_copy(
pc++;
}

std::vector<FF> AvmTraceBuilder::op_revert(uint8_t indirect, uint32_t ret_offset, uint32_t ret_size)
{
return return_op(indirect, ret_offset, ret_size);
}
/**
* @brief RETURN opcode with direct and indirect memory access, i.e.,
* direct: return(M[ret_offset:ret_offset+ret_size])
Expand Down Expand Up @@ -3289,6 +3293,114 @@ void AvmTraceBuilder::op_pedersen_hash(uint8_t indirect,
write_slice_to_memory(
call_ptr, clk, output_offset, AvmMemoryTag::FF, AvmMemoryTag::FF, FF(internal_return_ptr), { output });
}

void AvmTraceBuilder::op_embedded_ec_add(uint8_t indirect,
uint32_t lhs_x_offset,
uint32_t lhs_y_offset,
uint32_t lhs_is_inf_offset,
uint32_t rhs_x_offset,
uint32_t rhs_y_offset,
uint32_t rhs_is_inf_offset,
uint32_t output_offset)
{
// output_offset could be indirect
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;
// Load lhs point
auto lhs_x_read = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::IA, lhs_x_offset, AvmMemoryTag::FF, AvmMemoryTag::U0);
auto lhs_y_read = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::IB, lhs_y_offset, AvmMemoryTag::FF, AvmMemoryTag::U0);
// Load rhs point
auto rhs_x_read = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::IC, rhs_x_offset, AvmMemoryTag::FF, AvmMemoryTag::U0);
auto rhs_y_read = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::ID, rhs_y_offset, AvmMemoryTag::FF, AvmMemoryTag::U0);

// Save this clk time to line up with the gadget op.
auto ecc_clk = clk;
main_trace.push_back(Row{
.avm_main_clk = clk,
.avm_main_ia = lhs_x_read.val,
.avm_main_ib = lhs_y_read.val,
.avm_main_ic = rhs_x_read.val,
.avm_main_id = rhs_y_read.val,
.avm_main_internal_return_ptr = FF(internal_return_ptr),
.avm_main_mem_idx_a = FF(lhs_x_offset),
.avm_main_mem_idx_b = FF(lhs_y_offset),
.avm_main_mem_idx_c = FF(rhs_x_offset),
.avm_main_mem_idx_d = FF(rhs_y_offset),
.avm_main_mem_op_a = FF(1),
.avm_main_mem_op_b = FF(1),
.avm_main_mem_op_c = FF(1),
.avm_main_mem_op_d = FF(1),
.avm_main_pc = FF(pc++),
.avm_main_r_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::FF)),
});
clk++;
// Load the infinite bools separately since they have a different memory tag
auto lhs_is_inf_read = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::IA, lhs_is_inf_offset, AvmMemoryTag::U8, AvmMemoryTag::U0);
auto rhs_is_inf_read = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::IB, rhs_is_inf_offset, AvmMemoryTag::U8, AvmMemoryTag::U0);

main_trace.push_back(Row{
.avm_main_clk = clk,
.avm_main_ia = lhs_is_inf_read.val,
.avm_main_ib = rhs_is_inf_read.val,
.avm_main_internal_return_ptr = FF(internal_return_ptr),
.avm_main_mem_idx_a = FF(lhs_is_inf_offset),
.avm_main_mem_idx_b = FF(rhs_is_inf_offset),
.avm_main_mem_op_a = FF(1),
.avm_main_mem_op_b = FF(1),
.avm_main_pc = FF(pc),
.avm_main_r_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::U8)),
});
clk++;
grumpkin::g1::affine_element lhs = uint8_t(lhs_is_inf_read.val) == 1
? grumpkin::g1::affine_element::infinity()
: grumpkin::g1::affine_element{ lhs_x_read.val, lhs_y_read.val };
grumpkin::g1::affine_element rhs = uint8_t(rhs_is_inf_read.val) == 1
? grumpkin::g1::affine_element::infinity()
: grumpkin::g1::affine_element{ rhs_x_read.val, rhs_y_read.val };
auto result = ecc_trace_builder.embedded_curve_add(lhs, rhs, ecc_clk);
// Write across two lines since we have different mem_tags
uint32_t direct_output_offset = output_offset;
bool indirect_flag_output = is_operand_indirect(indirect, 6);
if (indirect_flag_output) {
auto read_ind_output =
mem_trace_builder.indirect_read_and_load_from_memory(call_ptr, clk, IndirectRegister::IND_A, output_offset);
direct_output_offset = uint32_t(read_ind_output.val);
}
auto read_output = mem_trace_builder.read_and_load_from_memory(
call_ptr, clk, IntermRegister::IA, direct_output_offset, AvmMemoryTag::U32, AvmMemoryTag::U0);
main_trace.push_back(Row{
.avm_main_clk = clk,
.avm_main_ia = read_output.val,
.avm_main_ind_a = indirect_flag_output ? FF(output_offset) : FF(0),
.avm_main_ind_op_a = FF(static_cast<uint32_t>(indirect_flag_output)),
.avm_main_internal_return_ptr = FF(internal_return_ptr),
.avm_main_mem_idx_a = FF(direct_output_offset),
.avm_main_mem_op_a = FF(1),
.avm_main_pc = FF(pc),
.avm_main_r_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::U32)),
});
clk++;
write_slice_to_memory(call_ptr,
clk,
direct_output_offset,
AvmMemoryTag::FF,
AvmMemoryTag::FF,
FF(internal_return_ptr),
{ result.x, result.y });
clk++;
write_slice_to_memory(call_ptr,
clk,
direct_output_offset + 2,
AvmMemoryTag::U8,
AvmMemoryTag::U8,
FF(internal_return_ptr),
{ result.is_point_at_infinity() });
}
// Finalise Lookup Counts
//
// For log derivative lookups, we require a column that contains the number of times each lookup is consumed
Expand Down
12 changes: 12 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "barretenberg/vm/avm_trace/avm_opcode.hpp"
#include "barretenberg/vm/avm_trace/constants.hpp"
#include "barretenberg/vm/avm_trace/gadgets/avm_conversion_trace.hpp"
#include "barretenberg/vm/avm_trace/gadgets/avm_ecc.hpp"
#include "barretenberg/vm/avm_trace/gadgets/avm_keccak.hpp"
#include "barretenberg/vm/avm_trace/gadgets/avm_pedersen.hpp"
#include "barretenberg/vm/avm_trace/gadgets/avm_poseidon2.hpp"
Expand Down Expand Up @@ -153,6 +154,7 @@ class AvmTraceBuilder {
uint32_t dst_offset,
std::vector<FF> const& call_data_mem);

std::vector<FF> op_revert(uint8_t indirect, uint32_t ret_offset, uint32_t ret_size);
// RETURN opcode with direct and indirect memory access, i.e.,
// direct: return(M[ret_offset:ret_offset+ret_size])
// indirect: return(M[M[ret_offset]:M[ret_offset]+ret_size])
Expand Down Expand Up @@ -190,6 +192,15 @@ class AvmTraceBuilder {
uint32_t output_offset,
uint32_t input_offset,
uint32_t input_size_offset);
// Embedded EC Add - the offsets are temporary
void op_embedded_ec_add(uint8_t indirect,
uint32_t lhs_x_offset,
uint32_t lhs_y_offset,
uint32_t lhs_is_inf_offset,
uint32_t rhs_x_offset,
uint32_t rhs_y_offset,
uint32_t rhs_is_inf_offset,
uint32_t output_offset);

private:
// Used for the standard indirect address resolution of three operands opcode.
Expand All @@ -215,6 +226,7 @@ class AvmTraceBuilder {
AvmPoseidon2TraceBuilder poseidon2_trace_builder;
AvmKeccakTraceBuilder keccak_trace_builder;
AvmPedersenTraceBuilder pedersen_trace_builder;
AvmEccTraceBuilder ecc_trace_builder;

/**
* @brief Create a kernel lookup opcode object
Expand Down
35 changes: 35 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/gadgets/avm_ecc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

#include "barretenberg/vm/avm_trace/gadgets/avm_ecc.hpp"
#include "barretenberg/vm/avm_trace/avm_common.hpp"

namespace bb::avm_trace {

AvmEccTraceBuilder::AvmEccTraceBuilder()
{
ecc_trace.reserve(AVM_TRACE_SIZE);
}

std::vector<AvmEccTraceBuilder::EccTraceEntry> AvmEccTraceBuilder::finalize()
{
return std::move(ecc_trace);
}

void AvmEccTraceBuilder::reset()
{
ecc_trace.clear();
}

grumpkin::g1::affine_element AvmEccTraceBuilder::embedded_curve_add(grumpkin::g1::affine_element lhs,
grumpkin::g1::affine_element rhs,
uint32_t clk)
{
grumpkin::g1::affine_element result = lhs + rhs;
std::tuple<FF, FF, bool> p1 = { lhs.x, lhs.y, lhs.is_point_at_infinity() };
std::tuple<FF, FF, bool> p2 = { rhs.x, rhs.y, rhs.is_point_at_infinity() };
std::tuple<FF, FF, bool> result_tuple = { result.x, result.y, result.is_point_at_infinity() };
ecc_trace.push_back({ clk, p1, p2, result_tuple });

return result;
}

} // namespace bb::avm_trace
30 changes: 30 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/gadgets/avm_ecc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

#pragma once

#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
#include "barretenberg/ecc/groups/affine_element.hpp"
#include "barretenberg/vm/avm_trace/avm_common.hpp"

namespace bb::avm_trace {
class AvmEccTraceBuilder {
public:
struct EccTraceEntry {
uint32_t clk = 0;
std::tuple<FF, FF, bool> p1; // x, y, is_infinity
std::tuple<FF, FF, bool> p2;
std::tuple<FF, FF, bool> result;
};

AvmEccTraceBuilder();
void reset();
// Finalize the trace
std::vector<EccTraceEntry> finalize();
grumpkin::g1::affine_element embedded_curve_add(grumpkin::g1::affine_element lhs,
grumpkin::g1::affine_element rhs,
uint32_t clk);

private:
std::vector<EccTraceEntry> ecc_trace;
};

} // namespace bb::avm_trace
Loading

0 comments on commit e8a754e

Please sign in to comment.