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): implement comparator opcodes (AztecProtocol#4232)
- Added `lt` and `equals` to AVM's memory types - Implemented `eq`, `lt`, `lte` opcodes to work with integral types, fields, and inTag checking - Added tests Refers to AztecProtocol#4120.
- Loading branch information
Showing
4 changed files
with
190 additions
and
13 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
147 changes: 147 additions & 0 deletions
147
yarn-project/acir-simulator/src/avm/opcodes/comparators.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,147 @@ | ||
import { MockProxy, mock } from 'jest-mock-extended'; | ||
|
||
import { AvmMachineState } from '../avm_machine_state.js'; | ||
import { Field, TypeTag, Uint16, Uint32 } from '../avm_memory_types.js'; | ||
import { initExecutionEnvironment } from '../fixtures/index.js'; | ||
import { AvmJournal } from '../journal/journal.js'; | ||
import { Eq, Lt, Lte } from './comparators.js'; | ||
import { InstructionExecutionError } from './instruction.js'; | ||
|
||
describe('Comparators', () => { | ||
let machineState: AvmMachineState; | ||
let journal: MockProxy<AvmJournal>; | ||
|
||
beforeEach(async () => { | ||
machineState = new AvmMachineState(initExecutionEnvironment()); | ||
journal = mock<AvmJournal>(); | ||
}); | ||
|
||
describe('Eq', () => { | ||
it('Works on integral types', async () => { | ||
machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(3), new Uint32(1)]); | ||
|
||
[ | ||
new Eq(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
new Eq(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 11), | ||
new Eq(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 3, /*dstOffset=*/ 12), | ||
].forEach(i => i.execute(machineState, journal)); | ||
|
||
const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); | ||
expect(actual).toEqual([new Uint32(0), new Uint32(0), new Uint32(1)]); | ||
}); | ||
|
||
it('Works on field elements', async () => { | ||
machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(3), new Field(1)]); | ||
|
||
[ | ||
new Eq(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
new Eq(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 11), | ||
new Eq(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 3, /*dstOffset=*/ 12), | ||
].forEach(i => i.execute(machineState, journal)); | ||
|
||
const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); | ||
expect(actual).toEqual([new Field(0), new Field(0), new Field(1)]); | ||
}); | ||
|
||
it('InTag is checked', async () => { | ||
machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); | ||
|
||
const ops = [ | ||
new Eq(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
new Eq(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 10), | ||
new Eq(TypeTag.UINT16, /*aOffset=*/ 1, /*bOffset=*/ 2, /*dstOffset=*/ 10), | ||
new Eq(TypeTag.UINT16, /*aOffset=*/ 1, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
]; | ||
|
||
for (const o of ops) { | ||
await expect(() => o.execute(machineState, journal)).rejects.toThrow(InstructionExecutionError); | ||
} | ||
}); | ||
}); | ||
|
||
describe('Lt', () => { | ||
it('Works on integral types', async () => { | ||
machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(0)]); | ||
|
||
[ | ||
new Lt(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), | ||
new Lt(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), | ||
new Lt(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), | ||
].forEach(i => i.execute(machineState, journal)); | ||
|
||
const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); | ||
expect(actual).toEqual([new Uint32(0), new Uint32(1), new Uint32(0)]); | ||
}); | ||
|
||
it('Works on field elements', async () => { | ||
machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(0)]); | ||
|
||
[ | ||
new Lt(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), | ||
new Lt(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), | ||
new Lt(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), | ||
].forEach(i => i.execute(machineState, journal)); | ||
|
||
const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); | ||
expect(actual).toEqual([new Field(0), new Field(1), new Field(0)]); | ||
}); | ||
|
||
it('InTag is checked', async () => { | ||
machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); | ||
|
||
const ops = [ | ||
new Lt(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
new Lt(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 10), | ||
new Lt(TypeTag.UINT16, /*aOffset=*/ 1, /*bOffset=*/ 2, /*dstOffset=*/ 10), | ||
new Lt(TypeTag.UINT16, /*aOffset=*/ 1, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
]; | ||
|
||
for (const o of ops) { | ||
await expect(() => o.execute(machineState, journal)).rejects.toThrow(InstructionExecutionError); | ||
} | ||
}); | ||
}); | ||
|
||
describe('Lte', () => { | ||
it('Works on integral types', async () => { | ||
machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(0)]); | ||
|
||
[ | ||
new Lte(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), | ||
new Lte(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), | ||
new Lte(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), | ||
].forEach(i => i.execute(machineState, journal)); | ||
|
||
const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); | ||
expect(actual).toEqual([new Uint32(1), new Uint32(1), new Uint32(0)]); | ||
}); | ||
|
||
it('Works on field elements', async () => { | ||
machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(0)]); | ||
|
||
[ | ||
new Lte(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), | ||
new Lte(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), | ||
new Lte(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), | ||
].forEach(i => i.execute(machineState, journal)); | ||
|
||
const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); | ||
expect(actual).toEqual([new Field(1), new Field(1), new Field(0)]); | ||
}); | ||
|
||
it('InTag is checked', async () => { | ||
machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); | ||
|
||
const ops = [ | ||
new Lte(TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
new Lte(TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 10), | ||
new Lte(TypeTag.UINT16, /*aOffset=*/ 1, /*bOffset=*/ 2, /*dstOffset=*/ 10), | ||
new Lte(TypeTag.UINT16, /*aOffset=*/ 1, /*bOffset=*/ 1, /*dstOffset=*/ 10), | ||
]; | ||
|
||
for (const o of ops) { | ||
await expect(() => o.execute(machineState, journal)).rejects.toThrow(InstructionExecutionError); | ||
} | ||
}); | ||
}); | ||
}); |
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