Skip to content

Commit

Permalink
feat(avm): pedersen commitment sim
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyasRidhuan committed Jul 26, 2024
1 parent 022a899 commit 58f8593
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 3 deletions.
2 changes: 2 additions & 0 deletions avm-transpiler/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -170,6 +171,7 @@ impl AvmOpcode {
AvmOpcode::PEDERSEN => "PEDERSEN",
AvmOpcode::ECADD => "ECADD",
AvmOpcode::MSM => "MSM",
AvmOpcode::PEDERSENCOMMITMENT => "PEDERSENCOMMITMENT",
// Conversions
AvmOpcode::TORADIXLE => "TORADIXLE",
// Other
Expand Down
18 changes: 18 additions & 0 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,24 @@ fn handle_black_box_function(avm_instrs: &mut Vec<AvmInstruction>, 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),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,11 @@ const std::unordered_map<OpCode, std::vector<OperandType>> 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 } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ enum class OpCode : uint8_t {
PEDERSEN,
ECADD,
MSM,
PEDERSENCOMMITMENT,
// Conversions
TORADIXLE,
// Future Gadgets -- pending changes in noir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
************************************************************************/
Expand Down
1 change: 1 addition & 0 deletions yarn-project/simulator/src/avm/avm_gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const BaseGasCosts: Record<Opcode, Gas> = {
[Opcode.PEDERSEN]: DefaultBaseGasCost,
[Opcode.ECADD]: DefaultBaseGasCost,
[Opcode.MSM]: DefaultBaseGasCost,
[Opcode.PEDERSENCOMMITMENT]: DefaultBaseGasCost,
// Conversions
[Opcode.TORADIXLE]: DefaultBaseGasCost,
// Other
Expand Down
18 changes: 17 additions & 1 deletion yarn-project/simulator/src/avm/avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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[] = [
Expand Down
93 changes: 93 additions & 0 deletions yarn-project/simulator/src/avm/opcodes/commitment.test.ts
Original file line number Diff line number Diff line change
@@ -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());
});
});
});
66 changes: 66 additions & 0 deletions yarn-project/simulator/src/avm/opcodes/commitment.ts
Original file line number Diff line number Diff line change
@@ -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<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 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();
}
}
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 58f8593

Please sign in to comment.