Skip to content

Commit

Permalink
feat(avm): pedersen commit in avm
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyasRidhuan committed Jul 26, 2024
1 parent 58f8593 commit d1f8e48
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,14 @@ std::vector<Row> Execution::gen_trace(std::vector<Instruction> const& instructio
std::get<uint32_t>(inst.operands.at(2)),
std::get<uint32_t>(inst.operands.at(3)));

break;
case OpCode::PEDERSENCOMMITMENT:
trace_builder.op_pedersen_commit(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)));

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
92 changes: 92 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 @@ -14,6 +14,7 @@
#include <vector>

#include "barretenberg/common/throw_or_abort.hpp"
#include "barretenberg/crypto/pedersen_commitment/pedersen.hpp"
#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
#include "barretenberg/numeric/uint256/uint256.hpp"
#include "barretenberg/polynomials/univariate.hpp"
Expand Down Expand Up @@ -3430,6 +3431,97 @@ void AvmTraceBuilder::op_variable_msm(uint8_t indirect,
pc++;
}

void AvmTraceBuilder::op_pedersen_commit(uint8_t indirect,
uint32_t input_offset,
uint32_t output_offset,
uint32_t input_size_offset,
uint32_t gen_ctx_offset)
{
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;
auto [resolved_input_offset, resolved_output_offset, resolved_input_size_offset, resolved_gen_ctx_offset] =
unpack_indirects<4>(indirect, { input_offset, output_offset, input_size_offset, gen_ctx_offset });

auto input_length_read = constrained_read_from_memory(
call_ptr, clk, resolved_input_size_offset, AvmMemoryTag::U32, AvmMemoryTag::U0, IntermRegister::IA);
auto gen_ctx_read = constrained_read_from_memory(
call_ptr, clk, resolved_gen_ctx_offset, AvmMemoryTag::U32, AvmMemoryTag::U0, IntermRegister::IB);

main_trace.push_back(Row{
.main_clk = clk,
.main_ia = input_length_read.val,
.main_ib = gen_ctx_read.val,
.main_ind_addr_a = FF(input_length_read.indirect_address),
.main_ind_addr_b = FF(gen_ctx_read.indirect_address),
.main_internal_return_ptr = FF(internal_return_ptr),
.main_mem_addr_a = FF(input_length_read.direct_address),
.main_mem_addr_b = FF(gen_ctx_read.direct_address),
.main_pc = FF(pc),
.main_r_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::U32)),
.main_sel_mem_op_a = FF(1),
.main_sel_mem_op_b = FF(1),
.main_sel_resolve_ind_addr_a = FF(static_cast<uint32_t>(input_length_read.is_indirect)),
.main_sel_resolve_ind_addr_b = FF(static_cast<uint32_t>(gen_ctx_read.is_indirect)),
});
clk++;

std::vector<FF> inputs;
auto num_rows = read_slice_to_memory<FF>(call_ptr,
clk,
resolved_input_offset,
AvmMemoryTag::FF,
AvmMemoryTag::U0,
FF(internal_return_ptr),
uint32_t(input_length_read.val),
inputs);
clk += num_rows;

grumpkin::g1::affine_element result =
crypto::pedersen_commitment::commit_native(inputs, uint32_t(gen_ctx_read.val));

auto write_x = constrained_write_to_memory(
call_ptr, clk, resolved_output_offset, result.x, AvmMemoryTag::U0, AvmMemoryTag::FF, IntermRegister::IA);

mem_trace_builder.write_into_memory(
call_ptr, clk, IntermRegister::IB, write_x.direct_address + 1, result.y, AvmMemoryTag::U0, AvmMemoryTag::FF);

main_trace.push_back(Row{
.main_clk = clk,
.main_ia = result.x,
.main_ib = result.y,
.main_ind_addr_a = FF(write_x.indirect_address),
.main_internal_return_ptr = FF(internal_return_ptr),
.main_mem_addr_a = FF(write_x.direct_address),
.main_mem_addr_b = FF(write_x.direct_address + 1),
.main_pc = FF(pc),
.main_rwa = FF(1),
.main_rwb = FF(1),
.main_sel_mem_op_a = FF(1),
.main_sel_mem_op_b = FF(1),
.main_sel_resolve_ind_addr_a = FF(static_cast<uint32_t>(write_x.is_indirect)),
.main_w_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::FF)),
});

clk++;
mem_trace_builder.write_into_memory(call_ptr,
clk,
IntermRegister::IA,
write_x.direct_address + 2,
result.is_point_at_infinity(),
AvmMemoryTag::U0,
AvmMemoryTag::U8);
main_trace.push_back(Row{
.main_clk = clk,
.main_ia = static_cast<uint8_t>(result.is_point_at_infinity()),
.main_internal_return_ptr = FF(internal_return_ptr),
.main_mem_addr_a = FF(write_x.direct_address + 2),
.main_pc = FF(pc),
.main_rwa = FF(1),
.main_sel_mem_op_a = FF(1),
.main_w_in_tag = FF(static_cast<uint32_t>(AvmMemoryTag::U8)),
});
pc++;
}

