From 0d66d5dbc7a281591f05f2cc36aaf80f9043dd2f Mon Sep 17 00:00:00 2001 From: fcarreiro Date: Thu, 21 Mar 2024 16:53:24 +0000 Subject: [PATCH] fix(avm-simulator): hashing opcodes indirection --- avm-transpiler/src/transpile.rs | 30 +++--- .../src/avm/avm_memory_types.test.ts | 8 +- .../simulator/src/avm/avm_memory_types.ts | 1 + .../src/avm/opcodes/comparators.test.ts | 12 +-- .../simulator/src/avm/opcodes/hashing.test.ts | 99 +++++++++++-------- .../simulator/src/avm/opcodes/hashing.ts | 47 +++++---- 6 files changed, 113 insertions(+), 84 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 5e3c81eaa2e9..88e7e3cc8bcb 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -642,8 +642,8 @@ fn handle_2_field_hash_instruction( inputs: &[ValueOrArray], ) { // handle field returns differently - let hash_offset_maybe = inputs[0]; - let (hash_offset, hash_size) = match hash_offset_maybe { + let message_offset_maybe = inputs[0]; + let (message_offset, message_size) = match message_offset_maybe { ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), _ => panic!("Keccak | Sha256 address inputs destination should be a single value"), }; @@ -669,16 +669,16 @@ fn handle_2_field_hash_instruction( avm_instrs.push(AvmInstruction { opcode, - indirect: Some(3), // 11 - addressing mode, indirect for input and output + indirect: Some(ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT), operands: vec![ AvmOperand::U32 { value: dest_offset as u32, }, AvmOperand::U32 { - value: hash_offset as u32, + value: message_offset as u32, }, AvmOperand::U32 { - value: hash_size as u32, + value: message_size as u32, }, ], ..Default::default() @@ -701,8 +701,8 @@ fn handle_single_field_hash_instruction( inputs: &[ValueOrArray], ) { // handle field returns differently - let hash_offset_maybe = inputs[0]; - let (hash_offset, hash_size) = match hash_offset_maybe { + let message_offset_maybe = inputs[0]; + let (message_offset, message_size) = match message_offset_maybe { ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), _ => panic!("Poseidon address inputs destination should be a single value"), }; @@ -724,16 +724,16 @@ fn handle_single_field_hash_instruction( avm_instrs.push(AvmInstruction { opcode, - indirect: Some(1), + indirect: Some(FIRST_OPERAND_INDIRECT), operands: vec![ AvmOperand::U32 { value: dest_offset as u32, }, AvmOperand::U32 { - value: hash_offset as u32, + value: message_offset as u32, }, AvmOperand::U32 { - value: hash_size as u32, + value: message_size as u32, }, ], ..Default::default() @@ -882,23 +882,23 @@ fn handle_black_box_function(avm_instrs: &mut Vec, operation: &B domain_separator: _, output, } => { - let hash_offset = inputs.pointer.0; - let hash_size = inputs.size.0; + let message_offset = inputs.pointer.0; + let message_size_offset = inputs.size.0; let dest_offset = output.0; avm_instrs.push(AvmInstruction { opcode: AvmOpcode::PEDERSEN, - indirect: Some(1), + indirect: Some(FIRST_OPERAND_INDIRECT), operands: vec![ AvmOperand::U32 { value: dest_offset as u32, }, AvmOperand::U32 { - value: hash_offset as u32, + value: message_offset as u32, }, AvmOperand::U32 { - value: hash_size as u32, + value: message_size_offset as u32, }, ], ..Default::default() diff --git a/yarn-project/simulator/src/avm/avm_memory_types.test.ts b/yarn-project/simulator/src/avm/avm_memory_types.test.ts index d491616d853d..982f6cea98bf 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.test.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.test.ts @@ -18,13 +18,13 @@ describe('TaggedMemory', () => { expect(mem.get(10)).toStrictEqual(new Field(5)); }); - it(`Should getSlice beyond current size`, () => { + it(`Should fail getSlice on unset elements`, () => { const mem = new TaggedMemory(); - const val = [new Field(5), new Field(6)]; - mem.setSlice(10, val); + mem.set(10, new Field(10)); + mem.set(12, new Field(12)); - expect(mem.getSlice(10, /*size=*/ 4)).toEqual([...val, undefined, undefined]); + expect(() => mem.getSlice(10, /*size=*/ 4)).toThrow(/size/); }); it(`Should set and get slices`, () => { diff --git a/yarn-project/simulator/src/avm/avm_memory_types.ts b/yarn-project/simulator/src/avm/avm_memory_types.ts index 9099eef19307..7f4b07462a09 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.ts @@ -229,6 +229,7 @@ export class TaggedMemory { assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE); const value = this._mem.slice(offset, offset + size); TaggedMemory.log(`getSlice(${offset}, ${size}) = ${value}`); + assert(value.length === size, `Expected slice of size ${size}, got ${value.length}.`); return value; } diff --git a/yarn-project/simulator/src/avm/opcodes/comparators.test.ts b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts index 97fff094a6ac..4591a05a1954 100644 --- a/yarn-project/simulator/src/avm/opcodes/comparators.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts @@ -42,7 +42,7 @@ describe('Comparators', () => { new Eq(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 3, /*dstOffset=*/ 12), ].forEach(i => i.execute(context)); - const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 3); expect(actual).toEqual([new Uint8(0), new Uint8(0), new Uint8(1)]); }); @@ -55,7 +55,7 @@ describe('Comparators', () => { new Eq(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 3, /*dstOffset=*/ 12), ].forEach(i => i.execute(context)); - const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 3); expect(actual).toEqual([new Uint8(0), new Uint8(0), new Uint8(1)]); }); @@ -106,7 +106,7 @@ describe('Comparators', () => { new Lt(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), ].forEach(i => i.execute(context)); - const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 3); expect(actual).toEqual([new Uint8(0), new Uint8(1), new Uint8(0)]); }); @@ -119,7 +119,7 @@ describe('Comparators', () => { new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), ].forEach(i => i.execute(context)); - const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 3); expect(actual).toEqual([new Uint8(0), new Uint8(1), new Uint8(0)]); }); @@ -170,7 +170,7 @@ describe('Comparators', () => { new Lte(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), ].forEach(i => i.execute(context)); - const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 3); expect(actual).toEqual([new Uint8(1), new Uint8(1), new Uint8(0)]); }); @@ -183,7 +183,7 @@ describe('Comparators', () => { new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), ].forEach(i => i.execute(context)); - const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 3); expect(actual).toEqual([new Uint8(1), new Uint8(1), new Uint8(0)]); }); diff --git a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts index 0db16f99013b..1b261643950e 100644 --- a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts @@ -3,6 +3,7 @@ import { keccak, pedersenHash, poseidonHash, sha256 } from '@aztec/foundation/cr import { AvmContext } from '../avm_context.js'; import { Field, Uint32 } from '../avm_memory_types.js'; import { initContext } from '../fixtures/index.js'; +import { Addressing, AddressingMode } from './addressing_mode.js'; import { Keccak, Pedersen, Poseidon2, Sha256 } from './hashing.js'; describe('Hashing Opcodes', () => { @@ -18,13 +19,13 @@ describe('Hashing Opcodes', () => { Poseidon2.opcode, // opcode 1, // indirect ...Buffer.from('12345678', 'hex'), // dstOffset - ...Buffer.from('23456789', 'hex'), // hashOffset + ...Buffer.from('23456789', 'hex'), // messageOffset ...Buffer.from('3456789a', 'hex'), // hashSize ]); const inst = new Poseidon2( /*indirect=*/ 1, /*dstOffset=*/ 0x12345678, - /*hashOffset=*/ 0x23456789, + /*messageOffset=*/ 0x23456789, /*hashSize=*/ 0x3456789a, ); @@ -35,13 +36,13 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - direct', async () => { const indirect = 0; const args = [new Field(1n), new Field(2n), new Field(3n)]; - const hashOffset = 0; - context.machineState.memory.setSlice(hashOffset, args); + const messageOffset = 0; + context.machineState.memory.setSlice(messageOffset, args); const dstOffset = 3; const expectedHash = poseidonHash(args.map(field => field.toBuffer())); - await new Poseidon2(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Poseidon2(indirect, dstOffset, messageOffset, args.length).execute(context); const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); @@ -49,17 +50,20 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - indirect', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; - const indirect = 1; - const hashOffset = 0; + const indirect = new Addressing([ + /*dstOffset=*/ AddressingMode.DIRECT, + /*messageOffset*/ AddressingMode.INDIRECT, + ]).toWire(); + const messageOffset = 0; const realLocation = 4; - context.machineState.memory.set(hashOffset, new Uint32(realLocation)); + context.machineState.memory.set(messageOffset, new Uint32(realLocation)); context.machineState.memory.setSlice(realLocation, args); const dstOffset = 3; const expectedHash = poseidonHash(args.map(field => field.toBuffer())); - await new Poseidon2(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Poseidon2(indirect, dstOffset, messageOffset, args.length).execute(context); const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); @@ -72,13 +76,13 @@ describe('Hashing Opcodes', () => { Keccak.opcode, // opcode 1, // indirect ...Buffer.from('12345678', 'hex'), // dstOffset - ...Buffer.from('23456789', 'hex'), // hashOffset + ...Buffer.from('23456789', 'hex'), // messageOffset ...Buffer.from('3456789a', 'hex'), // hashSize ]); const inst = new Keccak( /*indirect=*/ 1, /*dstOffset=*/ 0x12345678, - /*hashOffset=*/ 0x23456789, + /*messageOffset=*/ 0x23456789, /*hashSize=*/ 0x3456789a, ); @@ -89,14 +93,14 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - direct', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; const indirect = 0; - const hashOffset = 0; - context.machineState.memory.setSlice(hashOffset, args); + const messageOffset = 0; + context.machineState.memory.setSlice(messageOffset, args); const dstOffset = 3; const inputBuffer = Buffer.concat(args.map(field => field.toBuffer())); const expectedHash = keccak(inputBuffer); - await new Keccak(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Keccak(indirect, dstOffset, messageOffset, args.length).execute(context); const result = context.machineState.memory.getSliceAs(dstOffset, 2); const combined = Buffer.concat([result[0].toBuffer().subarray(16, 32), result[1].toBuffer().subarray(16, 32)]); @@ -106,20 +110,23 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - indirect', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; - const indirect = 3; // dest and return are indirect - const hashOffset = 0; + const indirect = new Addressing([ + /*dstOffset=*/ AddressingMode.INDIRECT, + /*messageOffset*/ AddressingMode.INDIRECT, + ]).toWire(); + const messageOffset = 0; const argsLocation = 4; const dstOffset = 2; const readLocation = 6; - context.machineState.memory.set(hashOffset, new Uint32(argsLocation)); + context.machineState.memory.set(messageOffset, new Uint32(argsLocation)); context.machineState.memory.set(dstOffset, new Uint32(readLocation)); context.machineState.memory.setSlice(argsLocation, args); const inputBuffer = Buffer.concat(args.map(field => field.toBuffer())); const expectedHash = keccak(inputBuffer); - await new Keccak(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Keccak(indirect, dstOffset, messageOffset, args.length).execute(context); const result = context.machineState.memory.getSliceAs(readLocation, 2); const combined = Buffer.concat([result[0].toBuffer().subarray(16, 32), result[1].toBuffer().subarray(16, 32)]); @@ -134,13 +141,13 @@ describe('Hashing Opcodes', () => { Sha256.opcode, // opcode 1, // indirect ...Buffer.from('12345678', 'hex'), // dstOffset - ...Buffer.from('23456789', 'hex'), // hashOffset + ...Buffer.from('23456789', 'hex'), // messageOffset ...Buffer.from('3456789a', 'hex'), // hashSize ]); const inst = new Sha256( /*indirect=*/ 1, /*dstOffset=*/ 0x12345678, - /*hashOffset=*/ 0x23456789, + /*messageOffset=*/ 0x23456789, /*hashSize=*/ 0x3456789a, ); @@ -150,15 +157,15 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - direct', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; - const hashOffset = 0; + const messageOffset = 0; const indirect = 0; - context.machineState.memory.setSlice(hashOffset, args); + context.machineState.memory.setSlice(messageOffset, args); const dstOffset = 3; const inputBuffer = Buffer.concat(args.map(field => field.toBuffer())); const expectedHash = sha256(inputBuffer); - await new Sha256(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Sha256(indirect, dstOffset, messageOffset, args.length).execute(context); const result = context.machineState.memory.getSliceAs(dstOffset, 2); const combined = Buffer.concat([result[0].toBuffer().subarray(16, 32), result[1].toBuffer().subarray(16, 32)]); @@ -168,20 +175,23 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - indirect', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; - const indirect = 3; // dest and return are indirect - const hashOffset = 0; + const indirect = new Addressing([ + /*dstOffset=*/ AddressingMode.INDIRECT, + /*messageOffset*/ AddressingMode.INDIRECT, + ]).toWire(); + const messageOffset = 0; const argsLocation = 4; const dstOffset = 2; const readLocation = 6; - context.machineState.memory.set(hashOffset, new Uint32(argsLocation)); + context.machineState.memory.set(messageOffset, new Uint32(argsLocation)); context.machineState.memory.set(dstOffset, new Uint32(readLocation)); context.machineState.memory.setSlice(argsLocation, args); const inputBuffer = Buffer.concat(args.map(field => field.toBuffer())); const expectedHash = sha256(inputBuffer); - await new Sha256(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Sha256(indirect, dstOffset, messageOffset, args.length).execute(context); const result = context.machineState.memory.getSliceAs(readLocation, 2); const combined = Buffer.concat([result[0].toBuffer().subarray(16, 32), result[1].toBuffer().subarray(16, 32)]); @@ -196,31 +206,34 @@ describe('Hashing Opcodes', () => { Pedersen.opcode, // opcode 1, // indirect ...Buffer.from('12345678', 'hex'), // dstOffset - ...Buffer.from('23456789', 'hex'), // hashOffset + ...Buffer.from('23456789', 'hex'), // messageOffset ...Buffer.from('3456789a', 'hex'), // hashSize ]); const inst = new Pedersen( /*indirect=*/ 1, /*dstOffset=*/ 0x12345678, - /*hashOffset=*/ 0x23456789, - /*hashSize=*/ 0x3456789a, + /*messageOffset=*/ 0x23456789, + /*hashSizeOffset=*/ 0x3456789a, ); - expect(Sha256.deserialize(buf)).toEqual(inst); + expect(Pedersen.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); }); it('Should hash correctly - direct', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; - const hashOffset = 0; + const messageOffset = 0; + const sizeOffset = 10; const indirect = 0; - context.machineState.memory.setSlice(hashOffset, args); + + context.machineState.memory.setSlice(messageOffset, args); + context.machineState.memory.set(sizeOffset, new Uint32(args.length)); const dstOffset = 3; const inputBuffer = args.map(field => field.toBuffer()); const expectedHash = pedersenHash(inputBuffer); - await new Pedersen(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Pedersen(indirect, dstOffset, messageOffset, sizeOffset).execute(context); const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); @@ -228,18 +241,26 @@ describe('Hashing Opcodes', () => { it('Should hash correctly - indirect', async () => { const args = [new Field(1n), new Field(2n), new Field(3n)]; - const indirect = 1; - const hashOffset = 0; + const indirect = new Addressing([ + /*dstOffset=*/ AddressingMode.DIRECT, + /*messageOffset*/ AddressingMode.INDIRECT, + /*messageSizeOffset*/ AddressingMode.INDIRECT, + ]).toWire(); + const messageOffset = 0; + const sizeOffset = 10; const realLocation = 4; + const realSizeLocation = 20; - context.machineState.memory.set(hashOffset, new Uint32(realLocation)); + context.machineState.memory.set(messageOffset, new Uint32(realLocation)); + context.machineState.memory.set(sizeOffset, new Uint32(realSizeLocation)); context.machineState.memory.setSlice(realLocation, args); + context.machineState.memory.set(realSizeLocation, new Uint32(args.length)); - const dstOffset = 3; + const dstOffset = 300; const inputBuffer = args.map(field => field.toBuffer()); const expectedHash = pedersenHash(inputBuffer); - await new Pedersen(indirect, dstOffset, hashOffset, args.length).execute(context); + await new Pedersen(indirect, dstOffset, messageOffset, sizeOffset).execute(context); const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); diff --git a/yarn-project/simulator/src/avm/opcodes/hashing.ts b/yarn-project/simulator/src/avm/opcodes/hashing.ts index 99e64b0a4439..ca212dc2d197 100644 --- a/yarn-project/simulator/src/avm/opcodes/hashing.ts +++ b/yarn-project/simulator/src/avm/opcodes/hashing.ts @@ -23,21 +23,24 @@ export class Poseidon2 extends Instruction { constructor( private indirect: number, private dstOffset: number, - private hashOffset: number, - private hashSize: number, + private messageOffset: number, + private messageSize: number, ) { super(); } async execute(context: AvmContext): Promise { // We hash a set of field elements - const [hashOffset] = Addressing.fromWire(this.indirect).resolve([this.hashOffset], context.machineState.memory); + const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve( + [this.dstOffset, this.messageOffset], + context.machineState.memory, + ); // Memory pointer will be indirect - const hashData = context.machineState.memory.getSlice(hashOffset, this.hashSize).map(word => word.toBuffer()); + const hashData = context.machineState.memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer()); const hash = poseidonHash(hashData); - context.machineState.memory.set(this.dstOffset, new Field(hash)); + context.machineState.memory.set(dstOffset, new Field(hash)); context.machineState.incrementPc(); } @@ -59,8 +62,8 @@ export class Keccak extends Instruction { constructor( private indirect: number, private dstOffset: number, - private hashOffset: number, - private hashSize: number, + private messageOffset: number, + private messageSize: number, ) { super(); } @@ -68,12 +71,12 @@ export class Keccak extends Instruction { // Note hash output is 32 bytes, so takes up two fields async execute(context: AvmContext): Promise { // We hash a set of field elements - const [hashOffset, dstOffset] = Addressing.fromWire(this.indirect).resolve( - [this.hashOffset, this.dstOffset], + const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve( + [this.dstOffset, this.messageOffset], context.machineState.memory, ); - const hashData = context.machineState.memory.getSlice(hashOffset, this.hashSize).map(word => word.toBuffer()); + const hashData = context.machineState.memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer()); const hash = keccak(Buffer.concat(hashData)); @@ -104,21 +107,21 @@ export class Sha256 extends Instruction { constructor( private indirect: number, private dstOffset: number, - private hashOffset: number, - private hashSize: number, + private messageOffset: number, + private messageSize: number, ) { super(); } // Note hash output is 32 bytes, so takes up two fields async execute(context: AvmContext): Promise { - const [hashOffset, dstOffset] = Addressing.fromWire(this.indirect).resolve( - [this.hashOffset, this.dstOffset], + const [dstOffset, messageOffset] = Addressing.fromWire(this.indirect).resolve( + [this.dstOffset, this.messageOffset], context.machineState.memory, ); // We hash a set of field elements - const hashData = context.machineState.memory.getSlice(hashOffset, this.hashSize).map(word => word.toBuffer()); + const hashData = context.machineState.memory.getSlice(messageOffset, this.messageSize).map(word => word.toBuffer()); const hash = sha256(Buffer.concat(hashData)); @@ -149,21 +152,25 @@ export class Pedersen extends Instruction { constructor( private indirect: number, private dstOffset: number, - private hashOffset: number, - private hashSize: number, + private messageOffset: number, + private messageSizeOffset: number, ) { super(); } async execute(context: AvmContext): Promise { - const [hashOffset] = Addressing.fromWire(this.indirect).resolve([this.hashOffset], context.machineState.memory); + const [dstOffset, messageOffset, messageSizeOffset] = Addressing.fromWire(this.indirect).resolve( + [this.dstOffset, this.messageOffset, this.messageSizeOffset], + context.machineState.memory, + ); // We hash a set of field elements - const hashData = context.machineState.memory.getSlice(hashOffset, this.hashSize).map(word => word.toBuffer()); + const messageSize = Number(context.machineState.memory.get(messageSizeOffset).toBigInt()); + const hashData = context.machineState.memory.getSlice(messageOffset, messageSize).map(word => word.toBuffer()); // No domain sep for now const hash = pedersenHash(hashData); - context.machineState.memory.set(this.dstOffset, new Field(hash)); + context.machineState.memory.set(dstOffset, new Field(hash)); context.machineState.incrementPc(); }