Skip to content

Commit

Permalink
feat(avm): add tests for memory and bitwise instructions (AztecProtoc…
Browse files Browse the repository at this point in the history
…ol#4184)

I have to implement memory tagging first for these to make sense, so I'm
merging this and then going back to it.

Advances AztecProtocol#4120 and AztecProtocol#4121.
  • Loading branch information
fcarreiro authored Jan 23, 2024
1 parent 5de0a8e commit 6dac650
Show file tree
Hide file tree
Showing 8 changed files with 454 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,6 @@ export abstract class AvmInterpreterError extends Error {
export class InvalidProgramCounterError extends AvmInterpreterError {
constructor(pc: number, max: number) {
super(`Invalid program counter ${pc}, max is ${max}`);
this.name = 'InvalidProgramCounterError';
}
}
166 changes: 166 additions & 0 deletions yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
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 {
And,
/*Not,*/
Or,
Shl,
Shr,
Xor,
} from './bitwise.js';

describe('Bitwise instructions', () => {
let machineState: AvmMachineState;
let stateManager = mock<AvmStateManager>();

beforeEach(() => {
machineState = new AvmMachineState([]);
stateManager = mock<AvmStateManager>();
});

it('Should AND correctly over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(0b11100100111001001111n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new And(0, 1, 2).execute(machineState, stateManager);

const expected = new Fr(0b11100100010001000100n);
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

it('Should OR correctly over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(0b11100100111001001111n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Or(0, 1, 2).execute(machineState, stateManager);

const expected = new Fr(0b11111110111011101111n);
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

it('Should XOR correctly over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(0b11100100111001001111n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Xor(0, 1, 2).execute(machineState, stateManager);

const expected = new Fr(0b00011010101010101011n);
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

describe('SHR', () => {
it('Should shift correctly 0 positions over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(0n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Shr(0, 1, 2).execute(machineState, stateManager);

const expected = a;
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

it('Should shift correctly 2 positions over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(2n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Shr(0, 1, 2).execute(machineState, stateManager);

const expected = new Fr(0b00111111100100111001n);
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

it('Should shift correctly 19 positions over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(19n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Shr(0, 1, 2).execute(machineState, stateManager);

const expected = new Fr(0b01n);
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});
});

describe('SHL', () => {
it('Should shift correctly 0 positions over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(0n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Shl(0, 1, 2).execute(machineState, stateManager);

const expected = a;
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

it('Should shift correctly 2 positions over Fr type', () => {
const a = new Fr(0b11111110010011100100n);
const b = new Fr(2n);

machineState.writeMemory(0, a);
machineState.writeMemory(1, b);

new Shl(0, 1, 2).execute(machineState, stateManager);

const expected = new Fr(0b1111111001001110010000n);
const actual = machineState.readMemory(2);
expect(actual).toEqual(expected);
});

// it('Should shift correctly over bit limit over Fr type', () => {
// const a = new Fr(0b11111110010011100100n);
// const b = new Fr(19n);

// machineState.writeMemory(0, a);
// machineState.writeMemory(1, b);

// new Shl(0, 1, 2).execute(machineState, stateManager);

// const expected = new Fr(0b01n);
// const actual = machineState.readMemory(2);
// expect(actual).toEqual(expected);
// });
});

// it('Should NOT correctly over Fr type', () => {
// const a = new Fr(0b11111110010011100100n);

// machineState.writeMemory(0, a);

// new Not(0, 1).execute(machineState, stateManager);

// const expected = new Fr(0b00000001101100011011n); // high bits!
// const actual = machineState.readMemory(1);
// expect(actual).toEqual(expected);
// });
});
3 changes: 3 additions & 0 deletions yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export class Shr extends Instruction {
const a: Fr = machineState.readMemory(this.aOffset);
const b: Fr = machineState.readMemory(this.bOffset);

// Here we are assuming that the field element maps to a positive number.
// The >> operator is *signed* in JS (and it sign extends).
// E.g.: -1n >> 3n == -1n.
const dest = new Fr(a.toBigInt() >> b.toBigInt());
machineState.writeMemory(this.destOffset, dest);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Add, Mul, Sub } from './arithmetic.js';
import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js';
import { Eq, Lt, Lte } from './comparators.js';
import { InternalCall, InternalCallStackEmptyError, InternalReturn, Jump, JumpI } from './control_flow.js';
import { CalldataCopy, Cast, Mov, Set } from './memory.js';
import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js';

describe('Control Flow Opcodes', () => {
let stateManager = mock<AvmStateManager>();
Expand Down Expand Up @@ -132,6 +132,7 @@ describe('Control Flow Opcodes', () => {
new CalldataCopy(0, 1, 2),
new Set(0n, 1),
new Mov(0, 1),
new CMov(0, 1, 2, 3),
new Cast(0, 1),
];

Expand Down
27 changes: 12 additions & 15 deletions yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Add, Div, Mul, Sub } from './arithmetic.js';
//import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js';
import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js';
//import { Eq, Lt, Lte } from './comparators.js';
import { InternalCall, InternalReturn, Jump, JumpI, Return } from './control_flow.js';
import { Instruction } from './instruction.js';
import {
CalldataCopy,
/*Cast, Mov*/
} from './memory.js';
import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js';
import { Opcode } from './opcodes.js';

/** - */
Expand All @@ -30,14 +27,14 @@ export const INSTRUCTION_SET: Map<Opcode, InstructionConstructorAndMembers> = ne
//[Opcode.LT, Lt],
//[Opcode.LTE, Lte],
//// Compute - Bitwise
//[Opcode.AND, And],
//[Opcode.OR, Or],
//[Opcode.XOR, Xor],
//[Opcode.NOT, Not],
//[Opcode.SHL, Shl],
//[Opcode.SHR, Shr],
[Opcode.AND, And],
[Opcode.OR, Or],
[Opcode.XOR, Xor],
[Opcode.NOT, Not],
[Opcode.SHL, Shl],
[Opcode.SHR, Shr],
//// Compute - Type Conversions
//[Opcode.CAST, Cast],
[Opcode.CAST, Cast],

//// Execution Environment
//[Opcode.ADDRESS, Address],
Expand Down Expand Up @@ -72,9 +69,9 @@ export const INSTRUCTION_SET: Map<Opcode, InstructionConstructorAndMembers> = ne
[Opcode.INTERNALCALL, InternalCall],
[Opcode.INTERNALRETURN, InternalReturn],
//// Machine State - Memory
//[Opcode.SET, Set],
//[Opcode.MOV, Mov],
//[Opcode.CMOV, CMov],
[Opcode.SET, Set],
[Opcode.MOV, Mov],
[Opcode.CMOV, CMov],

//// World State
//[Opcode.BLOCKHEADERBYNUMBER, Blockheaderbynumber],
Expand Down
Loading

0 comments on commit 6dac650

Please sign in to comment.