/**************************************************************************************************
* CONVERSIONS
**************************************************************************************************/
Expand Down
5 changes: 5 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 @@ -152,6 +152,11 @@ class AvmTraceBuilder {
uint32_t scalars_offset,
uint32_t output_offset,
uint32_t point_length_offset);
void op_pedersen_commit(uint8_t indirect,
uint32_t output_offset,
uint32_t input_offset,
uint32_t input_size_offset,
uint32_t gen_ctx_offset);
// Conversions
void op_to_radix_le(uint8_t indirect, uint32_t src_offset, uint32_t dst_offset, uint32_t radix, uint32_t num_limbs);

Expand Down
63 changes: 63 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,69 @@ TEST_F(AvmExecutionTests, msmOpCode)
validate_trace(std::move(trace), public_inputs, calldata, returndata);
}

// Positive test with pedersen commitment
TEST_F(AvmExecutionTests, pedersenCommitmentOpcode)
{
auto expected_result =
grumpkin::g1::affine_element(fr(uint256_t("054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402")),
fr(uint256_t("209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126")));
// grumpkin::g1::affine_eleelement;
// grumpkin::g1::affine_element b = grumpkin::g1::affine_element::one();

// Remmeber that grumpkin Fq == BN254 Fr => aka FF
grumpkin::g1::Fq scalar_a = grumpkin::g1::Fq::zero();
grumpkin::g1::Fq scalar_b = grumpkin::g1::Fq::one();
std::vector<FF> expected_output = { expected_result.x, expected_result.y, expected_result.is_point_at_infinity() };
// Send all the input as Fields and cast them to U8 later
std::vector<FF> calldata = { scalar_a, scalar_b };
std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // Calldatacopy...should fix the limit on calldatacopy
"00" // Indirect flag
"00000000" // cd_offset 0
"00000002" // copy_size (2 elements)
"00000000" // dst_offset 0
+ to_hex(OpCode::SET) + // opcode SET for indirect input
"00" // Indirect flag
"03" // U32
"00000000" // Input stored at memory 0
"0000000b" // dst offset (11)
+ to_hex(OpCode::SET) + // opcode SET for indirect output
"00" // Indirect flag
"03" // U32
"00000020" // output offset
"0000000d" // dst offset
+ to_hex(OpCode::SET) + // opcode SET for input length
"00" // Indirect flag
"03" // U32
"00000002" // scalars length (2)
"00000002" + // dst offset (3)
to_hex(OpCode::SET) + // opcode SET for ctx index
"00" // Indirect flag
"03" // U32
"00000000" // ctx index (0)
"0000000f" + // dst offset
to_hex(OpCode::PEDERSENCOMMITMENT) + // opcode MSM
"03" // Indirect flag (first 2 indirect)
"0000000b" // inputs offset
"0000000d" // outputs offset
"00000002" // inputs length offset
"0000000f" // gen ctx index offset
+ to_hex(OpCode::RETURN) + // opcode RETURN
"00" // Indirect flag
"00000020" // ret offset
"00000003"; // ret size 3

auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> returndata;
auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec);

EXPECT_EQ(returndata, expected_output);

validate_trace(std::move(trace), public_inputs, calldata, returndata);
}

