forked from visoftsolutions/noir_rs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(avm): encode TS AVM instructions as bytecode, especially for tes…
…ting (AztecProtocol#4115)
- Loading branch information
Showing
7 changed files
with
124 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { mock } from 'jest-mock-extended'; | ||
|
||
import { AvmMachineState } from './avm_machine_state.js'; | ||
import { AvmStateManager } from './avm_state_manager.js'; | ||
import { AvmInterpreter } from './interpreter/interpreter.js'; | ||
import { decodeBytecode } from './opcodes/decode_bytecode.js'; | ||
import { encodeToBytecode } from './opcodes/encode_to_bytecode.js'; | ||
import { Opcode } from './opcodes/opcodes.js'; | ||
|
||
describe('avm', () => { | ||
it('Should execute bytecode', () => { | ||
const calldata: Fr[] = [new Fr(1), new Fr(2)]; | ||
const stateManager = mock<AvmStateManager>(); | ||
|
||
// Construct bytecode | ||
const calldataCopyArgs = [0, 2, 0]; | ||
const addArgs = [0, 1, 2]; | ||
const returnArgs = [2, 1]; | ||
|
||
const calldataCopyBytecode = encodeToBytecode(Opcode.CALLDATACOPY, calldataCopyArgs); | ||
const addBytecode = encodeToBytecode(Opcode.ADD, addArgs); | ||
const returnBytecode = encodeToBytecode(Opcode.RETURN, returnArgs); | ||
const fullBytecode = Buffer.concat([calldataCopyBytecode, addBytecode, returnBytecode]); | ||
|
||
// Decode bytecode into instructions | ||
const instructions = decodeBytecode(fullBytecode); | ||
|
||
// Execute instructions | ||
const context = new AvmMachineState(calldata); | ||
const interpreter = new AvmInterpreter(context, stateManager, instructions); | ||
const avmReturnData = interpreter.run(); | ||
|
||
expect(avmReturnData.reverted).toBe(false); | ||
|
||
const returnData = avmReturnData.output; | ||
expect(returnData.length).toBe(1); | ||
expect(returnData).toEqual([new Fr(3)]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
yarn-project/acir-simulator/src/avm/opcodes/encode_to_bytecode.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { encodeToBytecode } from './encode_to_bytecode.js'; | ||
import { AVM_OPCODE_BYTE_LENGTH, AVM_OPERAND_BYTE_LENGTH } from './instruction.js'; | ||
import { Opcode } from './opcodes.js'; | ||
|
||
describe('Avm Encoder', () => { | ||
const toByte = (num: number): Buffer => { | ||
const buf = Buffer.alloc(AVM_OPCODE_BYTE_LENGTH); | ||
buf.writeUInt8(num); | ||
return buf; | ||
}; | ||
const to4Byte = (num: number): Buffer => { | ||
const buf = Buffer.alloc(AVM_OPERAND_BYTE_LENGTH); | ||
buf.writeUInt32BE(num); | ||
return buf; | ||
}; | ||
|
||
it('Should properly encode instructions into bytecode buffers', () => { | ||
const addArgs = [0, 1, 2]; | ||
const subArgs = [3, 4, 5]; | ||
|
||
const addBytecode = encodeToBytecode(Opcode.ADD, addArgs); | ||
const subBytecode = encodeToBytecode(Opcode.SUB, subArgs); | ||
|
||
const expectedAddBytecode = Buffer.concat([toByte(Opcode.ADD), to4Byte(0), to4Byte(1), to4Byte(2)]); | ||
const expectedSubBytecode = Buffer.concat([toByte(Opcode.SUB), to4Byte(3), to4Byte(4), to4Byte(5)]); | ||
|
||
expect(addBytecode).toEqual(expectedAddBytecode); | ||
expect(subBytecode).toEqual(expectedSubBytecode); | ||
}); | ||
}); |
32 changes: 32 additions & 0 deletions
32
yarn-project/acir-simulator/src/avm/opcodes/encode_to_bytecode.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { AVM_OPCODE_BYTE_LENGTH, AVM_OPERAND_BYTE_LENGTH } from './instruction.js'; | ||
import { INSTRUCTION_SET } from './instruction_set.js'; | ||
import { Opcode } from './opcodes.js'; | ||
|
||
/** | ||
* Encode an instruction (opcode & arguments) to bytecode. | ||
* @param opcode - the opcode to encode | ||
* @param args - the arguments to encode | ||
* @returns the bytecode for this one instruction | ||
*/ | ||
export function encodeToBytecode(opcode: Opcode, args: number[]): Buffer { | ||
const instructionType = INSTRUCTION_SET.get(opcode); | ||
if (instructionType === undefined) { | ||
throw new Error(`Opcode ${opcode} not implemented`); | ||
} | ||
|
||
const numberOfOperands = instructionType.numberOfOperands; | ||
if (args.length !== numberOfOperands) { | ||
throw new Error(`Opcode ${opcode} expects ${numberOfOperands} arguments, but ${args.length} were provided`); | ||
} | ||
|
||
const bytecode = Buffer.alloc(AVM_OPCODE_BYTE_LENGTH + numberOfOperands * AVM_OPERAND_BYTE_LENGTH); | ||
|
||
let bytePtr = 0; | ||
bytecode.writeUInt8(opcode as number, bytePtr); | ||
bytePtr += AVM_OPCODE_BYTE_LENGTH; | ||
for (let i = 0; i < args.length; i++) { | ||
bytecode.writeUInt32BE(args[i], bytePtr); | ||
bytePtr += AVM_OPERAND_BYTE_LENGTH; | ||
} | ||
return bytecode; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters