From b4ad3f283ead4a1b3400cbf320e1535098d7bc8f Mon Sep 17 00:00:00 2001 From: IlyasRidhuan Date: Fri, 26 Jul 2024 13:34:24 +0000 Subject: [PATCH 1/2] feat(avm): pedersen commitment sim --- avm-transpiler/src/opcodes.rs | 2 + avm-transpiler/src/transpile.rs | 18 ++++ .../vm/avm_trace/avm_deserialization.cpp | 3 +- .../barretenberg/vm/avm_trace/avm_opcode.hpp | 1 + .../contracts/avm_test_contract/src/main.nr | 8 +- yarn-project/simulator/src/avm/avm_gas.ts | 1 + .../simulator/src/avm/avm_simulator.test.ts | 18 +++- .../src/avm/opcodes/commitment.test.ts | 93 +++++++++++++++++++ .../simulator/src/avm/opcodes/commitment.ts | 66 +++++++++++++ .../serialization/bytecode_serialization.ts | 2 + .../instruction_serialization.ts | 1 + 11 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 yarn-project/simulator/src/avm/opcodes/commitment.test.ts create mode 100644 yarn-project/simulator/src/avm/opcodes/commitment.ts diff --git a/avm-transpiler/src/opcodes.rs b/avm-transpiler/src/opcodes.rs index fc177793494..23b67dc18f9 100644 --- a/avm-transpiler/src/opcodes.rs +++ b/avm-transpiler/src/opcodes.rs @@ -74,6 +74,7 @@ pub enum AvmOpcode { PEDERSEN, // temp - may be removed, but alot of contracts rely on it ECADD, MSM, + PEDERSENCOMMITMENT, // temp // Conversions TORADIXLE, // Other @@ -170,6 +171,7 @@ impl AvmOpcode { AvmOpcode::PEDERSEN => "PEDERSEN", AvmOpcode::ECADD => "ECADD", AvmOpcode::MSM => "MSM", + AvmOpcode::PEDERSENCOMMITMENT => "PEDERSENCOMMITMENT", // Conversions AvmOpcode::TORADIXLE => "TORADIXLE", // Other diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index a6d09a975fa..4109a453355 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -888,6 +888,24 @@ fn handle_black_box_function(avm_instrs: &mut Vec, operation: &B ..Default::default() }); } + // Temporary while we dont have efficient noir implementations (again) + BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { + let input_offset = inputs.pointer.0; + let input_size_offset = inputs.size.0; + let index_offset = domain_separator.0; + let output_offset = output.pointer.0; + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::PEDERSENCOMMITMENT, + indirect: Some(ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT), + operands: vec![ + AvmOperand::U32 { value: input_offset as u32 }, + AvmOperand::U32 { value: output_offset as u32 }, + AvmOperand::U32 { value: input_size_offset as u32 }, + AvmOperand::U32 { value: index_offset as u32 }, + ], + ..Default::default() + }); + } _ => panic!("Transpiler doesn't know how to process {:?}", operation), } } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp index 1663491d3ab..a2d596c12b7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp @@ -166,10 +166,11 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = OperandType::UINT32 } }, // dst_offset { OpCode::MSM, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::PEDERSENCOMMITMENT, + { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, // Gadget - Conversion { OpCode::TORADIXLE, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, - // Gadgets - Unused for now { OpCode::SHA256COMPRESSION, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp index f2beb29d32f..c70213f355d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp @@ -106,6 +106,7 @@ enum class OpCode : uint8_t { PEDERSEN, ECADD, MSM, + PEDERSENCOMMITMENT, // Conversions TORADIXLE, // Future Gadgets -- pending changes in noir diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 5bebeadf78d..4c6838558a1 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -24,7 +24,7 @@ contract AvmTest { global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef; // Libs - use std::embedded_curve_ops::multi_scalar_mul; + use std::embedded_curve_ops::{multi_scalar_mul, EmbeddedCurvePoint}; use dep::aztec::protocol_types::constants::CONTRACT_INSTANCE_LENGTH; use dep::aztec::prelude::{Map, Deserialize}; use dep::aztec::state_vars::PublicMutable; @@ -153,6 +153,12 @@ contract AvmTest { triple_g } + #[aztec(public)] + fn pedersen_commit(x: Field, y: Field) -> EmbeddedCurvePoint { + let commitment = dep::std::hash::pedersen_commitment([x, y]); + commitment + } + /************************************************************************ * Misc ************************************************************************/ diff --git a/yarn-project/simulator/src/avm/avm_gas.ts b/yarn-project/simulator/src/avm/avm_gas.ts index 34ee3b492c5..bdb8ef86097 100644 --- a/yarn-project/simulator/src/avm/avm_gas.ts +++ b/yarn-project/simulator/src/avm/avm_gas.ts @@ -124,6 +124,7 @@ const BaseGasCosts: Record = { [Opcode.PEDERSEN]: DefaultBaseGasCost, [Opcode.ECADD]: DefaultBaseGasCost, [Opcode.MSM]: DefaultBaseGasCost, + [Opcode.PEDERSENCOMMITMENT]: DefaultBaseGasCost, // Conversions [Opcode.TORADIXLE]: DefaultBaseGasCost, // Other diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 83d4f95939b..54b42fa3f80 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -3,7 +3,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { keccak256, keccakf1600, pedersenHash, poseidon2Hash, sha256 } from '@aztec/foundation/crypto'; +import { keccak256, keccakf1600, pedersenCommit, pedersenHash, poseidon2Hash, sha256 } from '@aztec/foundation/crypto'; import { Fq, Fr } from '@aztec/foundation/fields'; import { type Fieldable } from '@aztec/foundation/serialize'; @@ -140,6 +140,22 @@ describe('AVM simulator: transpiled Noir contracts', () => { expect(results.output).toEqual([expectedResult.x, expectedResult.y, Fr.ZERO]); }); + it('pedersen commitment operations', async () => { + const calldata: Fr[] = [new Fr(100), new Fr(1)]; + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + + const bytecode = getAvmTestContractBytecode('pedersen_commit'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + expect(results.reverted).toBe(false); + // This doesnt include infinites + const expectedResult = pedersenCommit([Buffer.from([100]), Buffer.from([1])]).map(f => new Fr(f)); + // TODO: Come back to the handling of infinities when we confirm how they're handled in bb + const isInf = expectedResult[0] === new Fr(0) && expectedResult[1] === new Fr(0); + expectedResult.push(new Fr(isInf)); + expect(results.output).toEqual(expectedResult); + }); + describe('U128 addition and overflows', () => { it('U128 addition', async () => { const calldata: Fr[] = [ diff --git a/yarn-project/simulator/src/avm/opcodes/commitment.test.ts b/yarn-project/simulator/src/avm/opcodes/commitment.test.ts new file mode 100644 index 00000000000..c5b7c509334 --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/commitment.test.ts @@ -0,0 +1,93 @@ +import { pedersenCommit } from '@aztec/foundation/crypto'; + +import { type AvmContext } from '../avm_context.js'; +import { Field, Uint32 } from '../avm_memory_types.js'; +import { initContext, randomMemoryFields } from '../fixtures/index.js'; +import { Addressing, AddressingMode } from './addressing_mode.js'; +import { PedersenCommitment } from './commitment.js'; + +describe('Commitment Opcode', () => { + let context: AvmContext; + + beforeEach(async () => { + context = initContext(); + }); + + describe('Pedersen Commitment', () => { + it('Should (de)serialize correctly', () => { + const buf = Buffer.from([ + PedersenCommitment.opcode, // opcode + 1, // indirect + ...Buffer.from('23456789', 'hex'), // inputOffset + ...Buffer.from('3456789a', 'hex'), // inputSizeOffset + ...Buffer.from('12345678', 'hex'), // outputOffset + ...Buffer.from('00000000', 'hex'), // genIndexOffset + ]); + const inst = new PedersenCommitment( + /*indirect=*/ 1, + /*inputOffset=*/ 0x23456789, + /*inputSizeOffset=*/ 0x3456789a, + /*outputOffset=*/ 0x12345678, + /*genIndexOffset=*/ 0, + ); + + expect(PedersenCommitment.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should commit correctly - direct', async () => { + const args = randomMemoryFields(10); + const inputOffset = 0; + const inputSizeOffset = 20; + const outputOffset = 50; + const indirect = 0; + const generatorIndexOffset = 10; + + context.machineState.memory.setSlice(inputOffset, args); + context.machineState.memory.set(inputSizeOffset, new Uint32(args.length)); + context.machineState.memory.set(generatorIndexOffset, new Uint32(0)); + + const expectedCommitment = pedersenCommit(args.map(f => f.toBuffer())).map(f => new Field(f)); + await new PedersenCommitment(indirect, inputOffset, outputOffset, inputSizeOffset, generatorIndexOffset).execute( + context, + ); + + const result = context.machineState.memory.getSlice(outputOffset, 2); + expect(result).toEqual(expectedCommitment); + // Check Inf + expect(0).toEqual(context.machineState.memory.get(outputOffset + 2).toNumber()); + }); + + it('Should commit correctly - indirect', async () => { + const args = randomMemoryFields(10); + const indirect = new Addressing([ + /*inputOffset=*/ AddressingMode.INDIRECT, + /*outputOffset*/ AddressingMode.INDIRECT, + /*inputSizeOffset=*/ AddressingMode.DIRECT, + /*generatorIndexOffset=*/ AddressingMode.DIRECT, + ]).toWire(); + const inputOffset = 0; + const inputSizeOffset = 20; + const outputOffset = 50; + const realOutputOffset = 100; + const realInputOffset = 200; + const generatorIndexOffset = 51; + + context.machineState.memory.set(outputOffset, new Uint32(realOutputOffset)); + context.machineState.memory.set(inputOffset, new Uint32(realInputOffset)); + context.machineState.memory.setSlice(realInputOffset, args); + context.machineState.memory.set(inputSizeOffset, new Uint32(args.length)); + context.machineState.memory.set(generatorIndexOffset, new Uint32(0)); + + const expectedCommitment = pedersenCommit(args.map(f => f.toBuffer())).map(f => new Field(f)); + await new PedersenCommitment(indirect, inputOffset, outputOffset, inputSizeOffset, generatorIndexOffset).execute( + context, + ); + + const result = context.machineState.memory.getSlice(realOutputOffset, 2); + expect(result).toEqual(expectedCommitment); + // Check Inf + expect(0).toEqual(context.machineState.memory.get(realOutputOffset + 2).toNumber()); + }); + }); +}); diff --git a/yarn-project/simulator/src/avm/opcodes/commitment.ts b/yarn-project/simulator/src/avm/opcodes/commitment.ts new file mode 100644 index 00000000000..ad99064a6d9 --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/commitment.ts @@ -0,0 +1,66 @@ +import { pedersenCommit } from '@aztec/foundation/crypto'; + +import { type AvmContext } from '../avm_context.js'; +import { Field, TypeTag, Uint8 } from '../avm_memory_types.js'; +import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; +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; + + // 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(); + } + + public async execute(context: AvmContext): Promise { + 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 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); + + 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)); + + 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(); + } +} diff --git a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts index 03a0d01f0c9..46811568427 100644 --- a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts @@ -1,3 +1,4 @@ +import { PedersenCommitment } from '../opcodes/commitment.js'; import { DAGasLeft, L2GasLeft } from '../opcodes/context_getters.js'; import { EcAdd } from '../opcodes/ec_add.js'; import { Keccak, KeccakF1600, Pedersen, Poseidon2, Sha256 } from '../opcodes/hashing.js'; @@ -146,6 +147,7 @@ const INSTRUCTION_SET = () => [Sha256.opcode, Sha256], [Pedersen.opcode, Pedersen], [MultiScalarMul.opcode, MultiScalarMul], + [PedersenCommitment.opcode, PedersenCommitment], // Conversions [ToRadixLE.opcode, ToRadixLE], // Future Gadgets -- pending changes in noir diff --git a/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts b/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts index c449f49cd8b..013c35ce369 100644 --- a/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts @@ -78,6 +78,7 @@ export enum Opcode { PEDERSEN, // temp - may be removed, but alot of contracts rely on it ECADD, MSM, + PEDERSENCOMMITMENT, // Conversion TORADIXLE, // Future Gadgets -- pending changes in noir From 5789669e6c5b7a908676bf1d07d7c48907c9ba6d Mon Sep 17 00:00:00 2001 From: IlyasRidhuan Date: Fri, 26 Jul 2024 15:48:39 +0000 Subject: [PATCH 2/2] feat(avm): pedersen commit in avm --- .../vm/avm_trace/avm_execution.cpp | 8 ++ .../barretenberg/vm/avm_trace/avm_trace.cpp | 92 +++++++++++++++++++ .../barretenberg/vm/avm_trace/avm_trace.hpp | 5 + .../vm/tests/avm_execution.test.cpp | 65 ++++++++++++- .../bb-prover/src/avm_proving.test.ts | 10 +- 5 files changed, 176 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 81aefd53187..5e81e6d38a9 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -797,6 +797,14 @@ std::vector Execution::gen_trace(std::vector const& instructio std::get(inst.operands.at(2)), std::get(inst.operands.at(3))); + break; + case OpCode::PEDERSENCOMMITMENT: + trace_builder.op_pedersen_commit(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(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) + diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index 5c970222340..620d264c7c7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -14,6 +14,7 @@ #include #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" @@ -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(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(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(input_length_read.is_indirect)), + .main_sel_resolve_ind_addr_b = FF(static_cast(gen_ctx_read.is_indirect)), + }); + clk++; + + std::vector inputs; + auto num_rows = read_slice_to_memory(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(write_x.is_indirect)), + .main_w_in_tag = FF(static_cast(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(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(AvmMemoryTag::U8)), + }); + pc++; +} + /************************************************************************************************** * CONVERSIONS **************************************************************************************************/ diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index 5ec74970703..06ec1227bdf 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -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); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp index be6f99c52f9..59e627ca707 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp @@ -1261,7 +1261,7 @@ TEST_F(AvmExecutionTests, msmOpCode) // Send all the input as Fields and cast them to U8 later std::vector calldata = { FF(a.x), FF(a.y), a_is_inf, FF(b.x), FF(b.y), b_is_inf, scalar_a_lo, scalar_a_hi, scalar_b_lo, scalar_b_hi }; - std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // Calldatacopy...should fix the limit on calldatacopy + std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // Calldatacopy "00" // Indirect flag "00000000" // cd_offset 0 "0000000a" // copy_size (10 elements) @@ -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 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 calldata = { scalar_a, scalar_b }; + std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // 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 (2) + 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 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) { diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index f769425ad68..4cf5b70dded 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -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, );