// Positive test for Kernel Input opcodes
TEST_F(AvmExecutionTests, kernelInputOpcodes)
{
Expand Down
10 changes: 7 additions & 3 deletions yarn-project/bb-prover/src/avm_proving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,15 @@ describe('AVM WitGen, proof generation and verification', () => {
* Avm Embedded Curve functions
************************************************************************/
describe('AVM Embedded Curve functions', () => {
const avmEmbeddedCurveFunctions: string[] = ['elliptic_curve_add_and_double', 'variable_base_msm'];
const avmEmbeddedCurveFunctions: [string, Fr[]][] = [
['elliptic_curve_add_and_double', []],
['variable_base_msm', []],
['pedersen_commit', [new Fr(1), new Fr(100)]],
];
it.each(avmEmbeddedCurveFunctions)(
'Should prove %s',
async name => {
await proveAndVerifyAvmTestContract(name);
async (name, calldata) => {
await proveAndVerifyAvmTestContract(name, calldata);
},
TIMEOUT,
);
Expand Down
92 changes: 46 additions & 46 deletions yarn-project/simulator/src/avm/opcodes/commitment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,60 @@ import { Addressing } from './addressing_mode.js';
import { Instruction } from './instruction.js';

export class PedersenCommitment extends Instruction {
static type: string = 'PEDERSENCOMMITMENT';
static readonly opcode: Opcode = Opcode.PEDERSENCOMMITMENT;
static type: string = 'PEDERSENCOMMITMENT';
static readonly opcode: Opcode = Opcode.PEDERSENCOMMITMENT;

// Informs (de)serialization. See Instruction.deserialize.
static readonly wireFormat: OperandType[] = [
OperandType.UINT8 /* Opcode */,
OperandType.UINT8 /* Indirect */,
OperandType.UINT32 /* Input Offset*/,
OperandType.UINT32 /* Dst Offset */,
OperandType.UINT32 /* Input Size Offset */,
OperandType.UINT32 /* Generator Index Offset */,
];
// Informs (de)serialization. See Instruction.deserialize.
static readonly wireFormat: OperandType[] = [
OperandType.UINT8 /* Opcode */,
OperandType.UINT8 /* Indirect */,
OperandType.UINT32 /* Input Offset*/,
OperandType.UINT32 /* Dst Offset */,
OperandType.UINT32 /* Input Size Offset */,
OperandType.UINT32 /* Generator Index Offset */,
];

constructor(
private indirect: number,
private inputOffset: number,
private outputOffset: number,
private inputSizeOffset: number,
private genIndexOffset: number,
) {
super();
}
constructor(
private indirect: number,
private inputOffset: number,
private outputOffset: number,
private inputSizeOffset: number,
private genIndexOffset: number,
) {
super();
}

public async execute(context: AvmContext): Promise<void> {
const memory = context.machineState.memory.track(this.type);
const [inputOffset, outputOffset, inputSizeOffset, genIndexOffset] = Addressing.fromWire(this.indirect).resolve(
[this.inputOffset, this.outputOffset, this.inputSizeOffset, this.genIndexOffset],
memory,
);
public async execute(context: AvmContext): Promise<void> {
const memory = context.machineState.memory.track(this.type);
const [inputOffset, outputOffset, inputSizeOffset, genIndexOffset] = Addressing.fromWire(this.indirect).resolve(
[this.inputOffset, this.outputOffset, this.inputSizeOffset, this.genIndexOffset],
memory,
);

const inputSize = memory.get(inputSizeOffset).toNumber();
memory.checkTag(TypeTag.UINT32, inputSizeOffset);
const inputSize = memory.get(inputSizeOffset).toNumber();
memory.checkTag(TypeTag.UINT32, inputSizeOffset);

const inputs = memory.getSlice(inputOffset, inputSize);
memory.checkTagsRange(TypeTag.FIELD, inputOffset, inputSize);
const inputs = memory.getSlice(inputOffset, inputSize);
memory.checkTagsRange(TypeTag.FIELD, inputOffset, inputSize);

// Generator index not used for now since we dont utilise it in the pedersenCommit function
memory.checkTag(TypeTag.UINT32, genIndexOffset);
// Generator index not used for now since we dont utilise it in the pedersenCommit function
memory.checkTag(TypeTag.UINT32, genIndexOffset);

const memoryOperations = { reads: inputSize + 1, writes: 3, indirect: this.indirect };
context.machineState.consumeGas(this.gasCost(memoryOperations));
const memoryOperations = { reads: inputSize + 1, writes: 3, indirect: this.indirect };
context.machineState.consumeGas(this.gasCost(memoryOperations));

const inputBuffer: Buffer[] = inputs.map(input => input.toBuffer());
// TODO: Add the generate index to the pedersenCommit function
const commitment = pedersenCommit(inputBuffer).map(f => new Field(f));
// The function doesnt include a flag if the output point is infinity, come back to this
// for now we just check if theyre zero - until we know how bb encodes them
const isInfinity = commitment[0].equals(new Field(0)) && commitment[1].equals(new Field(0));
const inputBuffer: Buffer[] = inputs.map(input => input.toBuffer());
// TODO: Add the generate index to the pedersenCommit function
const commitment = pedersenCommit(inputBuffer).map(f => new Field(f));
// The function doesnt include a flag if the output point is infinity, come back to this
// for now we just check if theyre zero - until we know how bb encodes them
const isInfinity = commitment[0].equals(new Field(0)) && commitment[1].equals(new Field(0));

memory.set(outputOffset, commitment[0]); // Field typed
memory.set(outputOffset + 1, commitment[1]); // Field typed
memory.set(outputOffset + 2, new Uint8(isInfinity ? 1 : 0)); // U8 typed
memory.set(outputOffset, commitment[0]); // Field typed
memory.set(outputOffset + 1, commitment[1]); // Field typed
memory.set(outputOffset + 2, new Uint8(isInfinity ? 1 : 0)); // U8 typed

memory.assert(memoryOperations);
context.machineState.incrementPc();
}
memory.assert(memoryOperations);
context.machineState.incrementPc();
}
}

0 comments on commit d1f8e48

Please sign in to comment.