From 8d06d9e7a0365dadad4a1cd7ca8049c2140f1cdd Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 19:24:32 +0000 Subject: [PATCH 01/14] feat(avm): better field arithmetic --- barretenberg/ts/src/types/fields.ts | 1 + yarn-project/foundation/src/fields/fields.ts | 44 ++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/barretenberg/ts/src/types/fields.ts b/barretenberg/ts/src/types/fields.ts index a54cbe5a3289..52c61c99ad10 100644 --- a/barretenberg/ts/src/types/fields.ts +++ b/barretenberg/ts/src/types/fields.ts @@ -54,6 +54,7 @@ export class Fr { isZero() { return this.value.every(v => v === 0); } + } export class Fq { diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 90600643cfe5..1a51c64d041e 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -192,8 +192,31 @@ export class Fr extends BaseField { static fromString(buf: string) { return fromString(buf, Fr); } + + add(rhs: Fr) { + return new Fr((this.toBigInt() + rhs.toBigInt()) % Fr.MODULUS); + } + + sub(rhs: Fr) { + const result = this.toBigInt() - rhs.toBigInt(); + return new Fr((result < 0) ? result + Fr.MODULUS : result); + } + + mul(rhs: Fr) { + return new Fr((this.toBigInt() * rhs.toBigInt()) % Fr.MODULUS); + } + + div(rhs: Fr) { + if (rhs.isZero()) { + throw new Error('Division by zero'); + } + + const bInv = modInverse(rhs.toBigInt()); + return new Fr((this.toBigInt() * bInv) % Fr.MODULUS); + } } + /** * Branding to ensure fields are not interchangeable types. */ @@ -252,6 +275,26 @@ export class Fq extends BaseField { } } +// Performance bottleneck +// TODO: add documentation +function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] { + if (a == 0n){ + return [modulus, 0n, 1n] + } + else{ + const [gcd, x, y]: [bigint, bigint, bigint] = extendedEuclidean(modulus % a, a) + return [gcd, y - (modulus / a) * x, x] + } +} + +function modInverse(b: bigint){ + const [gcd, x, _] = extendedEuclidean(b, Fr.MODULUS); + if (gcd != 1n){ + throw Error("Inverse does not exist"); + } + return x % Fr.MODULUS; +} + /** * GrumpkinScalar is an Fq. * @remarks Called GrumpkinScalar because it is used to represent elements in Grumpkin's scalar field as defined in @@ -259,3 +302,4 @@ export class Fq extends BaseField { */ export type GrumpkinScalar = Fq; export const GrumpkinScalar = Fq; + From 2c471d39468c9e108b289f438f7ec9dbb3dc74c4 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:14:18 +0000 Subject: [PATCH 02/14] chore: test field division --- barretenberg/ts/src/types/fields.ts | 2 + .../src/avm/opcodes/arithmetic.test.ts | 110 ++++++++++++++++++ .../src/avm/opcodes/arithmetic.ts | 9 +- .../acir-simulator/src/avm/opcodes/bitwise.ts | 4 +- yarn-project/foundation/src/fields/fields.ts | 11 +- 5 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts diff --git a/barretenberg/ts/src/types/fields.ts b/barretenberg/ts/src/types/fields.ts index 52c61c99ad10..a17b8e0b2ef6 100644 --- a/barretenberg/ts/src/types/fields.ts +++ b/barretenberg/ts/src/types/fields.ts @@ -55,6 +55,8 @@ export class Fr { return this.value.every(v => v === 0); } + + } export class Fq { diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts new file mode 100644 index 000000000000..9cda39873bef --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -0,0 +1,110 @@ +import { AvmMachineState } from "../avm_machine_state.js"; +import { Add, Div, Mul, Sub } from "./arithmetic.js"; +import { AvmStateManager } from "../avm_state_manager.js"; +import { mock } from "jest-mock-extended"; +import { Fr } from "@aztec/foundation/fields"; + +describe("Arithmetic Instructions", () => { + let machineState: AvmMachineState; + let stateManager = mock(); + + beforeEach(() => { + machineState = new AvmMachineState([]); + stateManager = mock(); + }) + + describe("Add", () => { + it("Should add correctly over Fr type", () => { + const a = new Fr(1n); + const b = new Fr(2n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new Add(0, 1, 2).execute(machineState, stateManager); + + const expected = new Fr(3n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); + }) + + it("Should wrap around on addition", () => { + const a = new Fr(1n); + const b = new Fr(Fr.MODULUS - 1n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new Add(0, 1, 2).execute(machineState, stateManager); + + const expected = new Fr(0n); + const actual = machineState.readMemory(3); + expect(actual).toEqual(expected); + }) + }) + + describe("Sub", () => { + it("Should subtract correctly over Fr type", () => { + const a = new Fr(1n); + const b = new Fr(2n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new Sub(0, 1, 2).execute(machineState, stateManager); + + const expected = new Fr(Fr.MODULUS - 1n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); + }); + }); + + describe("Mul", () => { + it("Should multiply correctly over Fr type", () => { + const a = new Fr(2n); + const b = new Fr(3n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new Mul(0, 1, 2).execute(machineState, stateManager); + + const expected = new Fr(6n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); + }); + + it("Should wrap around on multiplication", () => { + const a = new Fr(2n); + const b = new Fr((Fr.MODULUS / 2n) - 1n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new Mul(0, 1, 2).execute(machineState, stateManager); + + const expected = new Fr(Fr.MODULUS - 3n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); + }); + }); + + describe("Div", () => { + it("Should perform field division", () => { + const a = new Fr(2n); + const b = new Fr(3n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new Div(0, 1, 2).execute(machineState, stateManager); + + // Note + const actual = machineState.readMemory(2); + const recovered = actual.mul(b); + expect(recovered).toEqual(a); + }) + + }); + +}) \ No newline at end of file diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts index 7f2fb3db052c..4f9649624c8f 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts @@ -17,7 +17,7 @@ export class Add extends Instruction { const a = machineState.readMemory(this.aOffset); const b = machineState.readMemory(this.bOffset); - const dest = new Fr((a.toBigInt() + b.toBigInt()) % Fr.MODULUS); + const dest = a.add(b); machineState.writeMemory(this.destOffset, dest); this.incrementPc(machineState); @@ -37,7 +37,7 @@ export class Sub extends Instruction { const a = machineState.readMemory(this.aOffset); const b = machineState.readMemory(this.bOffset); - const dest = new Fr((a.toBigInt() - b.toBigInt()) % Fr.MODULUS); + const dest = a.sub(b); machineState.writeMemory(this.destOffset, dest); this.incrementPc(machineState); @@ -57,7 +57,7 @@ export class Mul extends Instruction { const a: Fr = machineState.readMemory(this.aOffset); const b: Fr = machineState.readMemory(this.bOffset); - const dest = new Fr((a.toBigInt() * b.toBigInt()) % Fr.MODULUS); + const dest = a.mul(b); machineState.writeMemory(this.destOffset, dest); this.incrementPc(machineState); @@ -77,8 +77,7 @@ export class Div extends Instruction { const a: Fr = machineState.readMemory(this.aOffset); const b: Fr = machineState.readMemory(this.bOffset); - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3993): proper field division - const dest = new Fr(a.toBigInt() / b.toBigInt()); + const dest = a.div(b) machineState.writeMemory(this.destOffset, dest); this.incrementPc(machineState); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts index bc5c3a211cb6..4950c771f7c6 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts @@ -76,8 +76,10 @@ export class Not extends Instruction { execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { const a: Fr = machineState.readMemory(this.aOffset); - // TODO: hack -> until proper field arithmetic is implemented + // TODO: hack -> Bitwise operations should not occur over field elements + // It should only work over integers const result = ~a.toBigInt(); + const dest = new Fr(result < 0 ? Fr.MODULUS + /* using a + as result is -ve*/ result : result); machineState.writeMemory(this.destOffset, dest); diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 1a51c64d041e..d7a919e89c23 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -193,6 +193,8 @@ export class Fr extends BaseField { return fromString(buf, Fr); } + /** Arithmetic */ + add(rhs: Fr) { return new Fr((this.toBigInt() + rhs.toBigInt()) % Fr.MODULUS); } @@ -212,7 +214,7 @@ export class Fr extends BaseField { } const bInv = modInverse(rhs.toBigInt()); - return new Fr((this.toBigInt() * bInv) % Fr.MODULUS); + return this.mul(bInv); } } @@ -282,8 +284,8 @@ function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] return [modulus, 0n, 1n] } else{ - const [gcd, x, y]: [bigint, bigint, bigint] = extendedEuclidean(modulus % a, a) - return [gcd, y - (modulus / a) * x, x] + const [gcd, x, y] = extendedEuclidean(modulus % a, a) + return [gcd, y - ((modulus / a) * x), x] } } @@ -292,7 +294,8 @@ function modInverse(b: bigint){ if (gcd != 1n){ throw Error("Inverse does not exist"); } - return x % Fr.MODULUS; + // Add modulus to ensure positive + return new Fr(x + Fr.MODULUS); } /** From 688530a6112d5e32625683730d4ddb643c2b500c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:16:13 +0000 Subject: [PATCH 03/14] chore: add div to opcodes list --- .../src/avm/opcodes/arithmetic.test.ts | 162 +++++++++--------- .../src/avm/opcodes/arithmetic.ts | 2 +- .../src/avm/opcodes/instruction_set.ts | 3 +- yarn-project/foundation/src/fields/fields.ts | 31 ++-- 4 files changed, 98 insertions(+), 100 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts index 9cda39873bef..76a802231a3b 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -1,110 +1,110 @@ -import { AvmMachineState } from "../avm_machine_state.js"; -import { Add, Div, Mul, Sub } from "./arithmetic.js"; -import { AvmStateManager } from "../avm_state_manager.js"; -import { mock } from "jest-mock-extended"; -import { Fr } from "@aztec/foundation/fields"; +import { Fr } from '@aztec/foundation/fields'; -describe("Arithmetic Instructions", () => { - let machineState: AvmMachineState; - let stateManager = mock(); +import { mock } from 'jest-mock-extended'; - beforeEach(() => { - machineState = new AvmMachineState([]); - stateManager = mock(); - }) +import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmStateManager } from '../avm_state_manager.js'; +import { Add, Div, Mul, Sub } from './arithmetic.js'; - describe("Add", () => { - it("Should add correctly over Fr type", () => { - const a = new Fr(1n); - const b = new Fr(2n); +describe('Arithmetic Instructions', () => { + let machineState: AvmMachineState; + let stateManager = mock(); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + beforeEach(() => { + machineState = new AvmMachineState([]); + stateManager = mock(); + }); - new Add(0, 1, 2).execute(machineState, stateManager); + describe('Add', () => { + it('Should add correctly over Fr type', () => { + const a = new Fr(1n); + const b = new Fr(2n); - const expected = new Fr(3n); - const actual = machineState.readMemory(2); - expect(actual).toEqual(expected); - }) + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); - it("Should wrap around on addition", () => { - const a = new Fr(1n); - const b = new Fr(Fr.MODULUS - 1n); + new Add(0, 1, 2).execute(machineState, stateManager); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + const expected = new Fr(3n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); + }); + + it('Should wrap around on addition', () => { + const a = new Fr(1n); + const b = new Fr(Fr.MODULUS - 1n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); - new Add(0, 1, 2).execute(machineState, stateManager); + new Add(0, 1, 2).execute(machineState, stateManager); - const expected = new Fr(0n); - const actual = machineState.readMemory(3); - expect(actual).toEqual(expected); - }) - }) + const expected = new Fr(0n); + const actual = machineState.readMemory(3); + expect(actual).toEqual(expected); + }); + }); - describe("Sub", () => { - it("Should subtract correctly over Fr type", () => { - const a = new Fr(1n); - const b = new Fr(2n); + describe('Sub', () => { + it('Should subtract correctly over Fr type', () => { + const a = new Fr(1n); + const b = new Fr(2n); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); - new Sub(0, 1, 2).execute(machineState, stateManager); + new Sub(0, 1, 2).execute(machineState, stateManager); - const expected = new Fr(Fr.MODULUS - 1n); - const actual = machineState.readMemory(2); - expect(actual).toEqual(expected); - }); + const expected = new Fr(Fr.MODULUS - 1n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); }); + }); - describe("Mul", () => { - it("Should multiply correctly over Fr type", () => { - const a = new Fr(2n); - const b = new Fr(3n); + describe('Mul', () => { + it('Should multiply correctly over Fr type', () => { + const a = new Fr(2n); + const b = new Fr(3n); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); - new Mul(0, 1, 2).execute(machineState, stateManager); + new Mul(0, 1, 2).execute(machineState, stateManager); - const expected = new Fr(6n); - const actual = machineState.readMemory(2); - expect(actual).toEqual(expected); - }); + const expected = new Fr(6n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); + }); - it("Should wrap around on multiplication", () => { - const a = new Fr(2n); - const b = new Fr((Fr.MODULUS / 2n) - 1n); + it('Should wrap around on multiplication', () => { + const a = new Fr(2n); + const b = new Fr(Fr.MODULUS / 2n - 1n); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); - new Mul(0, 1, 2).execute(machineState, stateManager); + new Mul(0, 1, 2).execute(machineState, stateManager); - const expected = new Fr(Fr.MODULUS - 3n); - const actual = machineState.readMemory(2); - expect(actual).toEqual(expected); - }); + const expected = new Fr(Fr.MODULUS - 3n); + const actual = machineState.readMemory(2); + expect(actual).toEqual(expected); }); + }); - describe("Div", () => { - it("Should perform field division", () => { - const a = new Fr(2n); - const b = new Fr(3n); - - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + describe('Div', () => { + it('Should perform field division', () => { + const a = new Fr(2n); + const b = new Fr(3n); - new Div(0, 1, 2).execute(machineState, stateManager); + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); - // Note - const actual = machineState.readMemory(2); - const recovered = actual.mul(b); - expect(recovered).toEqual(a); - }) + new Div(0, 1, 2).execute(machineState, stateManager); + // Note + const actual = machineState.readMemory(2); + const recovered = actual.mul(b); + expect(recovered).toEqual(a); }); - -}) \ No newline at end of file + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts index 4f9649624c8f..94df9713c83c 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts @@ -77,7 +77,7 @@ export class Div extends Instruction { const a: Fr = machineState.readMemory(this.aOffset); const b: Fr = machineState.readMemory(this.bOffset); - const dest = a.div(b) + const dest = a.div(b); machineState.writeMemory(this.destOffset, dest); this.incrementPc(machineState); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts index 1211205b979d..b36c5d34d297 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts @@ -1,5 +1,6 @@ import { Add, + Div, /*Div,*/ Mul, Sub, @@ -29,7 +30,7 @@ export const INSTRUCTION_SET: Map = ne [Opcode.ADD, Add], [Opcode.SUB, Sub], [Opcode.MUL, Mul], - //[Opcode.DIV, Div], + [Opcode.DIV, Div], //// Compute - Comparators //[Opcode.EQ, Eq], //[Opcode.LT, Lt], diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index d7a919e89c23..899ff03002b3 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -201,7 +201,7 @@ export class Fr extends BaseField { sub(rhs: Fr) { const result = this.toBigInt() - rhs.toBigInt(); - return new Fr((result < 0) ? result + Fr.MODULUS : result); + return new Fr(result < 0 ? result + Fr.MODULUS : result); } mul(rhs: Fr) { @@ -218,7 +218,6 @@ export class Fr extends BaseField { } } - /** * Branding to ensure fields are not interchangeable types. */ @@ -280,22 +279,21 @@ export class Fq extends BaseField { // Performance bottleneck // TODO: add documentation function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] { - if (a == 0n){ - return [modulus, 0n, 1n] - } - else{ - const [gcd, x, y] = extendedEuclidean(modulus % a, a) - return [gcd, y - ((modulus / a) * x), x] - } + if (a == 0n) { + return [modulus, 0n, 1n]; + } else { + const [gcd, x, y] = extendedEuclidean(modulus % a, a); + return [gcd, y - (modulus / a) * x, x]; + } } -function modInverse(b: bigint){ - const [gcd, x, _] = extendedEuclidean(b, Fr.MODULUS); - if (gcd != 1n){ - throw Error("Inverse does not exist"); - } - // Add modulus to ensure positive - return new Fr(x + Fr.MODULUS); +function modInverse(b: bigint) { + const [gcd, x, _] = extendedEuclidean(b, Fr.MODULUS); + if (gcd != 1n) { + throw Error('Inverse does not exist'); + } + // Add modulus to ensure positive + return new Fr(x + Fr.MODULUS); } /** @@ -305,4 +303,3 @@ function modInverse(b: bigint){ */ export type GrumpkinScalar = Fq; export const GrumpkinScalar = Fq; - From 8eb1ad7c62e18a679f2104ddc19e61ba9c8ac9a2 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:20:39 +0000 Subject: [PATCH 04/14] fix: lint bb --- barretenberg/ts/src/types/fields.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/barretenberg/ts/src/types/fields.ts b/barretenberg/ts/src/types/fields.ts index a17b8e0b2ef6..a54cbe5a3289 100644 --- a/barretenberg/ts/src/types/fields.ts +++ b/barretenberg/ts/src/types/fields.ts @@ -54,9 +54,6 @@ export class Fr { isZero() { return this.value.every(v => v === 0); } - - - } export class Fq { From d9b77475b4de9967138b82cbeffa23357ac51d26 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:23:12 +0000 Subject: [PATCH 05/14] chore: Add comments to mod inverse method --- yarn-project/foundation/src/fields/fields.ts | 28 +++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 899ff03002b3..4435366d80bd 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -276,17 +276,11 @@ export class Fq extends BaseField { } } -// Performance bottleneck -// TODO: add documentation -function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] { - if (a == 0n) { - return [modulus, 0n, 1n]; - } else { - const [gcd, x, y] = extendedEuclidean(modulus % a, a); - return [gcd, y - (modulus / a) * x, x]; - } -} +// Beware: Performance bottleneck below +/** + * Find the modular inverse of a given element, for BN254 Fr. + */ function modInverse(b: bigint) { const [gcd, x, _] = extendedEuclidean(b, Fr.MODULUS); if (gcd != 1n) { @@ -296,6 +290,20 @@ function modInverse(b: bigint) { return new Fr(x + Fr.MODULUS); } +/** + * The extended Euclidean algorithm can be used to find the multiplicative inverse of a field element + * This is used to perform field division. + */ +function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] { + if (a == 0n) { + return [modulus, 0n, 1n]; + } else { + const [gcd, x, y] = extendedEuclidean(modulus % a, a); + return [gcd, y - (modulus / a) * x, x]; + } +} + + /** * GrumpkinScalar is an Fq. * @remarks Called GrumpkinScalar because it is used to represent elements in Grumpkin's scalar field as defined in From 8550753aa615f7b112fd0eba5b850d617977f729 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:24:42 +0000 Subject: [PATCH 06/14] chore: remove commented import --- yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts index b36c5d34d297..102fc24b96b4 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts @@ -1,7 +1,6 @@ import { Add, Div, - /*Div,*/ Mul, Sub, } from './arithmetic.js'; From e66d6495423c009b665717893e0581ca0c3db1e8 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:05:41 +0000 Subject: [PATCH 07/14] fix: fmr --- .../acir-simulator/src/avm/opcodes/instruction_set.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts index 102fc24b96b4..4395ba46d534 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts @@ -1,9 +1,4 @@ -import { - Add, - Div, - Mul, - Sub, -} from './arithmetic.js'; +import { Add, Div, Mul, Sub } from './arithmetic.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'; From b40f42c5d3235cd3fede2665d31d27515fe6fed6 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 19 Jan 2024 09:40:45 +0000 Subject: [PATCH 08/14] fix: fmt --- yarn-project/foundation/src/fields/fields.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 4435366d80bd..bbf2f3b9a20c 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -278,7 +278,7 @@ export class Fq extends BaseField { // Beware: Performance bottleneck below -/** +/** * Find the modular inverse of a given element, for BN254 Fr. */ function modInverse(b: bigint) { @@ -303,7 +303,6 @@ function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] } } - /** * GrumpkinScalar is an Fq. * @remarks Called GrumpkinScalar because it is used to represent elements in Grumpkin's scalar field as defined in From 17a200535f62a1fd9a19e8913196298f5edbac7a Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:03:11 +0000 Subject: [PATCH 09/14] feat(avm): link up storage --- .../acir-simulator/src/avm/avm_context.ts | 12 +++-- .../src/avm/avm_execution_environment.ts | 52 ++++++++++++++++++ .../src/avm/avm_machine_state.ts | 13 ++++- .../src/avm/avm_state_manager.ts | 22 +++++++- .../acir-simulator/src/avm/fixtures/index.ts | 39 ++++++++++++++ .../acir-simulator/src/avm/index.test.ts | 4 +- .../src/avm/interpreter/interpreter.test.ts | 15 ++++-- .../src/avm/opcodes/arithmetic.test.ts | 7 +-- .../src/avm/opcodes/control_flow.test.ts | 9 ++-- .../src/avm/opcodes/storage.test.ts | 53 +++++++++++++++++++ .../acir-simulator/src/avm/opcodes/storage.ts | 42 +++++++++++++++ yellow-paper/docs/public-vm/avm.md | 2 +- 12 files changed, 249 insertions(+), 21 deletions(-) create mode 100644 yarn-project/acir-simulator/src/avm/avm_execution_environment.ts create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/storage.ts diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts index 79e763f79f45..855d03338522 100644 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ b/yarn-project/acir-simulator/src/avm/avm_context.ts @@ -1,5 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; +import { ExecutionEnvironment } from './avm_execution_environment.js'; import { AvmMachineState } from './avm_machine_state.js'; import { AvmMessageCallResult } from './avm_message_call_result.js'; import { AvmStateManager } from './avm_state_manager.js'; @@ -14,9 +15,11 @@ import { Instruction } from './opcodes/index.js'; */ export class AvmContext { private stateManager: AvmStateManager; + private executionEnvironment: ExecutionEnvironment; - constructor(stateManager: AvmStateManager) { + constructor(executionEnvironment: ExecutionEnvironment, stateManager: AvmStateManager) { this.stateManager = stateManager; + this.executionEnvironment = executionEnvironment; } /** @@ -26,17 +29,16 @@ export class AvmContext { * - We interpret the bytecode * - We run the interpreter * - * @param contractAddress - * @param calldata - */ - public call(contractAddress: Fr, calldata: Fr[]): AvmMessageCallResult { + public call(calldata: Fr[]): AvmMessageCallResult { // NOTE: the following is mocked as getPublicBytecode does not exist yet - // const bytecode = stateManager.journal.hostStorage.contractsDb.getBytecode(contractAddress); + // const bytecode = stateManager.journal.hostStorage.contractsDb.getBytecode(this.executionEnvironment.address); const bytecode = Buffer.from('0x01000100020003'); const instructions: Instruction[] = decodeBytecode(bytecode); - const context = new AvmMachineState(calldata); + const context = new AvmMachineState(calldata, this.executionEnvironment); const interpreter = new AvmInterpreter(context, this.stateManager, instructions); return interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts b/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts new file mode 100644 index 000000000000..871c9bb5a098 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts @@ -0,0 +1,52 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; + +/** - */ +export class ExecutionEnvironment { + constructor( + /** - */ + public readonly address: AztecAddress, + /** - */ + public readonly storageAddress: AztecAddress, + /** - */ + public readonly origin: AztecAddress, + /** - */ + public readonly sender: AztecAddress, + /** - */ + public readonly portal: EthAddress, + /** - */ + public readonly feePerL1Gas: Fr, + /** - */ + public readonly feePerL2Gas: Fr, + /** - */ + public readonly feePerDaGas: Fr, + /** - */ + public readonly contractCallDepth: Fr, + /** - */ + // globals: TODO: + /** - */ + public readonly isStaticCall: boolean, + /** - */ + public readonly isDelegateCall: boolean, + /** - */ + public readonly calldata: Fr[], + ) {} + + static empty(): ExecutionEnvironment { + return new ExecutionEnvironment( + AztecAddress.zero(), + AztecAddress.zero(), + AztecAddress.zero(), + AztecAddress.zero(), + EthAddress.ZERO, + Fr.zero(), + Fr.zero(), + Fr.zero(), + Fr.zero(), + false, + false, + [], + ); + } +} diff --git a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts index 53e8599b7c37..b5a3f2997a59 100644 --- a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts +++ b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts @@ -1,9 +1,17 @@ import { Fr } from '@aztec/foundation/fields'; +import { ExecutionEnvironment } from './avm_execution_environment.js'; + /** * Store's data for an Avm execution frame */ export class AvmMachineState { + /** + * Execution environment contains hard coded information that is received from the kernel + * Items like, the block header and global variables fall within this category + */ + public readonly executionEnvironment: ExecutionEnvironment; + /** - */ public readonly calldata: Fr[]; private returnData: Fr[]; @@ -31,8 +39,9 @@ export class AvmMachineState { /** * Create a new avm context * @param calldata - + * @param executionEnvironment - Machine context that is passed to the avm */ - constructor(calldata: Fr[]) { + constructor(calldata: Fr[], executionEnvironment: ExecutionEnvironment) { this.calldata = calldata; this.returnData = []; this.memory = []; @@ -42,6 +51,8 @@ export class AvmMachineState { this.callStack = []; this.halted = false; + + this.executionEnvironment = executionEnvironment; } /** diff --git a/yarn-project/acir-simulator/src/avm/avm_state_manager.ts b/yarn-project/acir-simulator/src/avm/avm_state_manager.ts index b5396accc7a9..d75c25c72a1f 100644 --- a/yarn-project/acir-simulator/src/avm/avm_state_manager.ts +++ b/yarn-project/acir-simulator/src/avm/avm_state_manager.ts @@ -1,4 +1,5 @@ -import { BlockHeader } from '@aztec/circuits.js'; +import { AztecAddress, BlockHeader } from '@aztec/circuits.js'; +import { Fr } from '@aztec/foundation/fields'; import { AvmJournal, HostStorage } from './journal/index.js'; @@ -42,4 +43,23 @@ export class AvmStateManager { const journal = AvmJournal.branchParent(parent.journal); return new AvmStateManager(parent.blockHeader, journal); } + + /** + * Passes storage call to the journal + * @param contractAddress - + * @param slot - + * @param value - + */ + public store(contractAddress: AztecAddress, slot: Fr, value: Fr): void { + this.journal.writeStorage(contractAddress, slot, value); + } + + /** + * Passes storage read from the journal + * @param contractAddress - + * @param slot - + */ + public read(contractAddress: AztecAddress, slot: Fr): Promise { + return this.journal.readStorage(contractAddress, slot); + } } diff --git a/yarn-project/acir-simulator/src/avm/fixtures/index.ts b/yarn-project/acir-simulator/src/avm/fixtures/index.ts index cfab7bc47b8f..d0d821875700 100644 --- a/yarn-project/acir-simulator/src/avm/fixtures/index.ts +++ b/yarn-project/acir-simulator/src/avm/fixtures/index.ts @@ -1 +1,40 @@ // Place large AVM text fixtures in here +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; + +import { ExecutionEnvironment } from '../avm_execution_environment.js'; + +export const initExecutionEnvironmentEmpty = (): ExecutionEnvironment => { + return new ExecutionEnvironment( + AztecAddress.zero(), + AztecAddress.zero(), + AztecAddress.zero(), + AztecAddress.zero(), + EthAddress.ZERO, + Fr.zero(), + Fr.zero(), + Fr.zero(), + Fr.zero(), + false, + false, + [], + ); +}; + +export const initExecutionEnvironment = (contractAddress: AztecAddress): ExecutionEnvironment => { + return new ExecutionEnvironment( + contractAddress, + contractAddress, + AztecAddress.zero(), + AztecAddress.zero(), + EthAddress.ZERO, + Fr.zero(), + Fr.zero(), + Fr.zero(), + Fr.zero(), + false, + false, + [], + ); +}; diff --git a/yarn-project/acir-simulator/src/avm/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts index 1db8306447af..9ab9845b28bf 100644 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ b/yarn-project/acir-simulator/src/avm/index.test.ts @@ -4,6 +4,7 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from './avm_machine_state.js'; import { AvmStateManager } from './avm_state_manager.js'; +import { initExecutionEnvironmentEmpty } from './fixtures/index.js'; import { AvmInterpreter } from './interpreter/interpreter.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { encodeToBytecode } from './opcodes/encode_to_bytecode.js'; @@ -28,7 +29,8 @@ describe('avm', () => { const instructions = decodeBytecode(fullBytecode); // Execute instructions - const context = new AvmMachineState(calldata); + const executionEnvironment = initExecutionEnvironmentEmpty(); + const context = new AvmMachineState(calldata, executionEnvironment); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts index a52a2c13222e..e5bb9fb6dd25 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -1,9 +1,10 @@ import { Fr } from '@aztec/foundation/fields'; -import { mock } from 'jest-mock-extended'; +import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; +import { initExecutionEnvironmentEmpty } from '../fixtures/index.js'; import { Add } from '../opcodes/arithmetic.js'; import { Jump, Return } from '../opcodes/control_flow.js'; import { Instruction } from '../opcodes/instruction.js'; @@ -11,9 +12,14 @@ import { CalldataCopy } from '../opcodes/memory.js'; import { AvmInterpreter } from './interpreter.js'; describe('interpreter', () => { + let stateManager: MockProxy; + + beforeEach(() => { + stateManager = mock(); + }); + it('Should execute a series of instructions', () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const stateManager = mock(); const instructions: Instruction[] = [ // Copy the first two elements of the calldata to memory regions 0 and 1 @@ -24,7 +30,7 @@ describe('interpreter', () => { new Return(2, 1), // [3] ]; - const context = new AvmMachineState(calldata); + const context = new AvmMachineState(calldata, initExecutionEnvironmentEmpty()); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); @@ -37,13 +43,12 @@ describe('interpreter', () => { it('Should revert with an invalid jump', () => { const calldata: Fr[] = []; - const stateManager = mock(); const invalidJumpDestination = 22; const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; - const context = new AvmMachineState(calldata); + const context = new AvmMachineState(calldata, initExecutionEnvironmentEmpty()); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts index 76a802231a3b..f3448c8740b3 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -1,17 +1,18 @@ import { Fr } from '@aztec/foundation/fields'; -import { mock } from 'jest-mock-extended'; +import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; +import { initExecutionEnvironmentEmpty } from '../fixtures/index.js'; import { Add, Div, Mul, Sub } from './arithmetic.js'; describe('Arithmetic Instructions', () => { let machineState: AvmMachineState; - let stateManager = mock(); + let stateManager: MockProxy; beforeEach(() => { - machineState = new AvmMachineState([]); + machineState = new AvmMachineState([], initExecutionEnvironmentEmpty()); stateManager = mock(); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts index 864ee0d0b425..43f537b9f74a 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts @@ -1,9 +1,10 @@ import { Fr } from '@aztec/foundation/fields'; -import { mock } from 'jest-mock-extended'; +import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; +import { initExecutionEnvironmentEmpty } from '../fixtures/index.js'; import { Add, Mul, Sub } from './arithmetic.js'; import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; import { Eq, Lt, Lte } from './comparators.js'; @@ -11,12 +12,12 @@ import { InternalCall, InternalCallStackEmptyError, InternalReturn, Jump, JumpI import { CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Control Flow Opcodes', () => { - let stateManager = mock(); + let stateManager: MockProxy; let machineState: AvmMachineState; beforeEach(() => { stateManager = mock(); - machineState = new AvmMachineState([]); + machineState = new AvmMachineState([], initExecutionEnvironmentEmpty()); }); it('Should implement JUMP', () => { @@ -137,7 +138,7 @@ describe('Control Flow Opcodes', () => { for (const instruction of instructions) { // Use a fresh machine state each run - const innerMachineState = new AvmMachineState([]); + const innerMachineState = new AvmMachineState([], initExecutionEnvironmentEmpty()); expect(machineState.pc).toBe(0); instruction.execute(innerMachineState, stateManager); expect(innerMachineState.pc).toBe(1); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts new file mode 100644 index 000000000000..7f9f5fc07217 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -0,0 +1,53 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; + +import { MockProxy, mock } from 'jest-mock-extended'; + +import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmStateManager } from '../avm_state_manager.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; +import { SLoad, SStore } from './storage.js'; + +describe('Storage Instructions', () => { + let stateManager: MockProxy; + let machineState: AvmMachineState; + const contractAddress = AztecAddress.random(); + + beforeEach(() => { + stateManager = mock(); + + const executionEnvironment = initExecutionEnvironment(contractAddress); + machineState = new AvmMachineState([], executionEnvironment); + }); + + it('Sstore should Write into storage', () => { + const a = new Fr(1n); + const b = new Fr(2n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + new SStore(0, 1).execute(machineState, stateManager); + + expect(stateManager.store).toBeCalledWith(contractAddress, a, b); + }); + + it('Sload should Read into storage', async () => { + // Mock response + const expectedResult = new Fr(1n); + stateManager.read.mockReturnValueOnce(Promise.resolve(expectedResult)); + + const a = new Fr(1n); + const b = new Fr(2n); + + machineState.writeMemory(0, a); + machineState.writeMemory(1, b); + + await new SLoad(0, 1).execute(machineState, stateManager); + + expect(stateManager.read).toBeCalledWith(contractAddress, a); + + const actual = machineState.readMemory(1); + expect(actual).toEqual(expectedResult); + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts new file mode 100644 index 000000000000..c773600413a7 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts @@ -0,0 +1,42 @@ +import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmStateManager } from '../avm_state_manager.js'; +import { Instruction } from './instruction.js'; + +/** - */ +export class SStore extends Instruction { + static type: string = 'SSTORE'; + static numberOfOperands = 2; + + constructor(private slotOffset: number, private dataOffset: number) { + super(); + } + + execute(machineState: AvmMachineState, stateManager: AvmStateManager): void { + const slot = machineState.readMemory(this.slotOffset); + const data = machineState.readMemory(this.dataOffset); + + stateManager.store(machineState.executionEnvironment.storageAddress, slot, data); + + this.incrementPc(machineState); + } +} + +/** - */ +export class SLoad extends Instruction { + static type: string = 'SLOAD'; + static numberOfOperands = 2; + + constructor(private slotOffset: number, private destOffset: number) { + super(); + } + + async execute(machineState: AvmMachineState, stateManager: AvmStateManager): Promise { + const slot = machineState.readMemory(this.slotOffset); + + const data = stateManager.read(machineState.executionEnvironment.storageAddress, slot); + + machineState.writeMemory(this.destOffset, await data); + + this.incrementPc(machineState); + } +} diff --git a/yellow-paper/docs/public-vm/avm.md b/yellow-paper/docs/public-vm/avm.md index b3417afcb298..60f06218ab6f 100644 --- a/yellow-paper/docs/public-vm/avm.md +++ b/yellow-paper/docs/public-vm/avm.md @@ -70,7 +70,7 @@ ExecutionEnvironment { storageAddress: AztecAddress, origin: AztecAddress, sender: AztecAddress, - portal: AztecAddress, + portal: EthAddress, feePerL1Gas: field, feePerL2Gas: field, feePerDaGas: field, From 4521d6d1e4da673993d55cf812ca3acb32e910b3 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:16:55 +0000 Subject: [PATCH 10/14] feat: add execution environment with test construction fixtures --- .../acir-simulator/src/avm/avm_context.ts | 10 ++- .../src/avm/avm_execution_environment.ts | 27 ++---- .../src/avm/avm_machine_state.ts | 6 +- .../acir-simulator/src/avm/fixtures/index.ts | 84 ++++++++++++------- .../acir-simulator/src/avm/index.test.ts | 4 +- .../src/avm/interpreter/interpreter.test.ts | 8 +- .../src/avm/opcodes/arithmetic.test.ts | 4 +- .../src/avm/opcodes/control_flow.test.ts | 6 +- .../src/avm/opcodes/storage.test.ts | 8 +- 9 files changed, 84 insertions(+), 73 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts index 855d03338522..63cf86305039 100644 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ b/yarn-project/acir-simulator/src/avm/avm_context.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; -import { ExecutionEnvironment } from './avm_execution_environment.js'; +import { AvmExecutionEnvironment } from './avm_execution_environment.js'; import { AvmMachineState } from './avm_machine_state.js'; import { AvmMessageCallResult } from './avm_message_call_result.js'; import { AvmStateManager } from './avm_state_manager.js'; @@ -14,12 +14,14 @@ import { Instruction } from './opcodes/index.js'; * It stores a state manager */ export class AvmContext { + /** Contains constant variables provided by the kernel */ + private executionEnvironment: AvmExecutionEnvironment; + /** A wrapper that manages mutable state during execution - (caching, fetching) */ private stateManager: AvmStateManager; - private executionEnvironment: ExecutionEnvironment; - constructor(executionEnvironment: ExecutionEnvironment, stateManager: AvmStateManager) { - this.stateManager = stateManager; + constructor(executionEnvironment: AvmExecutionEnvironment, stateManager: AvmStateManager) { this.executionEnvironment = executionEnvironment; + this.stateManager = stateManager; } /** diff --git a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts b/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts index 871c9bb5a098..495a579feab2 100644 --- a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts @@ -1,9 +1,13 @@ +import { GlobalVariables } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; -/** - */ -export class ExecutionEnvironment { +/** + * Contains variables that remain constant during AVM execution + * These variables are provided by the public kernel circuit + */ +export class AvmExecutionEnvironment { constructor( /** - */ public readonly address: AztecAddress, @@ -24,7 +28,7 @@ export class ExecutionEnvironment { /** - */ public readonly contractCallDepth: Fr, /** - */ - // globals: TODO: + public readonly globals: GlobalVariables, /** - */ public readonly isStaticCall: boolean, /** - */ @@ -32,21 +36,4 @@ export class ExecutionEnvironment { /** - */ public readonly calldata: Fr[], ) {} - - static empty(): ExecutionEnvironment { - return new ExecutionEnvironment( - AztecAddress.zero(), - AztecAddress.zero(), - AztecAddress.zero(), - AztecAddress.zero(), - EthAddress.ZERO, - Fr.zero(), - Fr.zero(), - Fr.zero(), - Fr.zero(), - false, - false, - [], - ); - } } diff --git a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts index b5a3f2997a59..299be3a375f8 100644 --- a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts +++ b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; -import { ExecutionEnvironment } from './avm_execution_environment.js'; +import { AvmExecutionEnvironment } from './avm_execution_environment.js'; /** * Store's data for an Avm execution frame @@ -10,7 +10,7 @@ export class AvmMachineState { * Execution environment contains hard coded information that is received from the kernel * Items like, the block header and global variables fall within this category */ - public readonly executionEnvironment: ExecutionEnvironment; + public readonly executionEnvironment: AvmExecutionEnvironment; /** - */ public readonly calldata: Fr[]; @@ -41,7 +41,7 @@ export class AvmMachineState { * @param calldata - * @param executionEnvironment - Machine context that is passed to the avm */ - constructor(calldata: Fr[], executionEnvironment: ExecutionEnvironment) { + constructor(calldata: Fr[], executionEnvironment: AvmExecutionEnvironment) { this.calldata = calldata; this.returnData = []; this.memory = []; diff --git a/yarn-project/acir-simulator/src/avm/fixtures/index.ts b/yarn-project/acir-simulator/src/avm/fixtures/index.ts index d0d821875700..fb16ebf4ee33 100644 --- a/yarn-project/acir-simulator/src/avm/fixtures/index.ts +++ b/yarn-project/acir-simulator/src/avm/fixtures/index.ts @@ -1,40 +1,60 @@ // Place large AVM text fixtures in here +import { GlobalVariables } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; -import { ExecutionEnvironment } from '../avm_execution_environment.js'; +import { AvmExecutionEnvironment } from '../avm_execution_environment.js'; -export const initExecutionEnvironmentEmpty = (): ExecutionEnvironment => { - return new ExecutionEnvironment( - AztecAddress.zero(), - AztecAddress.zero(), - AztecAddress.zero(), - AztecAddress.zero(), - EthAddress.ZERO, - Fr.zero(), - Fr.zero(), - Fr.zero(), - Fr.zero(), - false, - false, - [], - ); -}; +/** + * An interface that allows to override the default values of the AvmExecutionEnvironment + */ +export interface AvmExecutionEnvironmentOverrides { + /** - */ + address?: AztecAddress; + /** - */ + storageAddress?: AztecAddress; + /** - */ + origin?: AztecAddress; + /** - */ + sender?: AztecAddress; + /** - */ + portal?: EthAddress; + /** - */ + feePerL1Gas?: Fr; + /** - */ + feePerL2Gas?: Fr; + /** - */ + feePerDaGas?: Fr; + /** - */ + contractCallDepth?: Fr; + /** - */ + globals?: GlobalVariables; + /** - */ + isStaticCall?: boolean; + /** - */ + isDelegateCall?: boolean; + /** - */ + calldata?: Fr[]; +} -export const initExecutionEnvironment = (contractAddress: AztecAddress): ExecutionEnvironment => { - return new ExecutionEnvironment( - contractAddress, - contractAddress, - AztecAddress.zero(), - AztecAddress.zero(), - EthAddress.ZERO, - Fr.zero(), - Fr.zero(), - Fr.zero(), - Fr.zero(), - false, - false, - [], +/** + * Create an empty instance of the Execution Environment where all values are zero, unless overriden in the overrides object + */ +export function initExecutionEnvironment(overrides?: AvmExecutionEnvironmentOverrides): AvmExecutionEnvironment { + return new AvmExecutionEnvironment( + overrides?.address ?? AztecAddress.zero(), + overrides?.storageAddress ?? AztecAddress.zero(), + overrides?.origin ?? AztecAddress.zero(), + overrides?.sender ?? AztecAddress.zero(), + overrides?.portal ?? EthAddress.ZERO, + overrides?.feePerL1Gas ?? Fr.zero(), + overrides?.feePerL2Gas ?? Fr.zero(), + overrides?.feePerDaGas ?? Fr.zero(), + overrides?.contractCallDepth ?? Fr.zero(), + overrides?.globals ?? GlobalVariables.empty(), + overrides?.isStaticCall ?? false, + overrides?.isDelegateCall ?? false, + overrides?.calldata ?? [], ); -}; +} diff --git a/yarn-project/acir-simulator/src/avm/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts index 9ab9845b28bf..30b6c8c0551d 100644 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ b/yarn-project/acir-simulator/src/avm/index.test.ts @@ -4,7 +4,7 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from './avm_machine_state.js'; import { AvmStateManager } from './avm_state_manager.js'; -import { initExecutionEnvironmentEmpty } from './fixtures/index.js'; +import { initExecutionEnvironment } from './fixtures/index.js'; import { AvmInterpreter } from './interpreter/interpreter.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { encodeToBytecode } from './opcodes/encode_to_bytecode.js'; @@ -29,7 +29,7 @@ describe('avm', () => { const instructions = decodeBytecode(fullBytecode); // Execute instructions - const executionEnvironment = initExecutionEnvironmentEmpty(); + const executionEnvironment = initExecutionEnvironment(); const context = new AvmMachineState(calldata, executionEnvironment); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts index e5bb9fb6dd25..625c5afaf679 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -4,7 +4,7 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; -import { initExecutionEnvironmentEmpty } from '../fixtures/index.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; import { Add } from '../opcodes/arithmetic.js'; import { Jump, Return } from '../opcodes/control_flow.js'; import { Instruction } from '../opcodes/instruction.js'; @@ -30,7 +30,8 @@ describe('interpreter', () => { new Return(2, 1), // [3] ]; - const context = new AvmMachineState(calldata, initExecutionEnvironmentEmpty()); + const executionEnvironment = initExecutionEnvironment(); + const context = new AvmMachineState(calldata, executionEnvironment); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); @@ -48,7 +49,8 @@ describe('interpreter', () => { const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; - const context = new AvmMachineState(calldata, initExecutionEnvironmentEmpty()); + const executionEnvironment = initExecutionEnvironment(); + const context = new AvmMachineState(calldata, executionEnvironment); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts index f3448c8740b3..8f64beab064d 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -4,7 +4,7 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; -import { initExecutionEnvironmentEmpty } from '../fixtures/index.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; import { Add, Div, Mul, Sub } from './arithmetic.js'; describe('Arithmetic Instructions', () => { @@ -12,7 +12,7 @@ describe('Arithmetic Instructions', () => { let stateManager: MockProxy; beforeEach(() => { - machineState = new AvmMachineState([], initExecutionEnvironmentEmpty()); + machineState = new AvmMachineState([], initExecutionEnvironment()); stateManager = mock(); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts index 43f537b9f74a..cbe05388f5c0 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts @@ -4,7 +4,7 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; -import { initExecutionEnvironmentEmpty } from '../fixtures/index.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; import { Add, Mul, Sub } from './arithmetic.js'; import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; import { Eq, Lt, Lte } from './comparators.js'; @@ -17,7 +17,7 @@ describe('Control Flow Opcodes', () => { beforeEach(() => { stateManager = mock(); - machineState = new AvmMachineState([], initExecutionEnvironmentEmpty()); + machineState = new AvmMachineState([], initExecutionEnvironment()); }); it('Should implement JUMP', () => { @@ -138,7 +138,7 @@ describe('Control Flow Opcodes', () => { for (const instruction of instructions) { // Use a fresh machine state each run - const innerMachineState = new AvmMachineState([], initExecutionEnvironmentEmpty()); + const innerMachineState = new AvmMachineState([], initExecutionEnvironment()); expect(machineState.pc).toBe(0); instruction.execute(innerMachineState, stateManager); expect(innerMachineState.pc).toBe(1); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts index 7f9f5fc07217..3addf27f61d3 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -11,12 +11,12 @@ import { SLoad, SStore } from './storage.js'; describe('Storage Instructions', () => { let stateManager: MockProxy; let machineState: AvmMachineState; - const contractAddress = AztecAddress.random(); + const address = AztecAddress.random(); beforeEach(() => { stateManager = mock(); - const executionEnvironment = initExecutionEnvironment(contractAddress); + const executionEnvironment = initExecutionEnvironment({ address, storageAddress: address }); machineState = new AvmMachineState([], executionEnvironment); }); @@ -29,7 +29,7 @@ describe('Storage Instructions', () => { new SStore(0, 1).execute(machineState, stateManager); - expect(stateManager.store).toBeCalledWith(contractAddress, a, b); + expect(stateManager.store).toBeCalledWith(address, a, b); }); it('Sload should Read into storage', async () => { @@ -45,7 +45,7 @@ describe('Storage Instructions', () => { await new SLoad(0, 1).execute(machineState, stateManager); - expect(stateManager.read).toBeCalledWith(contractAddress, a); + expect(stateManager.read).toBeCalledWith(address, a); const actual = machineState.readMemory(1); expect(actual).toEqual(expectedResult); From 7fcc6cf38c739091dfb80e651d4450e9c75356d0 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:25:44 +0000 Subject: [PATCH 11/14] chore: add execution environment to merged tests --- .../acir-simulator/src/avm/opcodes/bitwise.test.ts | 3 ++- .../acir-simulator/src/avm/opcodes/instruction_set.ts | 5 +++-- .../acir-simulator/src/avm/opcodes/memory.test.ts | 9 +++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts index e1de73560412..5f605b31e55d 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -12,13 +12,14 @@ import { Shr, Xor, } from './bitwise.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; describe('Bitwise instructions', () => { let machineState: AvmMachineState; let stateManager = mock(); beforeEach(() => { - machineState = new AvmMachineState([]); + machineState = new AvmMachineState([], initExecutionEnvironment()); stateManager = mock(); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts index 664467f887dd..493be13507fb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts @@ -1,6 +1,7 @@ import { Add, Div, Mul, Sub } from './arithmetic.js'; import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; //import { Eq, Lt, Lte } from './comparators.js'; +import {SLoad, SStore} from './storage.js'; import { InternalCall, InternalReturn, Jump, JumpI, Return } from './control_flow.js'; import { Instruction } from './instruction.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; @@ -75,8 +76,8 @@ export const INSTRUCTION_SET: Map = ne //// World State //[Opcode.BLOCKHEADERBYNUMBER, Blockheaderbynumber], - //[Opcode.SLOAD, Sload], // Public Storage - //[Opcode.SSTORE, Sstore], // Public Storage + [Opcode.SLOAD, SLoad], // Public Storage + [Opcode.SSTORE, SStore], // Public Storage //[Opcode.READL1TOL2MSG, Readl1tol2msg], // Messages //[Opcode.SENDL2TOL1MSG, Sendl2tol1msg], // Messages //[Opcode.EMITNOTEHASH, Emitnotehash], // Notes & Nullifiers diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts index 3b02ef36c32c..e47ea45d818c 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -5,13 +5,14 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; describe('Memory instructions', () => { let machineState: AvmMachineState; let stateManager = mock(); beforeEach(() => { - machineState = new AvmMachineState([]); + machineState = new AvmMachineState([], initExecutionEnvironment()); stateManager = mock(); }); @@ -141,7 +142,7 @@ describe('Memory instructions', () => { const previousValue = new Fr(123456n); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(calldata); + machineState = new AvmMachineState(calldata, initExecutionEnvironment()); machineState.writeMemory(0, previousValue); new CalldataCopy(/*cdOffset=*/ 2, /*copySize=*/ 0, /*dstOffset=*/ 0).execute(machineState, stateManager); @@ -154,7 +155,7 @@ describe('Memory instructions', () => { const previousValue = new Fr(123456n); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(calldata); + machineState = new AvmMachineState(calldata, initExecutionEnvironment()); machineState.writeMemory(0, previousValue); new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(machineState, stateManager); @@ -167,7 +168,7 @@ describe('Memory instructions', () => { const previousValue = new Fr(123456n); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(calldata); + machineState = new AvmMachineState(calldata, initExecutionEnvironment()); machineState.writeMemory(0, previousValue); new CalldataCopy(/*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(machineState, stateManager); From db1ca36f4739a8f706579d5011f3bc77c8ade071 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 23 Jan 2024 17:38:30 +0000 Subject: [PATCH 12/14] fix: fmt --- yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts | 2 +- .../acir-simulator/src/avm/opcodes/instruction_set.ts | 4 ++-- yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts index 5f605b31e55d..9bfd0fae41da 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -4,6 +4,7 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; import { And, /*Not,*/ @@ -12,7 +13,6 @@ import { Shr, Xor, } from './bitwise.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; describe('Bitwise instructions', () => { let machineState: AvmMachineState; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts index 493be13507fb..3413673f7e62 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts @@ -1,11 +1,11 @@ import { Add, Div, Mul, Sub } from './arithmetic.js'; import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; -//import { Eq, Lt, Lte } from './comparators.js'; -import {SLoad, SStore} from './storage.js'; import { InternalCall, InternalReturn, Jump, JumpI, Return } from './control_flow.js'; import { Instruction } from './instruction.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; import { Opcode } from './opcodes.js'; +//import { Eq, Lt, Lte } from './comparators.js'; +import { SLoad, SStore } from './storage.js'; /** - */ type InstructionConstructor = new (...args: any[]) => Instruction; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts index e47ea45d818c..6cad7472548e 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -4,8 +4,8 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; -import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; +import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Memory instructions', () => { let machineState: AvmMachineState; From 26a2315ceef0e0e87b9338ce16c1e501b681ffe7 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:23:24 +0000 Subject: [PATCH 13/14] chore: move calldata into execution environment --- yarn-project/acir-simulator/src/avm/avm_context.ts | 7 ++----- yarn-project/acir-simulator/src/avm/avm_machine_state.ts | 6 +----- yarn-project/acir-simulator/src/avm/index.test.ts | 3 +-- .../src/avm/interpreter/interpreter.test.ts | 6 ++---- .../acir-simulator/src/avm/opcodes/arithmetic.test.ts | 2 +- .../acir-simulator/src/avm/opcodes/bitwise.test.ts | 2 +- .../acir-simulator/src/avm/opcodes/control_flow.test.ts | 4 ++-- .../acir-simulator/src/avm/opcodes/memory.test.ts | 8 ++++---- yarn-project/acir-simulator/src/avm/opcodes/memory.ts | 2 +- .../acir-simulator/src/avm/opcodes/storage.test.ts | 2 +- 10 files changed, 16 insertions(+), 26 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts index 63cf86305039..ec3fd17a87a6 100644 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ b/yarn-project/acir-simulator/src/avm/avm_context.ts @@ -1,5 +1,3 @@ -import { Fr } from '@aztec/foundation/fields'; - import { AvmExecutionEnvironment } from './avm_execution_environment.js'; import { AvmMachineState } from './avm_machine_state.js'; import { AvmMessageCallResult } from './avm_message_call_result.js'; @@ -31,16 +29,15 @@ export class AvmContext { * - We interpret the bytecode * - We run the interpreter * - * @param calldata - */ - public call(calldata: Fr[]): AvmMessageCallResult { + public call(): AvmMessageCallResult { // NOTE: the following is mocked as getPublicBytecode does not exist yet // const bytecode = stateManager.journal.hostStorage.contractsDb.getBytecode(this.executionEnvironment.address); const bytecode = Buffer.from('0x01000100020003'); const instructions: Instruction[] = decodeBytecode(bytecode); - const context = new AvmMachineState(calldata, this.executionEnvironment); + const context = new AvmMachineState(this.executionEnvironment); const interpreter = new AvmInterpreter(context, this.stateManager, instructions); return interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts index 299be3a375f8..fa70927a0b1a 100644 --- a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts +++ b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts @@ -12,8 +12,6 @@ export class AvmMachineState { */ public readonly executionEnvironment: AvmExecutionEnvironment; - /** - */ - public readonly calldata: Fr[]; private returnData: Fr[]; // TODO: implement tagged memory @@ -38,11 +36,9 @@ export class AvmMachineState { /** * Create a new avm context - * @param calldata - * @param executionEnvironment - Machine context that is passed to the avm */ - constructor(calldata: Fr[], executionEnvironment: AvmExecutionEnvironment) { - this.calldata = calldata; + constructor(executionEnvironment: AvmExecutionEnvironment) { this.returnData = []; this.memory = []; this.internalCallStack = []; diff --git a/yarn-project/acir-simulator/src/avm/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts index 30b6c8c0551d..bb1b15bffe0c 100644 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ b/yarn-project/acir-simulator/src/avm/index.test.ts @@ -29,8 +29,7 @@ describe('avm', () => { const instructions = decodeBytecode(fullBytecode); // Execute instructions - const executionEnvironment = initExecutionEnvironment(); - const context = new AvmMachineState(calldata, executionEnvironment); + const context = new AvmMachineState(initExecutionEnvironment({ calldata })); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts index 6f3a67a57128..cd6b93d592cf 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -27,8 +27,7 @@ describe('interpreter', () => { new Return(/*returnOffset=*/ 2, /*copySize=*/ 1), ]; - const executionEnvironment = initExecutionEnvironment(); - const context = new AvmMachineState(calldata, executionEnvironment); + const context = new AvmMachineState(initExecutionEnvironment({ calldata })); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); @@ -44,8 +43,7 @@ describe('interpreter', () => { const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; - const executionEnvironment = initExecutionEnvironment(); - const context = new AvmMachineState(calldata, executionEnvironment); + const context = new AvmMachineState(initExecutionEnvironment({ calldata })); const interpreter = new AvmInterpreter(context, stateManager, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts index 8f64beab064d..c1bd72b65129 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -12,7 +12,7 @@ describe('Arithmetic Instructions', () => { let stateManager: MockProxy; beforeEach(() => { - machineState = new AvmMachineState([], initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment()); stateManager = mock(); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts index 9bfd0fae41da..56856458a77c 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -19,7 +19,7 @@ describe('Bitwise instructions', () => { let stateManager = mock(); beforeEach(() => { - machineState = new AvmMachineState([], initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment()); stateManager = mock(); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts index 856c1f8126ff..976c56089adb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts @@ -17,7 +17,7 @@ describe('Control Flow Opcodes', () => { beforeEach(() => { stateManager = mock(); - machineState = new AvmMachineState([], initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment()); }); it('Should implement JUMP', () => { @@ -139,7 +139,7 @@ describe('Control Flow Opcodes', () => { for (const instruction of instructions) { // Use a fresh machine state each run - const innerMachineState = new AvmMachineState([], initExecutionEnvironment()); + const innerMachineState = new AvmMachineState(initExecutionEnvironment()); expect(machineState.pc).toBe(0); instruction.execute(innerMachineState, stateManager); expect(innerMachineState.pc).toBe(1); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts index 6cad7472548e..a6c5543ec0bd 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -12,7 +12,7 @@ describe('Memory instructions', () => { let stateManager = mock(); beforeEach(() => { - machineState = new AvmMachineState([], initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment()); stateManager = mock(); }); @@ -142,7 +142,7 @@ describe('Memory instructions', () => { const previousValue = new Fr(123456n); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(calldata, initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.writeMemory(0, previousValue); new CalldataCopy(/*cdOffset=*/ 2, /*copySize=*/ 0, /*dstOffset=*/ 0).execute(machineState, stateManager); @@ -155,7 +155,7 @@ describe('Memory instructions', () => { const previousValue = new Fr(123456n); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(calldata, initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.writeMemory(0, previousValue); new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(machineState, stateManager); @@ -168,7 +168,7 @@ describe('Memory instructions', () => { const previousValue = new Fr(123456n); const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(calldata, initExecutionEnvironment()); + machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.writeMemory(0, previousValue); new CalldataCopy(/*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(machineState, stateManager); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts index 3e6bbc62afdd..8bfe50e4a5eb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts @@ -92,7 +92,7 @@ export class CalldataCopy extends Instruction { } execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { - const calldata = machineState.calldata.slice(this.cdOffset, this.cdOffset + this.copySize); + const calldata = machineState.executionEnvironment.calldata.slice(this.cdOffset, this.cdOffset + this.copySize); machineState.writeMemoryChunk(this.destOffset, calldata); this.incrementPc(machineState); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts index 3addf27f61d3..f44d6fb5f5f5 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -17,7 +17,7 @@ describe('Storage Instructions', () => { stateManager = mock(); const executionEnvironment = initExecutionEnvironment({ address, storageAddress: address }); - machineState = new AvmMachineState([], executionEnvironment); + machineState = new AvmMachineState(executionEnvironment); }); it('Sstore should Write into storage', () => { From b2a40513237ace2a1685b61d688f4dc1551a7be9 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:05:16 +0000 Subject: [PATCH 14/14] fix: post merge fix --- .../src/avm/opcodes/bitwise.test.ts | 2 +- .../src/avm/opcodes/memory.test.ts | 2 +- .../src/avm/opcodes/storage.test.ts | 10 +++++----- .../acir-simulator/src/avm/opcodes/storage.ts | 18 ++++++++++++------ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts index 232f51a0e4b4..4221f3389728 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -3,8 +3,8 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { TypeTag, Uint16, Uint32 } from '../avm_memory_types.js'; import { AvmStateManager } from '../avm_state_manager.js'; -import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; +import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; describe('Bitwise instructions', () => { let machineState: AvmMachineState; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts index aba6aa851b05..5c3edb9e3793 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -243,7 +243,7 @@ describe('Memory instructions', () => { describe('CALLDATACOPY', () => { it('Writes nothing if size is 0', () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(initExecutionEnvironment({calldata})); + machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 0, /*dstOffset=*/ 0).execute(machineState, stateManager); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts index f44d6fb5f5f5..265bf670e205 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -24,8 +24,8 @@ describe('Storage Instructions', () => { const a = new Fr(1n); const b = new Fr(2n); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + machineState.memory.set(0, a); + machineState.memory.set(1, b); new SStore(0, 1).execute(machineState, stateManager); @@ -40,14 +40,14 @@ describe('Storage Instructions', () => { const a = new Fr(1n); const b = new Fr(2n); - machineState.writeMemory(0, a); - machineState.writeMemory(1, b); + machineState.memory.set(0, a); + machineState.memory.set(1, b); await new SLoad(0, 1).execute(machineState, stateManager); expect(stateManager.read).toBeCalledWith(address, a); - const actual = machineState.readMemory(1); + const actual = machineState.memory.get(1); expect(actual).toEqual(expectedResult); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts index c773600413a7..3f79594cb311 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts @@ -1,3 +1,5 @@ +import { Fr } from '@aztec/foundation/fields'; + import { AvmMachineState } from '../avm_machine_state.js'; import { AvmStateManager } from '../avm_state_manager.js'; import { Instruction } from './instruction.js'; @@ -12,10 +14,14 @@ export class SStore extends Instruction { } execute(machineState: AvmMachineState, stateManager: AvmStateManager): void { - const slot = machineState.readMemory(this.slotOffset); - const data = machineState.readMemory(this.dataOffset); + const slot = machineState.memory.get(this.slotOffset); + const data = machineState.memory.get(this.dataOffset); - stateManager.store(machineState.executionEnvironment.storageAddress, slot, data); + stateManager.store( + machineState.executionEnvironment.storageAddress, + new Fr(slot.toBigInt()), + new Fr(data.toBigInt()), + ); this.incrementPc(machineState); } @@ -31,11 +37,11 @@ export class SLoad extends Instruction { } async execute(machineState: AvmMachineState, stateManager: AvmStateManager): Promise { - const slot = machineState.readMemory(this.slotOffset); + const slot = machineState.memory.get(this.slotOffset); - const data = stateManager.read(machineState.executionEnvironment.storageAddress, slot); + const data = stateManager.read(machineState.executionEnvironment.storageAddress, new Fr(slot.toBigInt())); - machineState.writeMemory(this.destOffset, await data); + machineState.memory.set(this.destOffset, await data); this.incrementPc(machineState); }