From 0b124211ac445e9801a0559ec7f04dff10188b6d Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 24 Jan 2024 00:20:28 +0000 Subject: [PATCH 1/9] refactor: remove the state manager in favour of journal --- .../acir-simulator/src/avm/avm_context.ts | 14 ++-- .../src/avm/avm_state_manager.ts | 65 ------------------- .../acir-simulator/src/avm/index.test.ts | 6 +- yarn-project/acir-simulator/src/avm/index.ts | 3 - .../src/avm/interpreter/interpreter.test.ts | 10 +-- .../src/avm/interpreter/interpreter.ts | 10 +-- .../src/avm/opcodes/arithmetic.test.ts | 18 ++--- .../src/avm/opcodes/arithmetic.ts | 10 +-- .../src/avm/opcodes/bitwise.test.ts | 30 ++++----- .../acir-simulator/src/avm/opcodes/bitwise.ts | 14 ++-- .../src/avm/opcodes/comparators.ts | 8 +-- .../src/avm/opcodes/control_flow.test.ts | 24 +++---- .../src/avm/opcodes/control_flow.ts | 12 ++-- .../src/avm/opcodes/instruction.ts | 4 +- .../src/avm/opcodes/memory.test.ts | 38 +++++------ .../acir-simulator/src/avm/opcodes/memory.ts | 12 ++-- .../src/avm/opcodes/storage.test.ts | 16 ++--- .../acir-simulator/src/avm/opcodes/storage.ts | 10 +-- 18 files changed, 118 insertions(+), 186 deletions(-) delete mode 100644 yarn-project/acir-simulator/src/avm/avm_state_manager.ts delete mode 100644 yarn-project/acir-simulator/src/avm/index.ts diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts index ec3fd17a87a..699f9365b15 100644 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ b/yarn-project/acir-simulator/src/avm/avm_context.ts @@ -1,8 +1,8 @@ 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'; import { AvmInterpreter } from './interpreter/index.js'; +import { AvmJournal } from './journal/journal.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { Instruction } from './opcodes/index.js'; @@ -14,12 +14,12 @@ import { Instruction } from './opcodes/index.js'; 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; + /** Manages mutable state during execution - (caching, fetching) */ + private journal: AvmJournal; - constructor(executionEnvironment: AvmExecutionEnvironment, stateManager: AvmStateManager) { + constructor(executionEnvironment: AvmExecutionEnvironment, journal: AvmJournal) { this.executionEnvironment = executionEnvironment; - this.stateManager = stateManager; + this.journal = journal; } /** @@ -32,13 +32,13 @@ export class AvmContext { */ 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 = journal.journal.hostStorage.contractsDb.getBytecode(this.executionEnvironment.address); const bytecode = Buffer.from('0x01000100020003'); const instructions: Instruction[] = decodeBytecode(bytecode); const context = new AvmMachineState(this.executionEnvironment); - const interpreter = new AvmInterpreter(context, this.stateManager, instructions); + const interpreter = new AvmInterpreter(context, this.journal, instructions); return interpreter.run(); } diff --git a/yarn-project/acir-simulator/src/avm/avm_state_manager.ts b/yarn-project/acir-simulator/src/avm/avm_state_manager.ts deleted file mode 100644 index d75c25c72a1..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_state_manager.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { AztecAddress, BlockHeader } from '@aztec/circuits.js'; -import { Fr } from '@aztec/foundation/fields'; - -import { AvmJournal, HostStorage } from './journal/index.js'; - -/** - * The Avm State Manager is the interpreter's interface to the node's state - * It creates revertible views into the node state and manages the current call's journal - */ -export class AvmStateManager { - /** - */ - public readonly blockHeader: BlockHeader; - - /** - * Journal keeps track of pending state changes - */ - public readonly journal: AvmJournal; - - constructor(blockHeader: BlockHeader, journal: AvmJournal) { - this.blockHeader = blockHeader; - this.journal = journal; - } - - /** - * Create a base state root manager - * - this should be created by the highest level item where the state - * can be reverted - * @param blockHeader - - * @param hostStorage - An immutable view into the node db - * @returns Avm State Manager - */ - public static rootStateManager(blockHeader: BlockHeader, hostStorage: HostStorage): AvmStateManager { - const journal = AvmJournal.rootJournal(hostStorage); - return new AvmStateManager(blockHeader, journal); - } - - /** - * Avm State - * @param parent - Avm state manager with a forked journal - * @returns - */ - public static forkStateManager(parent: AvmStateManager): 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/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts index bb1b15bffe0..282afcc901e 100644 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ b/yarn-project/acir-simulator/src/avm/index.test.ts @@ -3,9 +3,9 @@ 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 { initExecutionEnvironment } from './fixtures/index.js'; import { AvmInterpreter } from './interpreter/interpreter.js'; +import { AvmJournal } from './journal/journal.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { encodeToBytecode } from './opcodes/encode_to_bytecode.js'; import { Opcode } from './opcodes/opcodes.js'; @@ -13,7 +13,7 @@ import { Opcode } from './opcodes/opcodes.js'; describe('avm', () => { it('Should execute bytecode', () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const stateManager = mock(); + const journal = mock(); // Construct bytecode const calldataCopyArgs = [0, 2, 0]; @@ -30,7 +30,7 @@ describe('avm', () => { // Execute instructions const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(context, stateManager, instructions); + const interpreter = new AvmInterpreter(context, journal, instructions); const avmReturnData = interpreter.run(); expect(avmReturnData.reverted).toBe(false); diff --git a/yarn-project/acir-simulator/src/avm/index.ts b/yarn-project/acir-simulator/src/avm/index.ts deleted file mode 100644 index 6a102a6cd57..00000000000 --- a/yarn-project/acir-simulator/src/avm/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './avm_machine_state.js'; -export * from './avm_context.js'; -export * from './avm_state_manager.js'; 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 cd6b93d592c..39b8092dabf 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -3,8 +3,8 @@ 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 { AvmJournal } from '../journal/journal.js'; import { Add } from '../opcodes/arithmetic.js'; import { Jump, Return } from '../opcodes/control_flow.js'; import { Instruction } from '../opcodes/instruction.js'; @@ -12,10 +12,10 @@ import { CalldataCopy } from '../opcodes/memory.js'; import { AvmInterpreter, InvalidProgramCounterError } from './interpreter.js'; describe('interpreter', () => { - let stateManager: MockProxy; + let journal: MockProxy; beforeEach(() => { - stateManager = mock(); + journal = mock(); }); it('Should execute a series of instructions', () => { @@ -28,7 +28,7 @@ describe('interpreter', () => { ]; const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(context, stateManager, instructions); + const interpreter = new AvmInterpreter(context, journal, instructions); const avmReturnData = interpreter.run(); expect(avmReturnData.reverted).toBe(false); @@ -44,7 +44,7 @@ describe('interpreter', () => { const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(context, stateManager, instructions); + const interpreter = new AvmInterpreter(context, journal, instructions); const avmReturnData = interpreter.run(); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts index 55204f88b47..f8aa30fed67 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts @@ -4,7 +4,7 @@ import { strict as assert } from 'assert'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmMessageCallResult } from '../avm_message_call_result.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/index.js'; import { Instruction } from '../opcodes/index.js'; /** @@ -15,11 +15,11 @@ import { Instruction } from '../opcodes/index.js'; export class AvmInterpreter { private instructions: Instruction[] = []; private machineState: AvmMachineState; - private stateManager: AvmStateManager; + private journal: AvmJournal; - constructor(machineState: AvmMachineState, stateManager: AvmStateManager, instructions: Instruction[]) { + constructor(machineState: AvmMachineState, stateManager: AvmJournal, instructions: Instruction[]) { this.machineState = machineState; - this.stateManager = stateManager; + this.journal = stateManager; this.instructions = instructions; } @@ -37,7 +37,7 @@ export class AvmInterpreter { const instruction = this.instructions[this.machineState.pc]; assert(!!instruction); // This should never happen - instruction.execute(this.machineState, this.stateManager); + instruction.execute(this.machineState, this.journal); if (this.machineState.pc >= this.instructions.length) { throw new InvalidProgramCounterError(this.machineState.pc, /*max=*/ this.instructions.length); 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 9f45eb15ac5..6dddce70aac 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -2,17 +2,17 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { Field } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; +import { AvmJournal } from '../journal/journal.js'; import { Add, Div, Mul, Sub } from './arithmetic.js'; describe('Arithmetic Instructions', () => { let machineState: AvmMachineState; - let stateManager: MockProxy; + let journal: MockProxy; beforeEach(() => { machineState = new AvmMachineState(initExecutionEnvironment()); - stateManager = mock(); + journal = mock(); }); describe('Add', () => { @@ -23,7 +23,7 @@ describe('Arithmetic Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Add(0, 1, 2).execute(machineState, stateManager); + new Add(0, 1, 2).execute(machineState, journal); const expected = new Field(3n); const actual = machineState.memory.get(2); @@ -37,7 +37,7 @@ describe('Arithmetic Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Add(0, 1, 2).execute(machineState, stateManager); + new Add(0, 1, 2).execute(machineState, journal); const expected = new Field(0n); const actual = machineState.memory.get(2); @@ -53,7 +53,7 @@ describe('Arithmetic Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Sub(0, 1, 2).execute(machineState, stateManager); + new Sub(0, 1, 2).execute(machineState, journal); const expected = new Field(Field.MODULUS - 1n); const actual = machineState.memory.get(2); @@ -69,7 +69,7 @@ describe('Arithmetic Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Mul(0, 1, 2).execute(machineState, stateManager); + new Mul(0, 1, 2).execute(machineState, journal); const expected = new Field(6n); const actual = machineState.memory.get(2); @@ -83,7 +83,7 @@ describe('Arithmetic Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Mul(0, 1, 2).execute(machineState, stateManager); + new Mul(0, 1, 2).execute(machineState, journal); const expected = new Field(Field.MODULUS - 3n); const actual = machineState.memory.get(2); @@ -99,7 +99,7 @@ describe('Arithmetic Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Div(0, 1, 2).execute(machineState, stateManager); + new Div(0, 1, 2).execute(machineState, journal); // Note const actual = machineState.memory.get(2); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts index 6bfc61ff584..d6b5bc2bccb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts @@ -1,5 +1,5 @@ import { AvmMachineState } from '../avm_machine_state.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/index.js'; import { Instruction } from './instruction.js'; export class Add extends Instruction { @@ -10,7 +10,7 @@ export class Add extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -29,7 +29,7 @@ export class Sub extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -48,7 +48,7 @@ export class Mul extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -68,7 +68,7 @@ export class Div extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); 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 4221f338972..4c791379c7e 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -1,25 +1,25 @@ -import { mock } from 'jest-mock-extended'; +import { MockProxy, 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 { initExecutionEnvironment } from '../fixtures/index.js'; +import { AvmJournal } from '../journal/journal.js'; import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; describe('Bitwise instructions', () => { let machineState: AvmMachineState; - let stateManager = mock(); + let journal: MockProxy; beforeEach(() => { machineState = new AvmMachineState(initExecutionEnvironment()); - stateManager = mock(); + journal = mock(); }); it('Should AND correctly over integral types', () => { machineState.memory.set(0, new Uint32(0b11111110010011100100n)); machineState.memory.set(1, new Uint32(0b11100100111001001111n)); - new And(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new And(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const actual = machineState.memory.get(2); expect(actual).toEqual(new Uint32(0b11100100010001000100n)); @@ -32,7 +32,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Or(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Or(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b11111110111011101111n); const actual = machineState.memory.get(2); @@ -46,7 +46,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Xor(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Xor(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b00011010101010101011n); const actual = machineState.memory.get(2); @@ -61,7 +61,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = a; const actual = machineState.memory.get(2); @@ -75,7 +75,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b00111111100100111001n); const actual = machineState.memory.get(2); @@ -89,7 +89,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b01n); const actual = machineState.memory.get(2); @@ -105,7 +105,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = a; const actual = machineState.memory.get(2); @@ -119,7 +119,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, stateManager); + new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b1111111001001110010000n); const actual = machineState.memory.get(2); @@ -133,7 +133,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, stateManager); + new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); const expected = new Uint16(0n); const actual = machineState.memory.get(2); @@ -147,7 +147,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, stateManager); + new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); const expected = new Uint16(0b1001001110011100n); const actual = machineState.memory.get(2); @@ -160,7 +160,7 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); - new Not(0, 1, TypeTag.UINT16).execute(machineState, stateManager); + new Not(0, 1, TypeTag.UINT16).execute(machineState, journal); const expected = new Uint16(0b1001101100011011n); // high bits! const actual = machineState.memory.get(1); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts index e788abcc1f5..7d7f881bbf9 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts @@ -1,6 +1,6 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { IntegralValue, TypeTag } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/index.js'; import { Instruction } from './instruction.js'; export class And extends Instruction { @@ -11,7 +11,7 @@ export class And extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -32,7 +32,7 @@ export class Or extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -53,7 +53,7 @@ export class Xor extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -74,7 +74,7 @@ export class Not extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { Instruction.checkTags(machineState, this.inTag, this.aOffset); const a = machineState.memory.getAs(this.aOffset); @@ -94,7 +94,7 @@ export class Shl extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -115,7 +115,7 @@ export class Shr extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts index b4f65a66f7b..d9a4c48d867 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts @@ -1,6 +1,6 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { Field } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/index.js'; import { Instruction } from './instruction.js'; export class Eq extends Instruction { @@ -11,7 +11,7 @@ export class Eq extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -30,7 +30,7 @@ export class Lt extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -49,7 +49,7 @@ export class Lte extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); 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 f703242cc5a..75a46347f61 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 @@ -2,8 +2,8 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { TypeTag, Uint16 } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; +import { AvmJournal } from '../journal/journal.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'; @@ -12,11 +12,11 @@ import { InstructionExecutionError } from './instruction.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Control Flow Opcodes', () => { - let stateManager: MockProxy; + let journal: MockProxy; let machineState: AvmMachineState; beforeEach(() => { - stateManager = mock(); + journal = mock(); machineState = new AvmMachineState(initExecutionEnvironment()); }); @@ -26,7 +26,7 @@ describe('Control Flow Opcodes', () => { expect(machineState.pc).toBe(0); const instruction = new Jump(jumpLocation); - instruction.execute(machineState, stateManager); + instruction.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation); }); @@ -40,12 +40,12 @@ describe('Control Flow Opcodes', () => { machineState.memory.set(1, new Uint16(2n)); const instruction = new JumpI(jumpLocation, 0); - instruction.execute(machineState, stateManager); + instruction.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation); // Truthy can be greater than 1 const instruction1 = new JumpI(jumpLocation1, 1); - instruction1.execute(machineState, stateManager); + instruction1.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation1); }); @@ -57,7 +57,7 @@ describe('Control Flow Opcodes', () => { machineState.memory.set(0, new Uint16(0n)); const instruction = new JumpI(jumpLocation, 0); - instruction.execute(machineState, stateManager); + instruction.execute(machineState, journal); expect(machineState.pc).toBe(1); }); @@ -69,10 +69,10 @@ describe('Control Flow Opcodes', () => { const instruction = new InternalCall(jumpLocation); const returnInstruction = new InternalReturn(); - instruction.execute(machineState, stateManager); + instruction.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation); - returnInstruction.execute(machineState, stateManager); + returnInstruction.execute(machineState, journal); expect(machineState.pc).toBe(1); }); @@ -106,14 +106,14 @@ describe('Control Flow Opcodes', () => { ]; for (let i = 0; i < instructions.length; i++) { - instructions[i].execute(machineState, stateManager); + instructions[i].execute(machineState, journal); expect(machineState.pc).toBe(expectedPcs[i]); } }); it('Should error if Internal Return is called without a corresponding Internal Call', () => { const returnInstruction = new InternalReturn(); - expect(() => returnInstruction.execute(machineState, stateManager)).toThrow(InstructionExecutionError); + expect(() => returnInstruction.execute(machineState, journal)).toThrow(InstructionExecutionError); }); it('Should increment PC on All other Instructions', () => { @@ -144,7 +144,7 @@ describe('Control Flow Opcodes', () => { innerMachineState.memory.set(1, new Uint16(8n)); innerMachineState.memory.set(2, new Uint16(12n)); expect(machineState.pc).toBe(0); - instruction.execute(innerMachineState, stateManager); + instruction.execute(innerMachineState, journal); expect(innerMachineState.pc).toBe(1); } }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts index 7967a417c8a..95c9e12dcdb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts @@ -2,7 +2,7 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmMachineState } from '../avm_machine_state.js'; import { IntegralValue } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/journal.js'; import { Instruction, InstructionExecutionError } from './instruction.js'; export class Return extends Instruction { @@ -13,7 +13,7 @@ export class Return extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const returnData = machineState.memory .getSlice(this.returnOffset, this.copySize) .map(fvt => new Fr(fvt.toBigInt())); @@ -32,7 +32,7 @@ export class Jump extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { machineState.pc = this.jumpOffset; } } @@ -45,7 +45,7 @@ export class JumpI extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const condition = machineState.memory.getAs(this.condOffset); // TODO: reconsider this casting @@ -65,7 +65,7 @@ export class InternalCall extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { machineState.internalCallStack.push(machineState.pc + 1); machineState.pc = this.jumpOffset; } @@ -79,7 +79,7 @@ export class InternalReturn extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const jumpOffset = machineState.internalCallStack.pop(); if (jumpOffset === undefined) { throw new InstructionExecutionError('Internal call empty!'); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts index 766e5ee158e..03e362018ec 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts @@ -1,6 +1,6 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { TypeTag } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/index.js'; export const AVM_OPERAND_BYTE_LENGTH = 4; export const AVM_OPCODE_BYTE_LENGTH = 1; @@ -9,7 +9,7 @@ export const AVM_OPCODE_BYTE_LENGTH = 1; * Opcode base class */ export abstract class Instruction { - abstract execute(machineState: AvmMachineState, stateManager: AvmStateManager): void; + abstract execute(machineState: AvmMachineState, journal: AvmJournal): void; incrementPc(machineState: AvmMachineState): void { machineState.pc++; 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 5c3edb9e379..8b1b7d101f8 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -4,22 +4,22 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { Field, TypeTag, Uint8, Uint16, Uint32, Uint64, Uint128 } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; +import { AvmJournal } from '../journal/journal.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Memory instructions', () => { let machineState: AvmMachineState; - let stateManager = mock(); + let journal = mock(); beforeEach(() => { machineState = new AvmMachineState(initExecutionEnvironment()); - stateManager = mock(); + journal = mock(); }); describe('SET', () => { it('should correctly set value and tag (uninitialized)', () => { - new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT16).execute(machineState, stateManager); + new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT16).execute(machineState, journal); const actual = machineState.memory.get(1); const tag = machineState.memory.getTag(1); @@ -31,7 +31,7 @@ describe('Memory instructions', () => { it('should correctly set value and tag (overwriting)', () => { machineState.memory.set(1, new Field(27)); - new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT32).execute(machineState, stateManager); + new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT32).execute(machineState, journal); const actual = machineState.memory.get(1); const tag = machineState.memory.getTag(1); @@ -55,7 +55,7 @@ describe('Memory instructions', () => { new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.UINT64), new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.UINT128), new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.UINT128), - ].forEach(i => i.execute(machineState, stateManager)); + ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ @@ -82,7 +82,7 @@ describe('Memory instructions', () => { new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.UINT16), new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.UINT32), new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.UINT64), - ].forEach(i => i.execute(machineState, stateManager)); + ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ @@ -109,7 +109,7 @@ describe('Memory instructions', () => { new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.FIELD), new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.FIELD), new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.FIELD), - ].forEach(i => i.execute(machineState, stateManager)); + ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ @@ -136,7 +136,7 @@ describe('Memory instructions', () => { new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.UINT32), new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.UINT64), new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.UINT128), - ].forEach(i => i.execute(machineState, stateManager)); + ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ @@ -153,7 +153,7 @@ describe('Memory instructions', () => { it('Should cast between field elements', () => { machineState.memory.set(0, new Field(12345678n)); - new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 1, TypeTag.FIELD).execute(machineState, stateManager); + new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 1, TypeTag.FIELD).execute(machineState, journal); const actual = machineState.memory.get(1); expect(actual).toEqual(new Field(12345678n)); @@ -165,7 +165,7 @@ describe('Memory instructions', () => { describe('MOV', () => { it('Should move integrals on different memory cells', () => { machineState.memory.set(1, new Uint16(27)); - new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, stateManager); + new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); const actual = machineState.memory.get(2); const tag = machineState.memory.getTag(2); @@ -176,7 +176,7 @@ describe('Memory instructions', () => { it('Should move field elements on different memory cells', () => { machineState.memory.set(1, new Field(27)); - new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, stateManager); + new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); const actual = machineState.memory.get(2); const tag = machineState.memory.getTag(2); @@ -192,7 +192,7 @@ describe('Memory instructions', () => { machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(2)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, stateManager); + new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -205,7 +205,7 @@ describe('Memory instructions', () => { machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(0)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, stateManager); + new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -218,7 +218,7 @@ describe('Memory instructions', () => { machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(1)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, stateManager); + new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -231,7 +231,7 @@ describe('Memory instructions', () => { machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(0)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, stateManager); + new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -246,7 +246,7 @@ describe('Memory instructions', () => { 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); + new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 0, /*dstOffset=*/ 0).execute(machineState, journal); const actual = machineState.memory.get(0); expect(actual).toEqual(new Uint16(12)); @@ -257,7 +257,7 @@ describe('Memory instructions', () => { machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(machineState, stateManager); + new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(machineState, journal); const actual = machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 3); expect(actual).toEqual([new Field(1), new Field(2), new Field(3)]); @@ -268,7 +268,7 @@ describe('Memory instructions', () => { machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - new CalldataCopy(/*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(machineState, stateManager); + new CalldataCopy(/*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(machineState, journal); const actual = machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 2); expect(actual).toEqual([new Field(2), new Field(3)]); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts index 5645246b962..16aa2327db4 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts @@ -1,6 +1,6 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { Field, TaggedMemory, TypeTag } from '../avm_memory_types.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/index.js'; import { Instruction } from './instruction.js'; export class Set extends Instruction { @@ -11,7 +11,7 @@ export class Set extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const res = TaggedMemory.integralFromTag(this.value, this.dstTag); machineState.memory.set(this.dstOffset, res); @@ -28,7 +28,7 @@ export class Cast extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); // TODO: consider not using toBigInt() @@ -49,7 +49,7 @@ export class Mov extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); machineState.memory.set(this.dstOffset, a); @@ -66,7 +66,7 @@ export class CMov extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); const cond = machineState.memory.get(this.condOffset); @@ -86,7 +86,7 @@ export class CalldataCopy extends Instruction { super(); } - execute(machineState: AvmMachineState, _stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, _journal: AvmJournal): void { const transformedData = machineState.executionEnvironment.calldata .slice(this.cdOffset, this.cdOffset + this.copySize) .map(f => new Field(f)); 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 265bf670e20..d5fcb0da8be 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -4,17 +4,17 @@ 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 { AvmJournal } from '../journal/journal.js'; import { SLoad, SStore } from './storage.js'; describe('Storage Instructions', () => { - let stateManager: MockProxy; + let journal: MockProxy; let machineState: AvmMachineState; const address = AztecAddress.random(); beforeEach(() => { - stateManager = mock(); + journal = mock(); const executionEnvironment = initExecutionEnvironment({ address, storageAddress: address }); machineState = new AvmMachineState(executionEnvironment); @@ -27,15 +27,15 @@ describe('Storage Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - new SStore(0, 1).execute(machineState, stateManager); + new SStore(0, 1).execute(machineState, journal); - expect(stateManager.store).toBeCalledWith(address, a, b); + expect(journal.writeStorage).toBeCalledWith(address, a, b); }); it('Sload should Read into storage', async () => { // Mock response const expectedResult = new Fr(1n); - stateManager.read.mockReturnValueOnce(Promise.resolve(expectedResult)); + journal.readStorage.mockReturnValueOnce(Promise.resolve(expectedResult)); const a = new Fr(1n); const b = new Fr(2n); @@ -43,9 +43,9 @@ describe('Storage Instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - await new SLoad(0, 1).execute(machineState, stateManager); + await new SLoad(0, 1).execute(machineState, journal); - expect(stateManager.read).toBeCalledWith(address, a); + expect(journal.readStorage).toBeCalledWith(address, a); 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 3f79594cb31..c8631e515d7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts @@ -1,7 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmMachineState } from '../avm_machine_state.js'; -import { AvmStateManager } from '../avm_state_manager.js'; +import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; /** - */ @@ -13,11 +13,11 @@ export class SStore extends Instruction { super(); } - execute(machineState: AvmMachineState, stateManager: AvmStateManager): void { + execute(machineState: AvmMachineState, journal: AvmJournal): void { const slot = machineState.memory.get(this.slotOffset); const data = machineState.memory.get(this.dataOffset); - stateManager.store( + journal.writeStorage( machineState.executionEnvironment.storageAddress, new Fr(slot.toBigInt()), new Fr(data.toBigInt()), @@ -36,10 +36,10 @@ export class SLoad extends Instruction { super(); } - async execute(machineState: AvmMachineState, stateManager: AvmStateManager): Promise { + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { const slot = machineState.memory.get(this.slotOffset); - const data = stateManager.read(machineState.executionEnvironment.storageAddress, new Fr(slot.toBigInt())); + const data = journal.readStorage(machineState.executionEnvironment.storageAddress, new Fr(slot.toBigInt())); machineState.memory.set(this.destOffset, await data); From 02de79f8a1c84ed380e82d29bbd384a0ddadca49 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:43:58 +0000 Subject: [PATCH 2/9] feat: initial external calls --- .../acir-simulator/src/avm/avm_context.ts | 95 ++++++++++++- .../src/avm/avm_execution_environment.test.ts | 55 ++++++++ .../src/avm/avm_execution_environment.ts | 55 ++++++++ .../acir-simulator/src/avm/index.test.ts | 4 +- .../src/avm/interpreter/interpreter.test.ts | 16 +-- .../src/avm/interpreter/interpreter.ts | 4 +- .../src/avm/journal/journal.test.ts | 2 +- .../acir-simulator/src/avm/journal/journal.ts | 18 +-- .../src/avm/opcodes/.eslintrc.cjs | 8 ++ .../src/avm/opcodes/arithmetic.test.ts | 26 ++-- .../src/avm/opcodes/arithmetic.ts | 8 +- .../src/avm/opcodes/bitwise.test.ts | 43 +++--- .../acir-simulator/src/avm/opcodes/bitwise.ts | 12 +- .../acir-simulator/src/avm/opcodes/call.ts | 0 .../src/avm/opcodes/comparators.ts | 6 +- .../src/avm/opcodes/control_flow.test.ts | 34 ++--- .../src/avm/opcodes/control_flow.ts | 10 +- .../src/avm/opcodes/external_calls.test.ts | 130 ++++++++++++++++++ .../src/avm/opcodes/external_calls.ts | 98 +++++++++++++ .../acir-simulator/src/avm/opcodes/index.ts | 1 - .../src/avm/opcodes/instruction.ts | 2 +- .../src/avm/opcodes/instruction_set.ts | 3 +- .../src/avm/opcodes/memory.test.ts | 60 ++++---- .../acir-simulator/src/avm/opcodes/memory.ts | 10 +- .../src/avm/opcodes/storage.test.ts | 20 ++- .../acir-simulator/src/avm/opcodes/storage.ts | 13 +- 26 files changed, 598 insertions(+), 135 deletions(-) create mode 100644 yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/.eslintrc.cjs delete mode 100644 yarn-project/acir-simulator/src/avm/opcodes/call.ts create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts index 699f9365b15..aed883fef21 100644 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ b/yarn-project/acir-simulator/src/avm/avm_context.ts @@ -1,7 +1,10 @@ +import { AztecAddress, FunctionSelector } from '@aztec/circuits.js'; +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'; -import { AvmInterpreter } from './interpreter/index.js'; +import { AvmInterpreter, AvmInterpreterError } from './interpreter/index.js'; import { AvmJournal } from './journal/journal.js'; import { decodeBytecode } from './opcodes/decode_bytecode.js'; import { Instruction } from './opcodes/index.js'; @@ -30,10 +33,19 @@ export class AvmContext { * - We run the interpreter * */ - public call(): AvmMessageCallResult { + async call(): Promise { // NOTE: the following is mocked as getPublicBytecode does not exist yet - // const bytecode = journal.journal.hostStorage.contractsDb.getBytecode(this.executionEnvironment.address); - const bytecode = Buffer.from('0x01000100020003'); + const selector = new FunctionSelector(0); + const bytecode = await this.journal.hostStorage.contractsDb.getBytecode( + this.executionEnvironment.address, + selector, + ); + + // This assumes that we will not be able to send messages to accounts without code + // Pending classes and instances impl details + if (!bytecode) { + throw new NoBytecodeFoundInterpreterError(this.executionEnvironment.address); + } const instructions: Instruction[] = decodeBytecode(bytecode); @@ -42,4 +54,79 @@ export class AvmContext { return interpreter.run(); } + + /** + * Create a new forked avm context - for internal calls + */ + public newWithForkedState(): AvmContext { + const forkedState = AvmJournal.branchParent(this.journal); + return new AvmContext(this.executionEnvironment, forkedState); + } + + /** + * Create a new forked avm context - for external calls + */ + public static newWithForkedState(executionEnvironment: AvmExecutionEnvironment, journal: AvmJournal): AvmContext { + const forkedState = AvmJournal.branchParent(journal); + return new AvmContext(executionEnvironment, forkedState); + } + + /** + * Prepare a new AVM context that will be ready for an external call + * - It will fork the journal + * - It will set the correct execution Environment Variables for a call + * - Alter both address and storageAddress + * + * @param address - The contract to call + * @param executionEnvironment - The current execution environment + * @param journal - The current journal + * @returns new AvmContext instance + */ + public static prepExternalCallContext( + address: AztecAddress, + calldata: Fr[], + executionEnvironment: AvmExecutionEnvironment, + journal: AvmJournal, + ): AvmContext { + const newExecutionEnvironment = executionEnvironment.newCall(address, calldata); + const forkedState = AvmJournal.branchParent(journal); + return new AvmContext(newExecutionEnvironment, forkedState); + } + + /** + * Prepare a new AVM context that will be ready for an external static call + * - It will fork the journal + * - It will set the correct execution Environment Variables for a call + * - Alter both address and storageAddress + * + * @param address - The contract to call + * @param executionEnvironment - The current execution environment + * @param journal - The current journal + * @returns new AvmContext instance + */ + public static prepExternalStaticCallContext( + address: AztecAddress, + calldata: Fr[], + executionEnvironment: AvmExecutionEnvironment, + journal: AvmJournal, + ): AvmContext { + const newExecutionEnvironment = executionEnvironment.newStaticCall(address, calldata); + const forkedState = AvmJournal.branchParent(journal); + return new AvmContext(newExecutionEnvironment, forkedState); + } + + /** + * Merge the journal of this call with it's parent + * NOTE: this should never be called on a root context - only from within a nested call + */ + public mergeJournal() { + this.journal.mergeWithParent(); + } +} + +class NoBytecodeFoundInterpreterError extends AvmInterpreterError { + constructor(contractAddress: AztecAddress) { + super(`No bytecode found at: ${contractAddress}`); + this.name = 'NoBytecodeFoundInterpreterError'; + } } diff --git a/yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts b/yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts new file mode 100644 index 00000000000..bf792862c8d --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts @@ -0,0 +1,55 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { initExecutionEnvironment } from './fixtures/index.js'; + +describe('Execution Environment', () => { + const newAddress = new Fr(123456n); + const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; + + it('New call should fork execution environment correctly', () => { + const executionEnvironment = initExecutionEnvironment(); + const newExecutionEnvironment = executionEnvironment.newCall(newAddress, calldata); + + allTheSameExcept(executionEnvironment, newExecutionEnvironment, { + address: newAddress, + storageAddress: newAddress, + calldata, + }); + }); + + it('New delegate call should fork execution environment correctly', () => { + const executionEnvironment = initExecutionEnvironment(); + const newExecutionEnvironment = executionEnvironment.newDelegateCall(newAddress, calldata); + + allTheSameExcept(executionEnvironment, newExecutionEnvironment, { + address: newAddress, + isDelegateCall: true, + calldata, + }); + }); + + it('New static call call should fork execution environment correctly', () => { + const executionEnvironment = initExecutionEnvironment(); + const newExecutionEnvironment = executionEnvironment.newStaticCall(newAddress, calldata); + + allTheSameExcept(executionEnvironment, newExecutionEnvironment, { + address: newAddress, + storageAddress: newAddress, + isStaticCall: true, + calldata, + }); + }); +}); + +/** + * Check all properties of one object are the same, except for the specified differentProperties + */ +function allTheSameExcept(referenceObject: any, comparingObject: any, differentProperties: Record): void { + for (const key in referenceObject) { + if (Object.keys(differentProperties).includes(key)) { + expect(comparingObject[key]).toEqual(differentProperties[key]); + } else { + expect(comparingObject[key]).toEqual(referenceObject[key]); + } + } +} 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 495a579feab..6c921bd08e9 100644 --- a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts @@ -7,6 +7,7 @@ import { Fr } from '@aztec/foundation/fields'; * Contains variables that remain constant during AVM execution * These variables are provided by the public kernel circuit */ +// TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): gas not implemented export class AvmExecutionEnvironment { constructor( /** - */ @@ -36,4 +37,58 @@ export class AvmExecutionEnvironment { /** - */ public readonly calldata: Fr[], ) {} + + public newCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { + return new AvmExecutionEnvironment( + /*address=*/ address, + /*storageAddress=*/ address, + this.origin, + this.sender, + this.portal, + this.feePerL1Gas, + this.feePerL2Gas, + this.feePerDaGas, + this.contractCallDepth, + this.globals, + this.isStaticCall, + this.isDelegateCall, + /*calldata=*/ calldata, + ); + } + + public newStaticCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { + return new AvmExecutionEnvironment( + /*address=*/ address, + /*storageAddress=*/ address, + this.origin, + this.sender, + this.portal, + this.feePerL1Gas, + this.feePerL2Gas, + this.feePerDaGas, + this.contractCallDepth, + this.globals, + /*isStaticCall=*/ true, + this.isDelegateCall, + /*calldata=*/ calldata, + ); + } + + public newDelegateCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { + return new AvmExecutionEnvironment( + /*address=*/ address, + this.storageAddress, + this.origin, + this.sender, + this.portal, + this.feePerL1Gas, + this.feePerL2Gas, + this.feePerDaGas, + this.contractCallDepth, + this.globals, + this.isStaticCall, + /*isDelegateCall=*/ true, + /*calldata=*/ calldata, + ); + } } diff --git a/yarn-project/acir-simulator/src/avm/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts index 282afcc901e..b43318d72ae 100644 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ b/yarn-project/acir-simulator/src/avm/index.test.ts @@ -11,7 +11,7 @@ import { encodeToBytecode } from './opcodes/encode_to_bytecode.js'; import { Opcode } from './opcodes/opcodes.js'; describe('avm', () => { - it('Should execute bytecode', () => { + it('Should execute bytecode', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; const journal = mock(); @@ -31,7 +31,7 @@ describe('avm', () => { // Execute instructions const context = new AvmMachineState(initExecutionEnvironment({ calldata })); const interpreter = new AvmInterpreter(context, journal, instructions); - const avmReturnData = interpreter.run(); + const avmReturnData = await interpreter.run(); expect(avmReturnData.reverted).toBe(false); 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 39b8092dabf..7ecaf130942 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -18,7 +18,7 @@ describe('interpreter', () => { journal = mock(); }); - it('Should execute a series of instructions', () => { + it('Should execute a series of instructions', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; const instructions: Instruction[] = [ @@ -27,26 +27,26 @@ describe('interpreter', () => { new Return(/*returnOffset=*/ 2, /*copySize=*/ 1), ]; - const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(context, journal, instructions); - const avmReturnData = interpreter.run(); + const machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); + const interpreter = new AvmInterpreter(machineState, journal, instructions); + const avmReturnData = await interpreter.run(); expect(avmReturnData.reverted).toBe(false); expect(avmReturnData.revertReason).toBeUndefined(); expect(avmReturnData.output).toEqual([new Fr(3)]); }); - it('Should revert with an invalid jump', () => { + it('Should revert with an invalid jump', async () => { const calldata: Fr[] = []; const invalidJumpDestination = 22; const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; - const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const interpreter = new AvmInterpreter(context, journal, instructions); + const machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); + const interpreter = new AvmInterpreter(machineState, journal, instructions); - const avmReturnData = interpreter.run(); + const avmReturnData = await interpreter.run(); expect(avmReturnData.reverted).toBe(true); expect(avmReturnData.revertReason).toBeInstanceOf(InvalidProgramCounterError); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts index f8aa30fed67..75b90eb5d0c 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts @@ -29,7 +29,7 @@ export class AvmInterpreter { * - reverted execution will return false * - any other panic will throw */ - run(): AvmMessageCallResult { + async run(): Promise { assert(this.instructions.length > 0); try { @@ -37,7 +37,7 @@ export class AvmInterpreter { const instruction = this.instructions[this.machineState.pc]; assert(!!instruction); // This should never happen - instruction.execute(this.machineState, this.journal); + await instruction.execute(this.machineState, this.journal); if (this.machineState.pc >= this.instructions.length) { throw new InvalidProgramCounterError(this.machineState.pc, /*max=*/ this.instructions.length); diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.test.ts b/yarn-project/acir-simulator/src/avm/journal/journal.test.ts index a11a3b38743..1d5d0d08671 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.test.ts @@ -29,7 +29,7 @@ describe('journal', () => { journal.writeStorage(contractAddress, key, value); const journalUpdates: JournalData = journal.flush(); - expect(journalUpdates.storageWrites.get(contractAddress)?.get(key)).toEqual(value); + expect(journalUpdates.storageWrites.get(contractAddress.toBigInt())?.get(key.toBigInt())).toEqual(value); }); it('When reading from storage, should check the parent first', async () => { diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.ts b/yarn-project/acir-simulator/src/avm/journal/journal.ts index cb69b3c33ef..62670b8f2f7 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.ts @@ -14,7 +14,7 @@ export type JournalData = { /** - */ newNullifiers: Fr[]; /** contract address -\> key -\> value */ - storageWrites: Map>; + storageWrites: Map>; }; /** @@ -32,7 +32,7 @@ export class AvmJournal { // Reading state - must be tracked for vm execution // contract address -> key -> value // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3999) - private storageReads: Map> = new Map(); + private storageReads: Map> = new Map(); // New written state private newCommitments: Fr[] = []; @@ -43,7 +43,7 @@ export class AvmJournal { private newLogs: Fr[][] = []; // contract address -> key -> value - private storageWrites: Map> = new Map(); + private storageWrites: Map> = new Map(); private parentJournal: AvmJournal | undefined; @@ -76,12 +76,12 @@ export class AvmJournal { * @param value - */ public writeStorage(contractAddress: Fr, key: Fr, value: Fr) { - let contractMap = this.storageWrites.get(contractAddress); + let contractMap = this.storageWrites.get(contractAddress.toBigInt()); if (!contractMap) { contractMap = new Map(); - this.storageWrites.set(contractAddress, contractMap); + this.storageWrites.set(contractAddress.toBigInt(), contractMap); } - contractMap.set(key, value); + contractMap.set(key.toBigInt(), value); } /** @@ -93,7 +93,7 @@ export class AvmJournal { * @returns current value */ public readStorage(contractAddress: Fr, key: Fr): Promise { - const cachedValue = this.storageWrites.get(contractAddress)?.get(key); + const cachedValue = this.storageWrites.get(contractAddress.toBigInt())?.get(key.toBigInt()); if (cachedValue) { return Promise.resolve(cachedValue); } @@ -168,7 +168,7 @@ export class AvmJournal { * @param hostMap - The map to be merged into * @param childMap - The map to be merged from */ -function mergeContractMaps(hostMap: Map>, childMap: Map>) { +function mergeContractMaps(hostMap: Map>, childMap: Map>) { for (const [key, value] of childMap) { const map1Value = hostMap.get(key); if (!map1Value) { @@ -184,7 +184,7 @@ function mergeContractMaps(hostMap: Map>, childMap: Map, childMap: Map) { +function mergeStorageMaps(hostMap: Map, childMap: Map) { for (const [key, value] of childMap) { hostMap.set(key, value); } diff --git a/yarn-project/acir-simulator/src/avm/opcodes/.eslintrc.cjs b/yarn-project/acir-simulator/src/avm/opcodes/.eslintrc.cjs new file mode 100644 index 00000000000..b972e1a3de3 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/.eslintrc.cjs @@ -0,0 +1,8 @@ +const baseConfig = require('@aztec/foundation/eslint'); +module.exports = { + ...baseConfig, + rules: { + ...baseConfig.rules, + 'require-await': 'off', + }, +}; 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 6dddce70aac..123e0a0a064 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -10,34 +10,34 @@ describe('Arithmetic Instructions', () => { let machineState: AvmMachineState; let journal: MockProxy; - beforeEach(() => { + beforeEach(async () => { machineState = new AvmMachineState(initExecutionEnvironment()); journal = mock(); }); describe('Add', () => { - it('Should add correctly over field elements', () => { + it('Should add correctly over field elements', async () => { const a = new Field(1n); const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Add(0, 1, 2).execute(machineState, journal); + await new Add(0, 1, 2).execute(machineState, journal); const expected = new Field(3n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should wrap around on addition', () => { + it('Should wrap around on addition',async () => { const a = new Field(1n); const b = new Field(Field.MODULUS - 1n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Add(0, 1, 2).execute(machineState, journal); + await new Add(0, 1, 2).execute(machineState, journal); const expected = new Field(0n); const actual = machineState.memory.get(2); @@ -46,14 +46,14 @@ describe('Arithmetic Instructions', () => { }); describe('Sub', () => { - it('Should subtract correctly over field elements', () => { + it('Should subtract correctly over field elements',async () => { const a = new Field(1n); const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Sub(0, 1, 2).execute(machineState, journal); + await new Sub(0, 1, 2).execute(machineState, journal); const expected = new Field(Field.MODULUS - 1n); const actual = machineState.memory.get(2); @@ -62,28 +62,28 @@ describe('Arithmetic Instructions', () => { }); describe('Mul', () => { - it('Should multiply correctly over field elements', () => { + it('Should multiply correctly over field elements', async () => { const a = new Field(2n); const b = new Field(3n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Mul(0, 1, 2).execute(machineState, journal); + await new Mul(0, 1, 2).execute(machineState, journal); const expected = new Field(6n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should wrap around on multiplication', () => { + it('Should wrap around on multiplication', async () => { const a = new Field(2n); const b = new Field(Field.MODULUS / 2n - 1n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Mul(0, 1, 2).execute(machineState, journal); + await new Mul(0, 1, 2).execute(machineState, journal); const expected = new Field(Field.MODULUS - 3n); const actual = machineState.memory.get(2); @@ -92,14 +92,14 @@ describe('Arithmetic Instructions', () => { }); describe('Div', () => { - it('Should perform field division', () => { + it('Should perform field division', async () => { const a = new Field(2n); const b = new Field(3n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Div(0, 1, 2).execute(machineState, journal); + await new Div(0, 1, 2).execute(machineState, journal); // Note const actual = machineState.memory.get(2); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts index d6b5bc2bccb..507430feae7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts @@ -10,7 +10,7 @@ export class Add extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -29,7 +29,7 @@ export class Sub extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -48,7 +48,7 @@ export class Mul extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -68,7 +68,7 @@ export class Div extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); 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 4c791379c7e..bb7831b8d5f 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -10,16 +10,16 @@ describe('Bitwise instructions', () => { let machineState: AvmMachineState; let journal: MockProxy; - beforeEach(() => { + beforeEach(async () => { machineState = new AvmMachineState(initExecutionEnvironment()); journal = mock(); }); - it('Should AND correctly over integral types', () => { + it('Should AND correctly over integral types', async () => { machineState.memory.set(0, new Uint32(0b11111110010011100100n)); machineState.memory.set(1, new Uint32(0b11100100111001001111n)); - new And(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new And(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const actual = machineState.memory.get(2); expect(actual).toEqual(new Uint32(0b11100100010001000100n)); @@ -39,14 +39,14 @@ describe('Bitwise instructions', () => { expect(actual).toEqual(expected); }); - it('Should XOR correctly over integral types', () => { + it('Should XOR correctly over integral types',async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Xor(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Xor(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b00011010101010101011n); const actual = machineState.memory.get(2); @@ -54,42 +54,41 @@ describe('Bitwise instructions', () => { }); describe('SHR', () => { - it('Should shift correctly 0 positions over integral types', () => { + it('Should shift correctly 0 positions over integral types',async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = a; const actual = machineState.memory.get(2); - expect(actual).toEqual(expected); }); - it('Should shift correctly 2 positions over integral types', () => { + it('Should shift correctly 2 positions over integral types',async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b00111111100100111001n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should shift correctly 19 positions over integral types', () => { + it('Should shift correctly 19 positions over integral types',async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(19n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b01n); const actual = machineState.memory.get(2); @@ -98,56 +97,56 @@ describe('Bitwise instructions', () => { }); describe('SHL', () => { - it('Should shift correctly 0 positions over integral types', () => { + it('Should shift correctly 0 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = a; const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should shift correctly 2 positions over integral types', () => { + it('Should shift correctly 2 positions over integral types',async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); const expected = new Uint32(0b1111111001001110010000n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should shift correctly over bit limit over integral types', () => { + it('Should shift correctly over bit limit over integral types', async () => { const a = new Uint16(0b1110010011100111n); const b = new Uint16(17n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); + await new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); const expected = new Uint16(0n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should truncate when shifting over bit size over integral types', () => { + it('Should truncate when shifting over bit size over integral types',async () => { const a = new Uint16(0b1110010011100111n); const b = new Uint16(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); + await new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); const expected = new Uint16(0b1001001110011100n); const actual = machineState.memory.get(2); @@ -155,12 +154,12 @@ describe('Bitwise instructions', () => { }); }); - it('Should NOT correctly over integral types', () => { + it('Should NOT correctly over integral types',async () => { const a = new Uint16(0b0110010011100100n); machineState.memory.set(0, a); - new Not(0, 1, TypeTag.UINT16).execute(machineState, journal); + await new Not(0, 1, TypeTag.UINT16).execute(machineState, journal); const expected = new Uint16(0b1001101100011011n); // high bits! const actual = machineState.memory.get(1); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts index 7d7f881bbf9..31420d0b3bc 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts @@ -11,7 +11,7 @@ export class And extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -32,7 +32,7 @@ export class Or extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -53,7 +53,7 @@ export class Xor extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -74,7 +74,7 @@ export class Not extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { Instruction.checkTags(machineState, this.inTag, this.aOffset); const a = machineState.memory.getAs(this.aOffset); @@ -94,7 +94,7 @@ export class Shl extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); @@ -115,7 +115,7 @@ export class Shr extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); const a = machineState.memory.getAs(this.aOffset); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/call.ts b/yarn-project/acir-simulator/src/avm/opcodes/call.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts index d9a4c48d867..8bdb406f9c6 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts @@ -11,7 +11,7 @@ export class Eq extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -30,7 +30,7 @@ export class Lt extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); @@ -49,7 +49,7 @@ export class Lte extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); 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 75a46347f61..ca4cdd45a5c 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 @@ -20,17 +20,17 @@ describe('Control Flow Opcodes', () => { machineState = new AvmMachineState(initExecutionEnvironment()); }); - it('Should implement JUMP', () => { + it('Should implement JUMP', async () => { const jumpLocation = 22; expect(machineState.pc).toBe(0); const instruction = new Jump(jumpLocation); - instruction.execute(machineState, journal); + await instruction.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation); }); - it('Should implement JUMPI - truthy', () => { + it('Should implement JUMPI - truthy', async () => { const jumpLocation = 22; const jumpLocation1 = 69; @@ -40,16 +40,16 @@ describe('Control Flow Opcodes', () => { machineState.memory.set(1, new Uint16(2n)); const instruction = new JumpI(jumpLocation, 0); - instruction.execute(machineState, journal); + await instruction.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation); // Truthy can be greater than 1 const instruction1 = new JumpI(jumpLocation1, 1); - instruction1.execute(machineState, journal); + await instruction1.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation1); }); - it('Should implement JUMPI - falsy', () => { + it('Should implement JUMPI - falsy', async () => { const jumpLocation = 22; expect(machineState.pc).toBe(0); @@ -57,11 +57,11 @@ describe('Control Flow Opcodes', () => { machineState.memory.set(0, new Uint16(0n)); const instruction = new JumpI(jumpLocation, 0); - instruction.execute(machineState, journal); + await instruction.execute(machineState, journal); expect(machineState.pc).toBe(1); }); - it('Should implement Internal Call and Return', () => { + it('Should implement Internal Call and Return', async () => { const jumpLocation = 22; expect(machineState.pc).toBe(0); @@ -69,14 +69,14 @@ describe('Control Flow Opcodes', () => { const instruction = new InternalCall(jumpLocation); const returnInstruction = new InternalReturn(); - instruction.execute(machineState, journal); + await instruction.execute(machineState, journal); expect(machineState.pc).toBe(jumpLocation); - returnInstruction.execute(machineState, journal); + await returnInstruction.execute(machineState, journal); expect(machineState.pc).toBe(1); }); - it('Should chain series of control flow instructions', () => { + it('Should chain series of control flow instructions', async () => { const jumpLocation0 = 22; const jumpLocation1 = 69; const jumpLocation2 = 1337; @@ -106,17 +106,17 @@ describe('Control Flow Opcodes', () => { ]; for (let i = 0; i < instructions.length; i++) { - instructions[i].execute(machineState, journal); + await instructions[i].execute(machineState, journal); expect(machineState.pc).toBe(expectedPcs[i]); } }); - it('Should error if Internal Return is called without a corresponding Internal Call', () => { - const returnInstruction = new InternalReturn(); - expect(() => returnInstruction.execute(machineState, journal)).toThrow(InstructionExecutionError); + it('Should error if Internal Return is called without a corresponding Internal Call', async () => { + const returnInstruction = () => new InternalReturn().execute(machineState, journal); + await expect(returnInstruction()).rejects.toThrow(InstructionExecutionError); }); - it('Should increment PC on All other Instructions', () => { + it('Should increment PC on All other Instructions', async () => { const instructions = [ new Add(0, 1, 2), new Sub(0, 1, 2), @@ -144,7 +144,7 @@ describe('Control Flow Opcodes', () => { innerMachineState.memory.set(1, new Uint16(8n)); innerMachineState.memory.set(2, new Uint16(12n)); expect(machineState.pc).toBe(0); - instruction.execute(innerMachineState, journal); + await instruction.execute(innerMachineState, journal); expect(innerMachineState.pc).toBe(1); } }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts index 95c9e12dcdb..518b987a1de 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts @@ -13,7 +13,7 @@ export class Return extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const returnData = machineState.memory .getSlice(this.returnOffset, this.copySize) .map(fvt => new Fr(fvt.toBigInt())); @@ -32,7 +32,7 @@ export class Jump extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { machineState.pc = this.jumpOffset; } } @@ -45,7 +45,7 @@ export class JumpI extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const condition = machineState.memory.getAs(this.condOffset); // TODO: reconsider this casting @@ -65,7 +65,7 @@ export class InternalCall extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { machineState.internalCallStack.push(machineState.pc + 1); machineState.pc = this.jumpOffset; } @@ -79,7 +79,7 @@ export class InternalReturn extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const jumpOffset = machineState.internalCallStack.pop(); if (jumpOffset === undefined) { throw new InstructionExecutionError('Internal call empty!'); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts new file mode 100644 index 00000000000..33919aba032 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts @@ -0,0 +1,130 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { jest } from '@jest/globals'; +import { MockProxy, mock } from 'jest-mock-extended'; + +import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; +import { AvmMachineState } from '../avm_machine_state.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; +import { HostStorage } from '../journal/host_storage.js'; +import { AvmJournal } from '../journal/journal.js'; +import { encodeToBytecode } from './encode_to_bytecode.js'; +import { Call } from './external_calls.js'; +import { Opcode } from './opcodes.js'; + +describe('External Calls', () => { + let machineState: AvmMachineState; + let journal: AvmJournal; + + let contractsDb: MockProxy; + + beforeEach(() => { + machineState = new AvmMachineState(initExecutionEnvironment()); + + contractsDb = mock(); + + const commitmentsDb = mock(); + const publicStateDb = mock(); + const hostStorage = new HostStorage(publicStateDb, contractsDb, commitmentsDb); + journal = new AvmJournal(hostStorage); + }); + + describe('Call', () => { + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): gas not implemented + it('Should execute a call correctly', async () => { + const gasOffset = 0; + const gas = Fr.zero(); + + const addrOffset = 1; + const addr = new Fr(123456n); + + const argsOffset = 2; + const args = [new Fr(1n), new Fr(2n), new Fr(3n)]; + const argsSize = args.length; + + const retOffset = 8; + const retSize = 2; + + const successOffset = 7; + + machineState.memory.set(0, gas); + machineState.memory.set(1, addr); + machineState.memory.setSlice(2, args); + + const otherContextInstructions: [Opcode, any[]][] = [ + // Place [1,2,3] into memory + [Opcode.CALLDATACOPY, [/*value=*/ 0, /*copySize=*/ argsSize, /*destOffset=*/ 0]], + // Store 1 into slot 1 + [Opcode.SSTORE, [/*slotOffset=*/ 0, /*dataOffset=*/ 0]], + // Return [1,2] from memory + [Opcode.RETURN, [/*retOffset=*/ 0, /*size=*/ 2]], + ]; + + const otherContextInstructionsBytecode = Buffer.concat( + otherContextInstructions.map(([opcode, args]) => encodeToBytecode(opcode, args)), + ); + jest + .spyOn(journal.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); + + const instruction = new Call(gasOffset, addrOffset, argsOffset, argsSize, retOffset, retSize, successOffset); + await instruction.execute(machineState, journal); + + const successValue = machineState.memory.get(successOffset); + expect(successValue).toEqual(new Fr(1n)); + + const retValue = machineState.memory.getSlice(retOffset, retSize); + expect(retValue).toEqual([new Fr(1n), new Fr(2n)]); + + // Check that the storage call has been merged into the parent journal + const { storageWrites } = journal.flush(); + expect(storageWrites.size).toEqual(1); + + const nestedContractWrites = storageWrites.get(addr.toBigInt()); + expect(nestedContractWrites).toBeDefined(); + + const slotNumber = 1n; + const expectedStoredValue = new Fr(1n); + expect(nestedContractWrites!.get(slotNumber)).toEqual(expectedStoredValue); + }); + }); + + describe('Static Call', () => { + it('Should fail if a static call attempts to touch storage', async () => { + const gasOffset = 0; + const gas = Fr.zero(); + const addrOffset = 1; + const addr = new Fr(123456n); + const argsOffset = 2; + const args = [new Fr(1n), new Fr(2n), new Fr(3n)]; + + const argsSize = args.length; + const retOffset = 8; + const retSize = 2; + const successOffset = 7; + + machineState.memory.set(0, gas); + machineState.memory.set(1, addr); + machineState.memory.setSlice(2, args); + + const otherContextInstructions: [Opcode, any[]][] = [ + [Opcode.SET, [/* value */ 1, /* destOffset */ 1]], + [Opcode.SSTORE, [/* slotOffset */ 1, /* dataOffset */ 0]], + ]; + + const otherContextInstructionsBytecode = Buffer.concat( + otherContextInstructions.map(([opcode, args]) => encodeToBytecode(opcode, args)), + ); + jest + .spyOn(journal.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); + + const instruction = new Call(gasOffset, addrOffset, argsOffset, argsSize, retOffset, retSize, successOffset); + await instruction.execute(machineState, journal); + + // No revert has occurred, but the nested execution has failed + const successValue = machineState.memory.get(successOffset); + expect(successValue).toEqual(new Fr(0n)); + }); + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts new file mode 100644 index 00000000000..38180dce916 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts @@ -0,0 +1,98 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { AvmContext } from '../avm_context.js'; +import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmJournal } from '../journal/journal.js'; +import { Instruction } from './instruction.js'; +import { Field } from '../avm_memory_types.js'; + +export class Call extends Instruction { + static type: string = 'CALL'; + static numberOfOperands = 7; + + constructor( + private /* Unused due to no formal gas implementation at this moment */ _gasOffset: number, + private addrOffset: number, + private argsOffset: number, + private argSize: number, + private retOffset: number, + private retSize: number, + private successOffset: number, + ) { + super(); + } + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): there is no concept of remaining / available gas at this moment + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + const callAddress = machineState.memory.getAs(this.addrOffset); + const calldata = machineState.memory.getSlice(this.argsOffset, this.argSize).map(f => new Fr(f.toBigInt())); + + const avmContext = AvmContext.prepExternalCallContext( + new Fr(callAddress.toBigInt()), + calldata, + machineState.executionEnvironment, + journal, + ); + + const returnObject = await avmContext.call(); + const success = !returnObject.reverted; + + // We only take as much data as was specified in the return size -> TODO: should we be reverting here + const returnData = returnObject.output.slice(0, this.retSize); + + // Write our return data into memory + machineState.memory.set(this.successOffset, new Fr(success)); + machineState.memory.setSlice(this.retOffset, returnData); + + if (success) { + avmContext.mergeJournal(); + } + + this.incrementPc(machineState); + } +} + +export class StaticCall extends Instruction { + static type: string = 'STATICCALL'; + static numberOfOperands = 7; + + constructor( + private /* Unused due to no formal gas implementation at this moment */ _gasOffset: number, + private addrOffset: number, + private argsOffset: number, + private argSize: number, + private retOffset: number, + private retSize: number, + private successOffset: number, + ) { + super(); + } + + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + const callAddress = machineState.memory.get(this.addrOffset); + const calldata = machineState.memory.getSlice(this.argsOffset, this.argSize).map(f => new Fr(f.toBigInt())); + + const avmContext = AvmContext.prepExternalStaticCallContext( + new Fr(callAddress.toBigInt()), + calldata, + machineState.executionEnvironment, + journal, + ); + + const returnObject = await avmContext.call(); + const success = !returnObject.reverted; + + // We only take as much data as was specified in the return size -> TODO: should we be reverting here + const returnData = returnObject.output.slice(0, this.retSize); + + // Write our return data into memory + machineState.memory.set(this.successOffset, new Fr(success)); + machineState.memory.setSlice(this.retOffset, returnData); + + if (success) { + avmContext.mergeJournal(); + } + + this.incrementPc(machineState); + } +} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/index.ts b/yarn-project/acir-simulator/src/avm/opcodes/index.ts index f1f479bab46..10ce6b4d0f7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/index.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/index.ts @@ -1,6 +1,5 @@ export * from './arithmetic.js'; export * from './control_flow.js'; -export * from './call.js'; export * from './instruction.js'; export * from './comparators.js'; export * from './memory.js'; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts index 03e362018ec..4878019b5f0 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts @@ -9,7 +9,7 @@ export const AVM_OPCODE_BYTE_LENGTH = 1; * Opcode base class */ export abstract class Instruction { - abstract execute(machineState: AvmMachineState, journal: AvmJournal): void; + abstract execute(machineState: AvmMachineState, journal: AvmJournal): Promise; incrementPc(machineState: AvmMachineState): void { machineState.pc++; 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 3413673f7e6..9ea66060ae3 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 { InternalCall, InternalReturn, Jump, JumpI, Return } from './control_flow.js'; +// import { Call } from './external_calls.js'; import { Instruction } from './instruction.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; import { Opcode } from './opcodes.js'; @@ -87,7 +88,7 @@ export const INSTRUCTION_SET: Map = ne //[Opcode.EMITUNENCRYPTEDLOG, Emitunencryptedlog], //// Control Flow - Contract Calls - //[Opcode.CALL, Call], + // [Opcode.CALL, Call], //[Opcode.STATICCALL, Staticcall], [Opcode.RETURN, Return], //[Opcode.REVERT, Revert], 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 8b1b7d101f8..65cb6a64eba 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -1,6 +1,6 @@ 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 { Field, TypeTag, Uint8, Uint16, Uint32, Uint64, Uint128 } from '../avm_memory_types.js'; @@ -10,16 +10,16 @@ import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Memory instructions', () => { let machineState: AvmMachineState; - let journal = mock(); + let journal: MockProxy; - beforeEach(() => { + beforeEach(async () => { machineState = new AvmMachineState(initExecutionEnvironment()); journal = mock(); }); describe('SET', () => { - it('should correctly set value and tag (uninitialized)', () => { - new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT16).execute(machineState, journal); + it('should correctly set value and tag (uninitialized)',async () => { + await new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT16).execute(machineState, journal); const actual = machineState.memory.get(1); const tag = machineState.memory.getTag(1); @@ -28,10 +28,10 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('should correctly set value and tag (overwriting)', () => { + it('should correctly set value and tag (overwriting)', async () => { machineState.memory.set(1, new Field(27)); - new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT32).execute(machineState, journal); + await new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT32).execute(machineState, journal); const actual = machineState.memory.get(1); const tag = machineState.memory.getTag(1); @@ -150,10 +150,10 @@ describe('Memory instructions', () => { expect(tags).toEqual([TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128]); }); - it('Should cast between field elements', () => { + it('Should cast between field elements',async () => { machineState.memory.set(0, new Field(12345678n)); - new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 1, TypeTag.FIELD).execute(machineState, journal); + await new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 1, TypeTag.FIELD).execute(machineState, journal); const actual = machineState.memory.get(1); expect(actual).toEqual(new Field(12345678n)); @@ -163,9 +163,9 @@ describe('Memory instructions', () => { }); describe('MOV', () => { - it('Should move integrals on different memory cells', () => { + it('Should move integrals on different memory cells', async () => { machineState.memory.set(1, new Uint16(27)); - new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); + await new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); const actual = machineState.memory.get(2); const tag = machineState.memory.getTag(2); @@ -174,9 +174,9 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('Should move field elements on different memory cells', () => { + it('Should move field elements on different memory cells',async () => { machineState.memory.set(1, new Field(27)); - new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); + await new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); const actual = machineState.memory.get(2); const tag = machineState.memory.getTag(2); @@ -187,12 +187,15 @@ describe('Memory instructions', () => { }); describe('CMOV', () => { - it('Should move A if COND is true, on different memory cells (integral condition)', () => { + it('Should move A if COND is true, on different memory cells (integral condition)',async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(2)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( + machineState, + journal, + ); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -200,12 +203,15 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT32); }); - it('Should move B if COND is false, on different memory cells (integral condition)', () => { + it('Should move B if COND is false, on different memory cells (integral condition)',async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(0)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( + machineState, + journal, + ); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -213,12 +219,12 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('Should move A if COND is true, on different memory cells (field condition)', () => { + it('Should move A if COND is true, on different memory cells (field condition)',async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(1)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -226,12 +232,12 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT32); }); - it('Should move B if COND is false, on different memory cells (integral condition)', () => { + it('Should move B if COND is false, on different memory cells (integral condition)',async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(0)); // Condition - new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -241,34 +247,34 @@ describe('Memory instructions', () => { }); describe('CALLDATACOPY', () => { - it('Writes nothing if size is 0', () => { + it('Writes nothing if size is 0',async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; 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, journal); + await new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 0, /*dstOffset=*/ 0).execute(machineState, journal); const actual = machineState.memory.get(0); expect(actual).toEqual(new Uint16(12)); }); - it('Copies all calldata', () => { + it('Copies all calldata',async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(machineState, journal); + await new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(machineState, journal); const actual = machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 3); expect(actual).toEqual([new Field(1), new Field(2), new Field(3)]); }); - it('Copies slice of calldata', () => { + it('Copies slice of calldata',async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - new CalldataCopy(/*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(machineState, journal); + await new CalldataCopy(/*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(machineState, journal); const actual = machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 2); expect(actual).toEqual([new Field(2), new Field(3)]); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts index 16aa2327db4..3ba63a633a7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts @@ -11,7 +11,7 @@ export class Set extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const res = TaggedMemory.integralFromTag(this.value, this.dstTag); machineState.memory.set(this.dstOffset, res); @@ -28,7 +28,7 @@ export class Cast extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); // TODO: consider not using toBigInt() @@ -49,7 +49,7 @@ export class Mov extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); machineState.memory.set(this.dstOffset, a); @@ -66,7 +66,7 @@ export class CMov extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); const cond = machineState.memory.get(this.condOffset); @@ -86,7 +86,7 @@ export class CalldataCopy extends Instruction { super(); } - execute(machineState: AvmMachineState, _journal: AvmJournal): void { + async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const transformedData = machineState.executionEnvironment.calldata .slice(this.cdOffset, this.cdOffset + this.copySize) .map(f => new Field(f)); 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 d5fcb0da8be..aadbbbb69f1 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -6,7 +6,7 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { AvmJournal } from '../journal/journal.js'; -import { SLoad, SStore } from './storage.js'; +import { SLoad, SStore, StaticCallStorageAlterError } from './storage.js'; describe('Storage Instructions', () => { let journal: MockProxy; @@ -20,18 +20,32 @@ describe('Storage Instructions', () => { machineState = new AvmMachineState(executionEnvironment); }); - it('Sstore should Write into storage', () => { + it('Sstore should Write into storage', async () => { const a = new Fr(1n); const b = new Fr(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new SStore(0, 1).execute(machineState, journal); + await new SStore(0, 1).execute(machineState, journal); expect(journal.writeStorage).toBeCalledWith(address, a, b); }); + it('Should not be able to write to storage in a static call', async () => { + const executionEnvironment = initExecutionEnvironment({ isStaticCall: true }); + machineState = new AvmMachineState(executionEnvironment); + + const a = new Fr(1n); + const b = new Fr(2n); + + machineState.memory.set(0, a); + machineState.memory.set(1, b); + + const instruction = () => new SStore(0, 1).execute(machineState, journal); + await expect(instruction()).rejects.toThrowError(StaticCallStorageAlterError); + }); + it('Sload should Read into storage', async () => { // Mock response const expectedResult = new Fr(1n); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts index c8631e515d7..a452b0c422a 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmInterpreterError } from '../interpreter/interpreter.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; @@ -13,7 +14,7 @@ export class SStore extends Instruction { super(); } - execute(machineState: AvmMachineState, journal: AvmJournal): void { + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { const slot = machineState.memory.get(this.slotOffset); const data = machineState.memory.get(this.dataOffset); @@ -46,3 +47,13 @@ export class SLoad extends Instruction { this.incrementPc(machineState); } } + +/** + * Error is thrown when a static call attempts to alter storage + */ +export class StaticCallStorageAlterError extends AvmInterpreterError { + constructor() { + super('Static calls cannot alter storage'); + this.name = 'StaticCallStorageAlterError'; + } +} From 31d47b276a7b0717e1a8a83891d1aea77bf6fdbc Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 24 Jan 2024 02:22:11 +0000 Subject: [PATCH 3/9] chore: remove stubbed docs --- .circleci/config.yml | 33 +- README.md | 2 +- aztec-up/bin/aztec | 19 +- aztec-up/bin/aztec-cli | 3 +- aztec-up/bin/aztec-install | 6 +- aztec-up/bin/docker-compose.yml | 6 +- barretenberg/.gitrepo | 4 +- barretenberg/cpp/.gitignore | 2 + .../scripts/barretenberg_module_digraph.sh | 24 + .../barretenberg_module_digraph_edges.awk | 35 + .../cpp/src/barretenberg/common/utils.cpp | 17 + .../cpp/src/barretenberg/common/utils.hpp | 17 + .../barretenberg/crypto/ecdsa/ecdsa.test.cpp | 24 +- .../dsl/acir_format/serde/acir.hpp | 141 +- .../vm/avm_trace/AvmMini_common.hpp | 4 + .../vm/avm_trace/AvmMini_execution.cpp | 238 + .../vm/avm_trace/AvmMini_execution.hpp | 28 + .../vm/avm_trace/AvmMini_instructions.hpp | 23 + .../vm/avm_trace/AvmMini_opcode.cpp | 153 + .../vm/avm_trace/AvmMini_opcode.hpp | 105 + .../vm/avm_trace/AvmMini_trace.cpp | 16 +- .../vm/avm_trace/AvmMini_trace.hpp | 11 +- .../vm/tests/AvmMini_arithmetic.test.cpp | 38 +- .../vm/tests/AvmMini_control_flow.test.cpp | 3 +- .../vm/tests/AvmMini_execution.test.cpp | 505 ++ .../vm/tests/AvmMini_memory.test.cpp | 17 +- boxes/Dockerfile | 4 +- boxes/blank-react/README.md | 2 +- boxes/blank/README.md | 2 +- boxes/blank/webpack.config.js | 1 + boxes/docker-compose.yml | 2 +- .../contracts/src/types/transparent_note.nr | 5 +- boxes/yarn.lock | 1 + build_manifest.yml | 10 +- .../history/differences_to_aztec_connect.md | 15 - .../advanced/circuits/kernels/main.md | 5 - .../concepts/advanced/data_structures/main.md | 5 - docs/docs/concepts/advanced/main.md | 5 - .../dev_docs/contracts/syntax/storage/main.md | 539 -- .../dev_docs/getting_started/core-concepts.md | 88 - .../{dev_docs => developers}/aztecjs/main.md | 0 .../{dev_docs => developers}/cli/blank_box.md | 0 .../cli/cli-commands.md | 4 +- .../docs/{dev_docs => developers}/cli/main.md | 0 .../cli/run_more_than_one_pxe_sandbox.md | 0 .../cli/sandbox-reference.md | 23 +- .../{dev_docs => developers}/contracts/abi.md | 0 .../contracts/artifacts.md | 0 .../contracts/compiling.md | 2 +- .../contracts/deploying.md | 2 +- .../contracts/example-contract.md | 0 .../contracts/layout.md | 0 .../contracts/main.md | 0 .../contracts/portals/data_structures.md | 0 .../contracts/portals/inbox.md | 0 .../contracts/portals/main.md | 2 +- .../contracts/portals/outbox.md | 0 .../contracts/portals/registry.md | 0 .../resources/common_patterns/authwit.md | 6 +- .../resources/common_patterns/main.md | 6 +- .../contracts/resources/dependencies.md | 0 .../contracts/resources/main.md | 0 .../contracts/resources/style_guide.md | 0 .../security/breaking_changes/main.md | 0 .../contracts/security/breaking_changes/v0.md | 0 .../contracts/security/main.md | 0 .../contracts/setup.md | 0 .../contracts/syntax/constrain.md | 0 .../contracts/syntax/context.mdx | 6 +- .../contracts/syntax/control_structure.md | 0 .../contracts/syntax/events.md | 0 .../contracts/syntax/functions.md | 16 +- .../contracts/syntax/globals.md | 0 .../history_lib_reference.md | 2 +- .../historical_access/how_to_prove_history.md | 2 +- .../contracts/syntax/main.md | 0 .../contracts/syntax/oracles.md | 0 .../contracts/syntax/slow_updates_tree.md | 2 +- .../contracts/syntax/storage/main.md | 133 + .../contracts/syntax/storage/private_state.md | 337 ++ .../contracts/syntax/storage/public_state.md | 95 + .../contracts/syntax/storage/storage_slots.md | 2 +- .../contracts/workflow.md | 0 .../debugging/aztecnr-errors.md | 2 +- .../debugging/main.md | 0 .../debugging/sandbox-errors.md | 12 +- .../aztecjs-getting-started.md | 6 +- .../aztecnr-getting-started.md | 4 +- .../getting_started/main.md | 2 +- .../getting_started/quickstart.md | 2 +- .../limitations/main.md | 8 +- .../{dev_docs => developers}/privacy/main.md | 0 .../testing/cheat_codes.md | 0 .../{dev_docs => developers}/testing/main.md | 0 .../tutorials/main.md | 0 .../tutorials/testing.md | 4 +- .../token_portal/cancelling_deposits.md | 0 .../token_portal/depositing_to_aztec.md | 0 .../tutorials/token_portal/main.md | 2 +- .../token_portal/minting_on_aztec.md | 0 .../tutorials/token_portal/setup.md | 2 +- .../token_portal/typescript_glue_code.md | 0 .../token_portal/withdrawing_to_l1.md | 2 +- .../uniswap/execute_private_swap_on_l1.md | 0 .../uniswap/execute_public_swap_on_l1.md | 0 .../tutorials/uniswap/l1_portal.md | 0 .../tutorials/uniswap/l2_contract_setup.md | 0 .../tutorials/uniswap/main.md | 0 .../uniswap/redeeming_swapped_assets_on_l2.md | 0 .../tutorials/uniswap/setup.md | 0 .../tutorials/uniswap/swap_privately.md | 0 .../tutorials/uniswap/swap_publicly.md | 0 .../tutorials/uniswap/typescript_glue_code.md | 0 .../writing_dapp/contract_deployment.md | 0 .../writing_dapp/contract_interaction.md | 4 +- .../tutorials/writing_dapp/main.md | 0 .../tutorials/writing_dapp/project_setup.md | 0 .../tutorials/writing_dapp/pxe_service.md | 0 .../tutorials/writing_dapp/testing.md | 2 +- .../writing_private_voting_contract.md | 6 +- .../tutorials/writing_token_contract.md | 6 +- .../docs/{dev_docs => developers}/updating.md | 2 +- .../wallets/architecture.md | 2 +- .../wallets/creating_schnorr_accounts.md | 2 +- .../{dev_docs => developers}/wallets/main.md | 12 +- .../wallets/writing_an_account_contract.md | 8 +- .../about_aztec/technical_overview.md} | 18 +- docs/docs/{ => learn}/about_aztec/vision.md | 2 +- .../about_aztec/what_is_aztec.mdx} | 6 +- .../concepts}/accounts/authwit.md | 6 +- .../concepts}/accounts/keys.md | 2 +- .../concepts}/accounts/main.md | 2 +- .../concepts}/block_production.md | 0 .../foundation => learn/concepts}/blocks.md | 0 .../circuits/kernels/private_kernel.md | 4 +- .../circuits/kernels/public_kernel.md | 2 +- .../concepts}/circuits/main.md | 2 +- .../circuits/rollup_circuits/main.md | 2 +- .../communication/cross_chain_calls.md | 0 .../concepts}/communication/main.md | 0 .../public_private_calls/main.md | 2 +- .../public_private_calls/slow_updates_tree.md | 2 +- .../foundation => learn/concepts}/globals.md | 0 .../concepts/hybrid_state}/main.md | 2 +- .../concepts/hybrid_state}/public_vm.md | 0 docs/docs/learn/concepts/main.md | 75 + .../nodes_clients/execution_client.md | 0 .../concepts}/nodes_clients/prover_client.md | 0 .../concepts/nodes_clients/sequencer/main.md} | 2 +- .../sequencer}/sequencer_selection.md | 0 .../concepts/pxe}/acir_simulator.md | 4 +- .../concepts/pxe/main.md} | 8 +- .../smart_contracts}/contract_creation.md | 4 +- .../concepts/smart_contracts/main.md} | 2 +- .../concepts/storage}/storage_slots.md | 8 +- .../storage/trees}/indexed_merkle_tree.md | 0 .../concepts/storage/trees/main.md} | 6 +- .../concepts}/transactions.md | 4 +- .../concepts}/upgrade_mechanism.md | 0 docs/docs/misc/common/_disclaimer.mdx | 2 +- .../how_to_contribute.md | 0 .../roadmap/cryptography_roadmap.md | 0 .../roadmap/engineering_roadmap.md | 2 +- .../roadmap/features_initial_ldt.md | 0 .../{about_aztec => misc}/roadmap/main.md | 0 docs/docs/{intro.md => welcome.md} | 12 +- docs/docusaurus.config.js | 4 +- docs/internal_notes/building_dapps.md | 2 +- docs/netlify.toml | 80 +- docs/sidebars.js | 356 +- l1-contracts/Dockerfile | 17 +- l1-contracts/README.md | 17 +- l1-contracts/package.json | 4 +- l1-contracts/slither.config.json | 3 + l1-contracts/slither_has_diff.sh | 12 + l1-contracts/slither_output.md | 249 + .../src/core/libraries/ConstantsGen.sol | 4 +- l1-contracts/src/core/libraries/Errors.sol | 3 + l1-contracts/src/core/libraries/HeaderLib.sol | 134 +- l1-contracts/test/Rollup.t.sol | 6 +- l1-contracts/test/decoders/Decoder.t.sol | 6 +- ...rDecoderHelper.sol => HeaderLibHelper.sol} | 2 +- l1-contracts/test/fixtures/empty_block_0.json | 2 +- l1-contracts/test/fixtures/empty_block_1.json | 8 +- l1-contracts/test/fixtures/mixed_block_0.json | 10 +- l1-contracts/test/fixtures/mixed_block_1.json | 14 +- noir/.github/ISSUE_TEMPLATE/config.yml | 4 - ...ea_action_plan.yml => feature_request.yml} | 4 +- noir/.github/scripts/wasm-bindgen-install.sh | 4 +- noir/.github/workflows/docs-pr.yml | 9 + .../.github/workflows/publish-es-packages.yml | 51 +- noir/.github/workflows/release.yml | 11 +- noir/.gitrepo | 4 +- noir/Cargo.toml | 1 - noir/acvm-repo/acir/codegen/acir.cpp | 112 +- .../acir/src/circuit/black_box_functions.rs | 5 + .../opcodes/black_box_function_call.rs | 22 +- .../acvm/src/compiler/transformers/mod.rs | 3 + noir/acvm-repo/acvm/src/lib.rs | 10 + noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs | 1 + noir/acvm-repo/brillig/src/black_box.rs | 5 + noir/acvm-repo/brillig_vm/src/black_box.rs | 2 + noir/acvm-repo/brillig_vm/src/lib.rs | 6 +- noir/acvm-repo/brillig_vm/src/memory.rs | 2 +- noir/aztec_macros/src/lib.rs | 39 +- noir/compiler/noirc_driver/src/abi_gen.rs | 2 +- noir/compiler/noirc_driver/src/contract.rs | 4 +- noir/compiler/noirc_driver/src/lib.rs | 25 +- noir/compiler/noirc_driver/tests/contracts.rs | 42 + .../brillig/brillig_gen/brillig_black_box.rs | 17 +- .../src/brillig/brillig_gen/brillig_block.rs | 33 + .../src/brillig/brillig_ir/debug_show.rs | 9 + noir/compiler/noirc_evaluator/src/errors.rs | 4 +- noir/compiler/noirc_evaluator/src/ssa.rs | 1 - .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 2 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 8 + .../noirc_evaluator/src/ssa/ir/instruction.rs | 529 +- .../src/ssa/ir/instruction/binary.rs | 349 ++ .../src/ssa/ir/instruction/call.rs | 1 + .../src/ssa/ir/instruction/cast.rs | 58 + .../src/ssa/ir/instruction/constrain.rs | 126 + .../src/ssa/opt/flatten_cfg.rs | 26 +- .../noirc_evaluator/src/ssa/ssa_gen/mod.rs | 6 +- .../noirc_frontend/src/ast/function.rs | 2 +- .../src/hir/def_collector/dc_crate.rs | 2 +- .../src/hir/resolution/resolver.rs | 21 +- .../noirc_frontend/src/hir/type_check/expr.rs | 326 +- .../noirc_frontend/src/hir/type_check/stmt.rs | 37 +- .../noirc_frontend/src/hir_def/expr.rs | 16 +- .../noirc_frontend/src/hir_def/types.rs | 112 +- .../src/monomorphization/printer.rs | 4 +- .../noirc_frontend/src/node_interner.rs | 10 +- .../noirc_frontend/src/parser/parser.rs | 43 +- .../noirc_frontend/src/resolve_locations.rs | 13 +- noir/compiler/wasm/src/compile.rs | 5 +- noir/compiler/wasm/src/compile_new.rs | 4 +- noir/cspell.json | 9 +- noir/docs/.gitignore | 2 + noir/docs/README.md | 18 +- .../hello_noir/_category_.json | 5 + .../index.md} | 10 +- .../{ => hello_noir}/project_breakdown.md | 22 +- .../getting_started/installation/index.md | 3 + .../getting_started/tooling/_category_.json | 2 +- noir/docs/docs/how_to/how-to-oracles.md | 2 +- noir/docs/docs/how_to/how-to-recursion.md | 2 +- .../docs/how_to/how-to-solidity-verifier.md | 231 + noir/docs/docs/how_to/solidity_verifier.md | 130 - noir/docs/docs/index.md | 85 - noir/docs/docs/index.mdx | 67 + .../docs/noir/concepts/data_types/arrays.md | 20 +- .../noir/standard_library/black_box_fns.md | 22 +- .../cryptographic_primitives/ec_primitives.md | 2 +- .../ecdsa_sig_verification.mdx | 8 +- .../cryptographic_primitives/hashes.mdx | 60 +- .../cryptographic_primitives/scalar.mdx | 4 +- .../cryptographic_primitives/schnorr.mdx | 4 +- .../docs/docs/noir/standard_library/traits.md | 110 +- noir/docs/docs/tutorials/noirjs_app.md | 7 +- noir/docs/docusaurus.config.ts | 1 + noir/docs/package.json | 5 +- noir/docs/scripts/preprocess/include_code.js | 312 ++ noir/docs/scripts/preprocess/index.js | 141 + noir/docs/src/css/custom.css | 84 +- noir/docs/src/pages/index.jsx | 60 +- noir/docs/static/img/aztec_logo.png | Bin 0 -> 38182 bytes .../img/how-tos/solidity_verifier_1.png | Bin 0 -> 33611 bytes .../img/how-tos/solidity_verifier_2.png | Bin 0 -> 66931 bytes .../img/how-tos/solidity_verifier_3.png | Bin 0 -> 63153 bytes .../img/how-tos/solidity_verifier_4.png | Bin 0 -> 79069 bytes .../img/how-tos/solidity_verifier_5.png | Bin 0 -> 48989 bytes noir/docs/static/img/logo.png | Bin 0 -> 178782 bytes noir/docs/static/img/solidity_verifier_ex.png | Bin 0 -> 1177990 bytes .../getting_started/01_hello_world.md | 2 +- .../language_concepts/06_generics.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../04_ec_primitives.md | 2 +- .../getting_started/01_hello_world.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../04_ec_primitives.md | 2 +- .../getting_started/01_hello_world.md | 2 +- .../language_concepts/06_generics.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../04_ec_primitives.md | 2 +- .../getting_started/01_hello_world.md | 2 +- .../language_concepts/06_generics.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../04_ec_primitives.md | 2 +- .../getting_started/01_hello_world.md | 2 +- .../language_concepts/06_generics.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../04_ec_primitives.md | 2 +- .../getting_started/01_hello_world.md | 2 +- .../language_concepts/06_generics.md | 2 +- .../getting_started/01_tiny_noir_app.md | 2 +- .../04_ec_primitives.md | 2 +- .../how_to/how-to-recursion.md | 2 +- .../cryptographic_primitives/ec_primitives.md | 2 +- .../version-v0.22.0/noir/syntax/generics.md | 2 +- .../version-v0.22.0/tutorials/noirjs_app.md | 2 +- .../explainers/explainer-oracle.md | 57 + .../explainers/explainer-recursion.md | 177 + .../getting_started/_category_.json | 5 + .../hello_noir/_category_.json | 5 + .../getting_started/hello_noir/index.md | 142 + .../hello_noir/project_breakdown.md | 199 + .../installation/_category_.json | 6 + .../getting_started/installation/index.md | 48 + .../installation/other_install_methods.md | 190 + .../getting_started/tooling/_category_.json | 6 + .../getting_started/tooling/index.mdx | 38 + .../tooling/language_server.md | 43 + .../getting_started/tooling/testing.md | 62 + .../version-v0.23.0/how_to/_category_.json | 5 + .../version-v0.23.0/how_to/how-to-oracles.md | 280 + .../how_to/how-to-recursion.md | 184 + .../how_to/how-to-solidity-verifier.md | 231 + .../version-v0.23.0/how_to/merkle-proof.mdx | 48 + .../how_to/using-devcontainers.mdx | 110 + .../versioned_docs/version-v0.23.0/index.mdx | 67 + .../version-v0.23.0/migration_notes.md | 91 + .../noir/concepts/_category_.json | 6 + .../version-v0.23.0/noir/concepts/assert.md | 27 + .../version-v0.23.0/noir/concepts/comments.md | 33 + .../noir/concepts/control_flow.md | 45 + .../version-v0.23.0/noir/concepts/data_bus.md | 21 + .../noir/concepts/data_types/_category_.json | 5 + .../noir/concepts/data_types/arrays.md | 249 + .../noir/concepts/data_types/booleans.md | 31 + .../noir/concepts/data_types/fields.md | 166 + .../concepts/data_types/function_types.md | 26 + .../noir/concepts/data_types/index.md | 96 + .../noir/concepts/data_types/integers.md | 113 + .../noir/concepts/data_types/references.md | 23 + .../noir/concepts/data_types/slices.mdx | 147 + .../noir/concepts/data_types/strings.md | 80 + .../noir/concepts/data_types/structs.md | 70 + .../noir/concepts/data_types/tuples.md | 48 + .../noir/concepts/data_types/vectors.mdx | 171 + .../version-v0.23.0/noir/concepts/distinct.md | 64 + .../noir/concepts/functions.md | 226 + .../version-v0.23.0/noir/concepts/generics.md | 106 + .../version-v0.23.0/noir/concepts/lambdas.md | 81 + .../noir/concepts/mutability.md | 93 + .../version-v0.23.0/noir/concepts/ops.md | 98 + .../version-v0.23.0/noir/concepts/oracles.md | 23 + .../noir/concepts/shadowing.md | 44 + .../version-v0.23.0/noir/concepts/traits.md | 389 ++ .../noir/concepts/unconstrained.md | 95 + .../modules_packages_crates/_category_.json | 6 + .../crates_and_packages.md | 43 + .../modules_packages_crates/dependencies.md | 124 + .../noir/modules_packages_crates/modules.md | 105 + .../modules_packages_crates/workspaces.md | 40 + .../noir/standard_library/_category_.json | 6 + .../noir/standard_library/black_box_fns.md | 45 + .../cryptographic_primitives/_category_.json | 5 + .../cryptographic_primitives/ec_primitives.md | 102 + .../ecdsa_sig_verification.mdx | 46 + .../cryptographic_primitives/eddsa.mdx | 18 + .../cryptographic_primitives/hashes.mdx | 167 + .../cryptographic_primitives/index.md | 14 + .../cryptographic_primitives/scalar.mdx | 28 + .../cryptographic_primitives/schnorr.mdx | 38 + .../noir/standard_library/logging.md | 78 + .../noir/standard_library/merkle_trees.md | 58 + .../noir/standard_library/options.md | 97 + .../noir/standard_library/recursion.md | 90 + .../noir/standard_library/traits.md | 284 + .../noir/standard_library/zeroed.md | 25 + .../reference/backend_barretenberg/.nojekyll | 1 + .../classes/BarretenbergBackend.md | 185 + .../reference/backend_barretenberg/index.md | 45 + .../interfaces/Backend.md | 132 + .../type-aliases/BackendOptions.md | 19 + .../type-aliases/CompiledCircuit.md | 20 + .../type-aliases/ProofData.md | 20 + .../backend_barretenberg/typedoc-sidebar.cjs | 4 + .../noir_js/reference/noir_js/.nojekyll | 1 + .../noir_js/reference/noir_js/classes/Noir.md | 131 + .../reference/noir_js/functions/and.md | 22 + .../reference/noir_js/functions/blake2s256.md | 21 + .../functions/ecdsa_secp256k1_verify.md | 29 + .../functions/ecdsa_secp256r1_verify.md | 28 + .../reference/noir_js/functions/keccak256.md | 21 + .../reference/noir_js/functions/sha256.md | 21 + .../reference/noir_js/functions/xor.md | 22 + .../noir_js/reference/noir_js/index.md | 37 + .../noir_js/type-aliases/CompiledCircuit.md | 20 + .../type-aliases/ForeignCallHandler.md | 24 + .../noir_js/type-aliases/ForeignCallInput.md | 9 + .../noir_js/type-aliases/ForeignCallOutput.md | 9 + .../noir_js/type-aliases/InputMap.md | 13 + .../noir_js/type-aliases/ProofData.md | 20 + .../noir_js/type-aliases/WitnessMap.md | 9 + .../reference/noir_js/typedoc-sidebar.cjs | 4 + .../NoirJS/backend_barretenberg/.nojekyll | 1 + .../classes/BarretenbergBackend.md | 185 + .../NoirJS/backend_barretenberg/index.md | 46 + .../interfaces/Backend.md | 132 + .../type-aliases/BackendOptions.md | 19 + .../type-aliases/CompiledCircuit.md | 20 + .../type-aliases/ProofData.md | 20 + .../backend_barretenberg/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_js/.nojekyll | 1 + .../reference/NoirJS/noir_js/classes/Noir.md | 132 + .../reference/NoirJS/noir_js/functions/and.md | 22 + .../NoirJS/noir_js/functions/blake2s256.md | 21 + .../functions/ecdsa_secp256k1_verify.md | 28 + .../functions/ecdsa_secp256r1_verify.md | 28 + .../NoirJS/noir_js/functions/keccak256.md | 21 + .../NoirJS/noir_js/functions/sha256.md | 21 + .../reference/NoirJS/noir_js/functions/xor.md | 22 + .../reference/NoirJS/noir_js/index.md | 37 + .../noir_js/type-aliases/CompiledCircuit.md | 20 + .../type-aliases/ForeignCallHandler.md | 24 + .../noir_js/type-aliases/ForeignCallInput.md | 9 + .../noir_js/type-aliases/ForeignCallOutput.md | 9 + .../NoirJS/noir_js/type-aliases/InputMap.md | 13 + .../NoirJS/noir_js/type-aliases/ProofData.md | 20 + .../NoirJS/noir_js/type-aliases/WitnessMap.md | 9 + .../NoirJS/noir_js/typedoc-sidebar.cjs | 4 + .../version-v0.23.0/reference/_category_.json | 5 + .../reference/nargo_commands.md | 253 + .../version-v0.23.0/tutorials/noirjs_app.md | 279 + .../version-v0.23.0-sidebars.json | 83 + noir/noir_stdlib/src/cmp.nr | 6 +- noir/noir_stdlib/src/convert.nr | 61 + noir/noir_stdlib/src/default.nr | 2 + noir/noir_stdlib/src/ecdsa_secp256k1.nr | 5 +- noir/noir_stdlib/src/ecdsa_secp256r1.nr | 5 +- noir/noir_stdlib/src/hash.nr | 33 +- noir/noir_stdlib/src/lib.nr | 1 + noir/noir_stdlib/src/ops.nr | 23 +- noir/noir_stdlib/src/prelude.nr | 1 + noir/noir_stdlib/src/scalar_mul.nr | 3 +- noir/noir_stdlib/src/schnorr.nr | 5 +- noir/scripts/install_wasm-bindgen.sh | 6 +- .../multiple_contracts/Nargo.toml | 5 - .../multiple_contracts/src/main.nr | 3 - .../intrinsic_die/src/main.nr | 2 - .../trait_generics/src/main.nr | 9 +- .../execution_success/databus/src/main.nr | 14 +- .../execution_success/keccak256/src/main.nr | 7 +- .../pedersen_commitment/Nargo.toml | 6 + .../pedersen_commitment/Prover.toml | 6 + .../pedersen_commitment/src/main.nr | 10 + .../pedersen_hash/Nargo.toml | 6 + .../pedersen_hash/Prover.toml | 4 + .../pedersen_hash/src/main.nr | 9 + .../poseidon_bn254_hash/src/main.nr | 2 + .../regression_4088/Nargo.toml | 5 + .../regression_4088/Prover.toml | 2 + .../regression_4088/src/main.nr | 27 + .../regression_4124/Nargo.toml | 7 + .../regression_4124/Prover.toml | 1 + .../regression_4124/src/main.nr | 39 + .../execution_success/to_le_bytes/Prover.toml | 1 + .../execution_success/to_le_bytes/src/main.nr | 9 +- .../out_of_bounds_alignment/Nargo.toml | 5 + .../out_of_bounds_alignment/Prover.toml | 0 .../out_of_bounds_alignment/src/main.nr | 17 + .../regression_4080/Nargo.toml | 5 + .../regression_4080/Prover.toml | 1 + .../regression_4080/src/main.nr | 8 + noir/tooling/debugger/src/repl.rs | 10 +- noir/tooling/lsp/src/lib.rs | 58 +- noir/tooling/lsp/src/requests/profile_run.rs | 20 +- noir/tooling/nargo/src/artifacts/debug.rs | 12 +- noir/tooling/nargo/src/ops/compile.rs | 35 +- noir/tooling/nargo/src/ops/foreign_calls.rs | 4 +- noir/tooling/nargo/src/ops/mod.rs | 3 + noir/tooling/nargo/src/ops/optimize.rs | 18 +- noir/tooling/nargo/src/ops/transform.rs | 30 + noir/tooling/nargo/src/workspace.rs | 2 + .../nargo_cli/src/cli/codegen_verifier_cmd.rs | 23 +- noir/tooling/nargo_cli/src/cli/compile_cmd.rs | 54 +- noir/tooling/nargo_cli/src/cli/dap_cmd.rs | 55 +- noir/tooling/nargo_cli/src/cli/debug_cmd.rs | 21 +- noir/tooling/nargo_cli/src/cli/execute_cmd.rs | 25 +- noir/tooling/nargo_cli/src/cli/info_cmd.rs | 17 +- noir/tooling/nargo_cli/src/cli/prove_cmd.rs | 26 +- noir/tooling/nargo_cli/src/cli/test_cmd.rs | 98 +- noir/tooling/nargo_cli/src/cli/verify_cmd.rs | 30 +- noir/tooling/nargo_toml/src/lib.rs | 8 +- .../noir_js_backend_barretenberg/src/index.ts | 63 +- noir/tooling/noirc_abi/src/lib.rs | 2 +- yarn-project/Dockerfile.prod | 64 +- yarn-project/accounts/src/defaults/index.ts | 2 +- yarn-project/acir-simulator/package.json | 1 + .../acir-simulator/src/acvm/deserialize.ts | 146 +- .../acir-simulator/src/acvm/serialize.ts | 7 +- .../src/avm/avm_execution_environment.ts | 25 +- .../src/avm/avm_machine_state.ts | 5 +- .../src/avm/avm_memory_types.ts | 83 +- .../src/avm/avm_message_call_result.ts | 3 +- .../acir-simulator/src/avm/fixtures/index.ts | 25 +- .../src/avm/interpreter/interpreter.test.ts | 4 +- .../src/avm/journal/host_storage.ts | 5 +- .../acir-simulator/src/avm/journal/journal.ts | 5 +- .../src/avm/opcodes/accrued_substate.ts | 0 .../src/avm/opcodes/arithmetic.test.ts | 4 +- .../src/avm/opcodes/arithmetic.ts | 17 +- .../src/avm/opcodes/bitwise.test.ts | 39 +- .../acir-simulator/src/avm/opcodes/bitwise.ts | 24 +- .../src/avm/opcodes/comparators.test.ts | 147 + .../src/avm/opcodes/comparators.ts | 29 +- .../src/avm/opcodes/control_flow.test.ts | 22 +- .../src/avm/opcodes/control_flow.ts | 2 +- .../src/avm/opcodes/decode_bytecode.ts | 5 +- .../src/avm/opcodes/encode_to_bytecode.ts | 6 +- .../src/avm/opcodes/external_calls.test.ts | 26 +- .../src/avm/opcodes/external_calls.ts | 12 +- .../src/avm/opcodes/instruction.ts | 4 +- .../src/avm/opcodes/instruction_set.ts | 4 +- .../src/avm/opcodes/memory.test.ts | 76 +- .../acir-simulator/src/avm/opcodes/memory.ts | 10 +- .../acir-simulator/src/avm/opcodes/opcodes.ts | 2 +- .../src/avm/opcodes/storage.test.ts | 19 +- .../acir-simulator/src/avm/opcodes/storage.ts | 16 +- .../src/client/private_execution.test.ts | 7 +- .../src/client/unconstrained_execution.ts | 5 +- yarn-project/acir-simulator/tsconfig.json | 3 + yarn-project/archiver/package.json | 2 +- .../archiver/src/archiver/archiver.ts | 7 +- .../archiver/kv_archiver_store/block_store.ts | 6 +- .../kv_archiver_store/contract_class_store.ts | 2 +- .../contract_instance_store.ts | 2 +- .../kv_archiver_store/contract_store.ts | 2 +- .../kv_archiver_store.test.ts | 3 +- .../archiver/kv_archiver_store/log_store.ts | 4 +- .../kv_archiver_store/message_store.ts | 8 +- yarn-project/archiver/src/index.ts | 1 + .../archiver/src/rpc/archiver_client.ts | 33 + .../archiver/src/rpc/archiver_server.ts | 37 + yarn-project/archiver/src/rpc/index.ts | 2 + yarn-project/aztec-node/package.json | 6 - .../aztec-node/src/aztec-node/config.ts | 4 + yarn-project/aztec-node/src/aztec-node/db.ts | 92 - .../src/aztec-node/http_rpc_server.ts | 1 - .../aztec-node/src/aztec-node/server.ts | 36 +- yarn-project/aztec-node/src/declaration.d.ts | 16 - yarn-project/aztec-node/terraform/main.tf | 4 +- yarn-project/aztec-nr/.gitrepo | 4 +- yarn-project/aztec-nr/aztec/src/context.nr | 36 +- .../aztec/src/history/note_inclusion.nr | 4 +- .../aztec-nr/aztec/src/key/nullifier_key.nr | 18 +- yarn-project/aztec-nr/aztec/src/note.nr | 1 - .../aztec-nr/aztec/src/note/lifecycle.nr | 9 +- .../aztec-nr/aztec/src/note/note_hash.nr | 23 - yarn-project/aztec-nr/aztec/src/note/utils.nr | 36 +- .../aztec/src/oracle/nullifier_key.nr | 18 +- yarn-project/aztec-sandbox/src/bin/index.ts | 244 - yarn-project/aztec.js/src/contract/index.ts | 4 +- yarn-project/aztec.js/src/index.ts | 3 +- .../aztec.js/src/rpc_clients/index.ts | 1 + .../src/{ => rpc_clients}/pxe_client.ts | 3 +- .../aztec.js/src/utils/l1_contracts.ts | 2 +- .../{aztec-sandbox => aztec}/.eslintrc.cjs | 0 .../{aztec-sandbox => aztec}/.gitignore | 0 .../{aztec-sandbox => aztec}/Dockerfile | 4 +- .../{aztec-sandbox => aztec}/README.md | 8 +- .../docker-compose.yml | 7 +- .../{aztec-sandbox => aztec}/package.json | 7 +- yarn-project/aztec/src/aztec_client.ts | 0 yarn-project/aztec/src/bin/index.ts | 66 + yarn-project/aztec/src/cli/cli.ts | 70 + .../aztec/src/cli/cmds/start_archiver.ts | 31 + yarn-project/aztec/src/cli/cmds/start_node.ts | 87 + .../aztec/src/cli/cmds/start_p2p_bootstrap.ts | 18 + yarn-project/aztec/src/cli/cmds/start_pxe.ts | 38 + yarn-project/aztec/src/cli/index.ts | 1 + yarn-project/aztec/src/cli/texts.ts | 71 + yarn-project/aztec/src/cli/util.ts | 139 + .../src/examples/token.ts | 0 .../src/examples/util.ts | 0 .../{aztec-sandbox => aztec}/src/index.ts | 0 .../{aztec-sandbox => aztec}/src/logging.ts | 4 +- .../{aztec-sandbox => aztec}/src/sandbox.ts | 10 +- .../{aztec-sandbox => aztec}/src/splash.ts | 0 .../{aztec-sandbox => aztec}/tsconfig.json | 6 + .../src/aztec_node/rpc/aztec_node_client.ts | 1 + .../circuit-types/src/contract_data.ts | 17 + .../circuit-types/src/keys/key_store.ts | 9 + .../circuit-types/src/l1_to_l2_message.ts | 9 + .../src/logs/l2_block_l2_logs.ts | 18 + yarn-project/circuits.js/src/abis/abis.ts | 40 +- yarn-project/circuits.js/src/constants.gen.ts | 4 +- yarn-project/circuits.js/src/keys/index.ts | 13 +- .../circuits.js/src/structs/call_context.ts | 16 +- .../src/structs/global_variables.ts | 2 +- .../circuits.js/src/structs/header.ts | 17 +- yarn-project/circuits.js/src/structs/index.ts | 1 + .../kernel/combined_accumulated_data.ts | 13 + .../src/structs/kernel/private_kernel.ts | 38 +- .../nullifier_key_validation_request.ts | 101 + .../structs/private_circuit_public_inputs.ts | 39 +- .../circuits.js/src/structs/side_effects.ts | 18 +- .../src/structs/state_reference.ts | 2 +- .../circuits.js/src/tests/factories.ts | 49 +- yarn-project/cli/src/bin/index.ts | 2 +- yarn-project/cli/src/client.test.ts | 2 +- yarn-project/cli/src/cmds/add_contract.ts | 3 - yarn-project/cli/src/cmds/add_note.ts | 3 - yarn-project/cli/src/cmds/block_number.ts | 3 - yarn-project/cli/src/cmds/call.ts | 3 - yarn-project/cli/src/cmds/check_deploy.ts | 3 - yarn-project/cli/src/cmds/compute_selector.ts | 3 - yarn-project/cli/src/cmds/create_account.ts | 3 - yarn-project/cli/src/cmds/deploy.ts | 3 - .../cli/src/cmds/deploy_l1_contracts.ts | 3 - .../cli/src/cmds/example_contracts.ts | 3 - .../cli/src/cmds/generate_p2p_private_key.ts | 3 - .../cli/src/cmds/generate_private_key.ts | 3 - yarn-project/cli/src/cmds/get_account.ts | 3 - yarn-project/cli/src/cmds/get_accounts.ts | 3 - .../cli/src/cmds/get_contract_data.ts | 3 - yarn-project/cli/src/cmds/get_logs.ts | 3 - yarn-project/cli/src/cmds/get_node_info.ts | 3 - yarn-project/cli/src/cmds/get_recipient.ts | 3 - yarn-project/cli/src/cmds/get_recipients.ts | 3 - yarn-project/cli/src/cmds/get_tx_receipt.ts | 3 - yarn-project/cli/src/cmds/inspect_contract.ts | 3 - .../cli/src/cmds/parse_parameter_struct.ts | 3 - yarn-project/cli/src/cmds/register_account.ts | 3 - .../cli/src/cmds/register_recipient.ts | 3 - yarn-project/cli/src/cmds/send.ts | 3 - yarn-project/cli/src/cmds/unbox.ts | 3 - yarn-project/cli/src/update/update.ts | 2 +- yarn-project/cli/src/utils.ts | 4 +- yarn-project/end-to-end/package.json | 1 + .../scripts/docker-compose-browser.yml | 2 +- .../end-to-end/scripts/docker-compose-p2p.yml | 5 +- .../end-to-end/scripts/docker-compose.yml | 2 +- .../src/e2e_blacklist_token_contract.test.ts | 9 +- .../end-to-end/src/e2e_card_game.test.ts | 96 +- yarn-project/end-to-end/src/e2e_cli.test.ts | 2 +- .../src/e2e_nested_contract.test.ts | 32 +- .../end-to-end/src/e2e_note_getter.test.ts | 55 +- .../end-to-end/src/e2e_p2p_network.test.ts | 2 +- .../end-to-end/src/e2e_persistence.test.ts | 2 +- .../end-to-end/src/e2e_slow_tree.test.ts | 16 +- .../end-to-end/src/fixtures/fixtures.ts | 3 - yarn-project/end-to-end/src/fixtures/utils.ts | 24 +- .../src/integration_archiver_l1_to_l2.test.ts | 2 +- .../src/integration_l1_publisher.test.ts | 5 +- .../src/shared/cross_chain_test_harness.ts | 3 +- yarn-project/foundation/src/abi/decoder.ts | 8 +- yarn-project/foundation/src/abi/selector.ts | 7 +- .../foundation/src/aztec-address/index.ts | 6 + yarn-project/foundation/src/fields/point.ts | 7 +- .../json-rpc/client/json_rpc_client.test.ts | 26 +- .../src/json-rpc/client/json_rpc_client.ts | 17 +- .../foundation/src/json-rpc/server/index.ts | 2 +- .../src/json-rpc/server/json_proxy.ts | 29 +- .../json-rpc/server/json_rpc_server.test.ts | 15 +- .../src/json-rpc/server/json_rpc_server.ts | 210 +- .../foundation/src/serialize/buffer_reader.ts | 10 + .../src/serialize/field_reader.test.ts | 93 + .../foundation/src/serialize/field_reader.ts | 143 + .../foundation/src/serialize/index.ts | 1 + yarn-project/key-store/src/test_key_store.ts | 18 +- yarn-project/kv-store/package.json | 2 +- yarn-project/kv-store/src/interfaces/store.ts | 10 +- yarn-project/kv-store/src/lmdb/store.ts | 18 +- yarn-project/merkle-tree/package.json | 5 +- .../src/interfaces/indexed_tree.ts | 36 +- .../merkle-tree/src/interfaces/merkle_tree.ts | 4 +- yarn-project/merkle-tree/src/load_tree.ts | 19 +- yarn-project/merkle-tree/src/new_tree.ts | 9 +- .../snapshots/append_only_snapshot.test.ts | 7 +- .../src/snapshots/append_only_snapshot.ts | 222 +- .../src/snapshots/base_full_snapshot.ts | 185 +- .../src/snapshots/full_snapshot.test.ts | 7 +- .../src/snapshots/full_snapshot.ts | 2 +- .../snapshots/indexed_tree_snapshot.test.ts | 22 +- .../src/snapshots/indexed_tree_snapshot.ts | 46 +- .../src/snapshots/snapshot_builder.ts | 12 +- .../snapshots/snapshot_builder_test_suite.ts | 14 +- .../src/sparse_tree/sparse_tree.test.ts | 28 +- .../src/sparse_tree/sparse_tree.ts | 15 +- .../standard_indexed_tree.ts | 179 +- .../test/standard_indexed_tree.test.ts | 43 +- .../test/standard_indexed_tree_with_append.ts | 18 +- .../src/standard_tree/standard_tree.test.ts | 24 +- .../src/standard_tree/standard_tree.ts | 23 +- .../src/test/standard_based_test_suite.ts | 11 +- .../merkle-tree/src/test/test_suite.ts | 30 +- .../src/test/utils/create_mem_down.ts | 3 - yarn-project/merkle-tree/src/tree_base.ts | 87 +- yarn-project/merkle-tree/tsconfig.json | 3 + .../add_noir_compiler_commander_actions.ts | 6 - .../docs_example_contract/src/main.nr | 23 +- .../src/ecdsa_public_key_note.nr | 6 +- .../src/public_key_note.nr | 6 +- .../src/types/transparent_note.nr | 5 +- .../src/types/transparent_note.nr | 5 +- .../noir-protocol-circuits/package.json | 1 + .../src/__snapshots__/index.test.ts.snap | 4796 ++++++++++------ .../crates/private-kernel-lib/src/common.nr | 43 +- .../src/private_kernel_init.nr | 22 + .../src/private_kernel_ordering.nr | 33 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 2 +- .../src/crates/types/src/abis.nr | 1 + .../src/abis/combined_accumulated_data.nr | 6 + .../abis/nullifier_key_validation_request.nr | 101 + .../src/abis/private_circuit_public_inputs.nr | 3 + .../src/crates/types/src/constants.nr | 4 +- .../src/crates/types/src/grumpkin_point.nr | 12 + .../crates/types/src/grumpkin_private_key.nr | 45 + .../src/crates/types/src/lib.nr | 1 + .../private_circuit_public_inputs_builder.nr | 4 + .../nested-call-private-kernel-init.hex | 1 + .../nested-call-private-kernel-inner.hex | 2 +- .../nested-call-private-kernel-ordering.hex | 1 + .../noir-protocol-circuits/src/index.test.ts | 267 +- .../src/noir_test_gen.test.ts | 8 +- .../src/type_conversion.ts | 106 +- .../noir-protocol-circuits/tsconfig.json | 3 + .../scripts/docker-compose-bootstrap.yml | 4 +- yarn-project/p2p-bootstrap/terraform/main.tf | 3 +- .../p2p/src/client/p2p_client.test.ts | 3 +- yarn-project/p2p/src/client/p2p_client.ts | 6 +- yarn-project/p2p/src/config.ts | 4 +- .../p2p/src/tx_pool/aztec_kv_tx_pool.test.ts | 3 +- .../p2p/src/tx_pool/aztec_kv_tx_pool.ts | 2 +- yarn-project/package.json | 6 +- yarn-project/pxe/src/config/index.ts | 7 +- yarn-project/pxe/src/database/index.ts | 1 - .../pxe/src/database/kv_pxe_database.test.ts | 3 +- .../pxe/src/database/kv_pxe_database.ts | 165 +- .../pxe/src/database/memory_db.test.ts | 67 - yarn-project/pxe/src/database/memory_db.ts | 248 - .../pxe/src/database/note_dao.test.ts | 2 +- .../src/database/pxe_database_test_suite.ts | 1 + yarn-project/pxe/src/kernel_oracle/index.ts | 17 +- .../pxe/src/kernel_prover/kernel_prover.ts | 27 + .../src/kernel_prover/proving_data_oracle.ts | 10 + .../src/note_processor/note_processor.test.ts | 4 +- .../pxe/src/pxe_http/pxe_http_server.ts | 4 - .../pxe/src/pxe_service/create_pxe_service.ts | 7 +- .../pxe/src/pxe_service/pxe_service.ts | 4 +- .../src/pxe_service/test/pxe_service.test.ts | 4 +- .../pxe/src/simulator_oracle/index.ts | 2 +- .../pxe/src/synchronizer/synchronizer.test.ts | 6 +- yarn-project/sequencer-client/package.json | 1 + .../block_builder/solo_block_builder.test.ts | 6 +- yarn-project/sequencer-client/tsconfig.json | 3 + yarn-project/tsconfig.json | 4 +- yarn-project/typedoc.json | 4 +- yarn-project/world-state/package.json | 3 +- .../server_world_state_synchronizer.test.ts | 79 +- .../server_world_state_synchronizer.ts | 61 +- .../src/world-state-db/merkle_trees.ts | 55 +- yarn-project/world-state/tsconfig.json | 3 + yarn-project/yarn.lock | 4979 ++++++++--------- yellow-paper/docs/public-vm/avm.md | 2 +- 757 files changed, 22844 insertions(+), 9941 deletions(-) create mode 100755 barretenberg/cpp/scripts/barretenberg_module_digraph.sh create mode 100644 barretenberg/cpp/scripts/barretenberg_module_digraph_edges.awk create mode 100644 barretenberg/cpp/src/barretenberg/common/utils.cpp create mode 100644 barretenberg/cpp/src/barretenberg/common/utils.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp delete mode 100644 docs/docs/about_aztec/history/differences_to_aztec_connect.md delete mode 100644 docs/docs/concepts/advanced/circuits/kernels/main.md delete mode 100644 docs/docs/concepts/advanced/data_structures/main.md delete mode 100644 docs/docs/concepts/advanced/main.md delete mode 100644 docs/docs/dev_docs/contracts/syntax/storage/main.md delete mode 100644 docs/docs/dev_docs/getting_started/core-concepts.md rename docs/docs/{dev_docs => developers}/aztecjs/main.md (100%) rename docs/docs/{dev_docs => developers}/cli/blank_box.md (100%) rename docs/docs/{dev_docs => developers}/cli/cli-commands.md (97%) rename docs/docs/{dev_docs => developers}/cli/main.md (100%) rename docs/docs/{dev_docs => developers}/cli/run_more_than_one_pxe_sandbox.md (100%) rename docs/docs/{dev_docs => developers}/cli/sandbox-reference.md (93%) rename docs/docs/{dev_docs => developers}/contracts/abi.md (100%) rename docs/docs/{dev_docs => developers}/contracts/artifacts.md (100%) rename docs/docs/{dev_docs => developers}/contracts/compiling.md (98%) rename docs/docs/{dev_docs => developers}/contracts/deploying.md (98%) rename docs/docs/{dev_docs => developers}/contracts/example-contract.md (100%) rename docs/docs/{dev_docs => developers}/contracts/layout.md (100%) rename docs/docs/{dev_docs => developers}/contracts/main.md (100%) rename docs/docs/{dev_docs => developers}/contracts/portals/data_structures.md (100%) rename docs/docs/{dev_docs => developers}/contracts/portals/inbox.md (100%) rename docs/docs/{dev_docs => developers}/contracts/portals/main.md (97%) rename docs/docs/{dev_docs => developers}/contracts/portals/outbox.md (100%) rename docs/docs/{dev_docs => developers}/contracts/portals/registry.md (100%) rename docs/docs/{dev_docs => developers}/contracts/resources/common_patterns/authwit.md (97%) rename docs/docs/{dev_docs => developers}/contracts/resources/common_patterns/main.md (96%) rename docs/docs/{dev_docs => developers}/contracts/resources/dependencies.md (100%) rename docs/docs/{dev_docs => developers}/contracts/resources/main.md (100%) rename docs/docs/{dev_docs => developers}/contracts/resources/style_guide.md (100%) rename docs/docs/{dev_docs => developers}/contracts/security/breaking_changes/main.md (100%) rename docs/docs/{dev_docs => developers}/contracts/security/breaking_changes/v0.md (100%) rename docs/docs/{dev_docs => developers}/contracts/security/main.md (100%) rename docs/docs/{dev_docs => developers}/contracts/setup.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/constrain.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/context.mdx (93%) rename docs/docs/{dev_docs => developers}/contracts/syntax/control_structure.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/events.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/functions.md (95%) rename docs/docs/{dev_docs => developers}/contracts/syntax/globals.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/historical_access/history_lib_reference.md (98%) rename docs/docs/{dev_docs => developers}/contracts/syntax/historical_access/how_to_prove_history.md (97%) rename docs/docs/{dev_docs => developers}/contracts/syntax/main.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/oracles.md (100%) rename docs/docs/{dev_docs => developers}/contracts/syntax/slow_updates_tree.md (98%) create mode 100644 docs/docs/developers/contracts/syntax/storage/main.md create mode 100644 docs/docs/developers/contracts/syntax/storage/private_state.md create mode 100644 docs/docs/developers/contracts/syntax/storage/public_state.md rename docs/docs/{dev_docs => developers}/contracts/syntax/storage/storage_slots.md (88%) rename docs/docs/{dev_docs => developers}/contracts/workflow.md (100%) rename docs/docs/{dev_docs => developers}/debugging/aztecnr-errors.md (98%) rename docs/docs/{dev_docs => developers}/debugging/main.md (100%) rename docs/docs/{dev_docs => developers}/debugging/sandbox-errors.md (89%) rename docs/docs/{dev_docs => developers}/getting_started/aztecjs-getting-started.md (97%) rename docs/docs/{dev_docs => developers}/getting_started/aztecnr-getting-started.md (97%) rename docs/docs/{dev_docs => developers}/getting_started/main.md (91%) rename docs/docs/{dev_docs => developers}/getting_started/quickstart.md (95%) rename docs/docs/{dev_docs => developers}/limitations/main.md (93%) rename docs/docs/{dev_docs => developers}/privacy/main.md (100%) rename docs/docs/{dev_docs => developers}/testing/cheat_codes.md (100%) rename docs/docs/{dev_docs => developers}/testing/main.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/main.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/testing.md (95%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/cancelling_deposits.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/depositing_to_aztec.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/main.md (97%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/minting_on_aztec.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/setup.md (97%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/typescript_glue_code.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/token_portal/withdrawing_to_l1.md (93%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/execute_private_swap_on_l1.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/execute_public_swap_on_l1.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/l1_portal.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/l2_contract_setup.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/main.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/redeeming_swapped_assets_on_l2.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/setup.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/swap_privately.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/swap_publicly.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/uniswap/typescript_glue_code.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/writing_dapp/contract_deployment.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/writing_dapp/contract_interaction.md (93%) rename docs/docs/{dev_docs => developers}/tutorials/writing_dapp/main.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/writing_dapp/project_setup.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/writing_dapp/pxe_service.md (100%) rename docs/docs/{dev_docs => developers}/tutorials/writing_dapp/testing.md (98%) rename docs/docs/{dev_docs => developers}/tutorials/writing_private_voting_contract.md (97%) rename docs/docs/{dev_docs => developers}/tutorials/writing_token_contract.md (97%) rename docs/docs/{dev_docs => developers}/updating.md (96%) rename docs/docs/{dev_docs => developers}/wallets/architecture.md (80%) rename docs/docs/{dev_docs => developers}/wallets/creating_schnorr_accounts.md (96%) rename docs/docs/{dev_docs => developers}/wallets/main.md (75%) rename docs/docs/{dev_docs => developers}/wallets/writing_an_account_contract.md (88%) rename docs/docs/{concepts/foundation/main.md => learn/about_aztec/technical_overview.md} (74%) rename docs/docs/{ => learn}/about_aztec/vision.md (96%) rename docs/docs/{about_aztec/overview.mdx => learn/about_aztec/what_is_aztec.mdx} (95%) rename docs/docs/{concepts/foundation => learn/concepts}/accounts/authwit.md (95%) rename docs/docs/{concepts/foundation => learn/concepts}/accounts/keys.md (98%) rename docs/docs/{concepts/foundation => learn/concepts}/accounts/main.md (99%) rename docs/docs/{concepts/foundation => learn/concepts}/block_production.md (100%) rename docs/docs/{concepts/foundation => learn/concepts}/blocks.md (100%) rename docs/docs/{concepts/advanced => learn/concepts}/circuits/kernels/private_kernel.md (93%) rename docs/docs/{concepts/advanced => learn/concepts}/circuits/kernels/public_kernel.md (82%) rename docs/docs/{concepts/advanced => learn/concepts}/circuits/main.md (98%) rename docs/docs/{concepts/advanced => learn/concepts}/circuits/rollup_circuits/main.md (96%) rename docs/docs/{concepts/foundation => learn/concepts}/communication/cross_chain_calls.md (100%) rename docs/docs/{concepts/foundation => learn/concepts}/communication/main.md (100%) rename docs/docs/{concepts/foundation => learn/concepts}/communication/public_private_calls/main.md (99%) rename docs/docs/{concepts/foundation => learn/concepts}/communication/public_private_calls/slow_updates_tree.md (97%) rename docs/docs/{concepts/foundation => learn/concepts}/globals.md (100%) rename docs/docs/{concepts/foundation/state_model => learn/concepts/hybrid_state}/main.md (97%) rename docs/docs/{concepts/advanced => learn/concepts/hybrid_state}/public_vm.md (100%) create mode 100644 docs/docs/learn/concepts/main.md rename docs/docs/{concepts/foundation => learn/concepts}/nodes_clients/execution_client.md (100%) rename docs/docs/{concepts/foundation => learn/concepts}/nodes_clients/prover_client.md (100%) rename docs/docs/{concepts/foundation/nodes_clients/sequencer.md => learn/concepts/nodes_clients/sequencer/main.md} (97%) rename docs/docs/{concepts/advanced => learn/concepts/nodes_clients/sequencer}/sequencer_selection.md (100%) rename docs/docs/{concepts/advanced => learn/concepts/pxe}/acir_simulator.md (88%) rename docs/docs/{concepts/advanced/private_execution_environment.md => learn/concepts/pxe/main.md} (91%) rename docs/docs/{concepts/advanced => learn/concepts/smart_contracts}/contract_creation.md (99%) rename docs/docs/{concepts/foundation/contracts.md => learn/concepts/smart_contracts/main.md} (95%) rename docs/docs/{concepts/foundation/state_model => learn/concepts/storage}/storage_slots.md (77%) rename docs/docs/{concepts/advanced/data_structures => learn/concepts/storage/trees}/indexed_merkle_tree.md (100%) rename docs/docs/{concepts/advanced/data_structures/trees.md => learn/concepts/storage/trees/main.md} (96%) rename docs/docs/{concepts/foundation => learn/concepts}/transactions.md (93%) rename docs/docs/{concepts/foundation => learn/concepts}/upgrade_mechanism.md (100%) rename docs/docs/{about_aztec => misc}/how_to_contribute.md (100%) rename docs/docs/{about_aztec => misc}/roadmap/cryptography_roadmap.md (100%) rename docs/docs/{about_aztec => misc}/roadmap/engineering_roadmap.md (98%) rename docs/docs/{about_aztec => misc}/roadmap/features_initial_ldt.md (100%) rename docs/docs/{about_aztec => misc}/roadmap/main.md (100%) rename docs/docs/{intro.md => welcome.md} (62%) create mode 100644 l1-contracts/slither.config.json create mode 100755 l1-contracts/slither_has_diff.sh create mode 100644 l1-contracts/slither_output.md rename l1-contracts/test/decoders/helpers/{HeaderDecoderHelper.sol => HeaderLibHelper.sol} (92%) delete mode 100644 noir/.github/ISSUE_TEMPLATE/config.yml rename noir/.github/ISSUE_TEMPLATE/{idea_action_plan.yml => feature_request.yml} (90%) create mode 100644 noir/compiler/noirc_driver/tests/contracts.rs create mode 100644 noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs create mode 100644 noir/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs create mode 100644 noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs create mode 100644 noir/docs/docs/getting_started/hello_noir/_category_.json rename noir/docs/docs/getting_started/{create_a_project.md => hello_noir/index.md} (92%) rename noir/docs/docs/getting_started/{ => hello_noir}/project_breakdown.md (86%) create mode 100644 noir/docs/docs/how_to/how-to-solidity-verifier.md delete mode 100644 noir/docs/docs/how_to/solidity_verifier.md delete mode 100644 noir/docs/docs/index.md create mode 100644 noir/docs/docs/index.mdx create mode 100644 noir/docs/scripts/preprocess/include_code.js create mode 100644 noir/docs/scripts/preprocess/index.js create mode 100644 noir/docs/static/img/aztec_logo.png create mode 100644 noir/docs/static/img/how-tos/solidity_verifier_1.png create mode 100644 noir/docs/static/img/how-tos/solidity_verifier_2.png create mode 100644 noir/docs/static/img/how-tos/solidity_verifier_3.png create mode 100644 noir/docs/static/img/how-tos/solidity_verifier_4.png create mode 100644 noir/docs/static/img/how-tos/solidity_verifier_5.png create mode 100644 noir/docs/static/img/logo.png create mode 100644 noir/docs/static/img/solidity_verifier_ex.png create mode 100644 noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/how_to/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/index.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/migration_notes.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/_category_.json create mode 100644 noir/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md create mode 100644 noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md create mode 100644 noir/docs/versioned_sidebars/version-v0.23.0-sidebars.json create mode 100644 noir/noir_stdlib/src/convert.nr delete mode 100644 noir/test_programs/compile_failure/multiple_contracts/Nargo.toml delete mode 100644 noir/test_programs/compile_failure/multiple_contracts/src/main.nr create mode 100644 noir/test_programs/execution_success/pedersen_commitment/Nargo.toml create mode 100644 noir/test_programs/execution_success/pedersen_commitment/Prover.toml create mode 100644 noir/test_programs/execution_success/pedersen_commitment/src/main.nr create mode 100644 noir/test_programs/execution_success/pedersen_hash/Nargo.toml create mode 100644 noir/test_programs/execution_success/pedersen_hash/Prover.toml create mode 100644 noir/test_programs/execution_success/pedersen_hash/src/main.nr create mode 100644 noir/test_programs/execution_success/regression_4088/Nargo.toml create mode 100644 noir/test_programs/execution_success/regression_4088/Prover.toml create mode 100644 noir/test_programs/execution_success/regression_4088/src/main.nr create mode 100644 noir/test_programs/execution_success/regression_4124/Nargo.toml create mode 100644 noir/test_programs/execution_success/regression_4124/Prover.toml create mode 100644 noir/test_programs/execution_success/regression_4124/src/main.nr create mode 100644 noir/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml create mode 100644 noir/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml create mode 100644 noir/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr create mode 100644 noir/test_programs/noir_test_success/regression_4080/Nargo.toml create mode 100644 noir/test_programs/noir_test_success/regression_4080/Prover.toml create mode 100644 noir/test_programs/noir_test_success/regression_4080/src/main.nr create mode 100644 noir/tooling/nargo/src/ops/transform.rs create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts create mode 100644 yarn-project/archiver/src/rpc/archiver_client.ts create mode 100644 yarn-project/archiver/src/rpc/archiver_server.ts create mode 100644 yarn-project/archiver/src/rpc/index.ts delete mode 100644 yarn-project/aztec-node/src/aztec-node/db.ts delete mode 100644 yarn-project/aztec-node/src/declaration.d.ts delete mode 100644 yarn-project/aztec-nr/aztec/src/note/note_hash.nr delete mode 100644 yarn-project/aztec-sandbox/src/bin/index.ts create mode 100644 yarn-project/aztec.js/src/rpc_clients/index.ts rename yarn-project/aztec.js/src/{ => rpc_clients}/pxe_client.ts (94%) rename yarn-project/{aztec-sandbox => aztec}/.eslintrc.cjs (100%) rename yarn-project/{aztec-sandbox => aztec}/.gitignore (100%) rename yarn-project/{aztec-sandbox => aztec}/Dockerfile (85%) rename yarn-project/{aztec-sandbox => aztec}/README.md (72%) rename yarn-project/{aztec-sandbox => aztec}/docker-compose.yml (85%) rename yarn-project/{aztec-sandbox => aztec}/package.json (92%) create mode 100644 yarn-project/aztec/src/aztec_client.ts create mode 100644 yarn-project/aztec/src/bin/index.ts create mode 100644 yarn-project/aztec/src/cli/cli.ts create mode 100644 yarn-project/aztec/src/cli/cmds/start_archiver.ts create mode 100644 yarn-project/aztec/src/cli/cmds/start_node.ts create mode 100644 yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts create mode 100644 yarn-project/aztec/src/cli/cmds/start_pxe.ts create mode 100644 yarn-project/aztec/src/cli/index.ts create mode 100644 yarn-project/aztec/src/cli/texts.ts create mode 100644 yarn-project/aztec/src/cli/util.ts rename yarn-project/{aztec-sandbox => aztec}/src/examples/token.ts (100%) rename yarn-project/{aztec-sandbox => aztec}/src/examples/util.ts (100%) rename yarn-project/{aztec-sandbox => aztec}/src/index.ts (100%) rename yarn-project/{aztec-sandbox => aztec}/src/logging.ts (92%) rename yarn-project/{aztec-sandbox => aztec}/src/sandbox.ts (94%) rename yarn-project/{aztec-sandbox => aztec}/src/splash.ts (100%) rename yarn-project/{aztec-sandbox => aztec}/tsconfig.json (89%) create mode 100644 yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts create mode 100644 yarn-project/foundation/src/serialize/field_reader.test.ts create mode 100644 yarn-project/foundation/src/serialize/field_reader.ts delete mode 100644 yarn-project/merkle-tree/src/test/utils/create_mem_down.ts create mode 100644 yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr create mode 100644 yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr create mode 100644 yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex create mode 100644 yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex delete mode 100644 yarn-project/pxe/src/database/memory_db.test.ts delete mode 100644 yarn-project/pxe/src/database/memory_db.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 07dd2a3ee5f..cf0b8686481 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -411,7 +411,7 @@ jobs: name: Test command: cond_spot_run_container yarn-project 64 test | add_timestamps - aztec-sandbox: + aztec-package: machine: image: ubuntu-2204:2023.07.2 resource_class: large @@ -420,7 +420,7 @@ jobs: - *setup_env - run: name: "Build and test" - command: build aztec-sandbox + command: build aztec cli: machine: @@ -521,6 +521,17 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_2_pxes.test.ts + e2e-note-getter: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_note_getter.test.ts + e2e-multiple-accounts-1-enc-key: docker: - image: aztecprotocol/alpine-build-image @@ -982,7 +993,7 @@ jobs: command: | should_release || exit 0 deploy_dockerhub noir - deploy_dockerhub aztec-sandbox + deploy_dockerhub aztec deploy_dockerhub cli deploy_dockerhub aztec-faucet deploy_dockerhub mainnet-fork @@ -1034,7 +1045,7 @@ jobs: # Export variables for Terraform. export TF_VAR_BOOTNODE_1_PRIVATE_KEY=$BOOTNODE_1_PRIVATE_KEY export TF_VAR_BOOTNODE_2_PRIVATE_KEY=$BOOTNODE_2_PRIVATE_KEY - deploy_terraform_services yarn-project/p2p-bootstrap aztec-sandbox + deploy_terraform_services yarn-project/p2p-bootstrap aztec - run: name: "Deploy Aztec Nodes to AWS" command: | @@ -1048,16 +1059,16 @@ jobs: # Check if l1-contracts have changed if [ "$CONTRACTS_DEPLOYED" -eq 1 ]; then echo "Contracts have changed, taint nodes to force redeploy.." - deploy_terraform_services yarn-project/aztec-node aztec-sandbox aztec-node "aws_ecs_task_definition.aztec-node[0],aws_ecs_task_definition.aztec-node[1]" + deploy_terraform_services yarn-project/aztec-node aztec aztec-node "aws_ecs_task_definition.aztec-node[0],aws_ecs_task_definition.aztec-node[1]" else - deploy_terraform_services yarn-project/aztec-node aztec-sandbox + deploy_terraform_services yarn-project/aztec-node aztec fi - run: name: "Deploy Aztec Faucet to AWS" command: | should_deploy 0 || exit 0 export TF_VAR_FAUCET_PRIVATE_KEY=$FAUCET_PRIVATE_KEY - deploy_terraform_services yarn-project/aztec-faucet aztec-sandbox + deploy_terraform_services yarn-project/aztec-faucet aztec # Repeatable config for defining the workflow below. defaults: &defaults @@ -1191,14 +1202,14 @@ workflows: - build-docs: *defaults_yarn_project # Artifacts - - aztec-sandbox: *defaults_yarn_project_prod + - aztec-package: *defaults_yarn_project_prod - cli: *defaults_yarn_project_prod - aztec-faucet: *defaults_yarn_project_prod # Boxes. - boxes: requires: - - aztec-sandbox + - aztec-package <<: *defaults - boxes-blank: requires: @@ -1217,10 +1228,11 @@ workflows: - e2e-join: requires: - end-to-end - - aztec-sandbox + - aztec-package - cli <<: *defaults - e2e-2-pxes: *e2e_test + - e2e-note-getter: *e2e_test - e2e-deploy-contract: *e2e_test - e2e-lending-contract: *e2e_test - e2e-token-contract: *e2e_test @@ -1260,6 +1272,7 @@ workflows: requires: - mainnet-fork - e2e-2-pxes + - e2e-note-getter - e2e-deploy-contract - e2e-lending-contract - e2e-token-contract diff --git a/README.md b/README.md index dc4c5d8cf62..95e9503fa2f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ All the packages that make up [Aztec](https://docs.aztec.network). ## Popular packages - [Aztec.nr](./yarn-project/aztec-nr/): A [Noir](https://noir-lang.org) framework for smart contracts on Aztec. -- [Aztec Sandbox](./yarn-project/aztec-sandbox/): A package for setting up a local dev net, including a local Ethereum network, deployed rollup contracts and Aztec execution environment. +- [Aztec](./yarn-project/aztec/): A package for starting up local dev net modules, including a local 'sandbox' devnet, an Ethereum network, deployed rollup contracts and Aztec execution environment. - [Aztec.js](./yarn-project/aztec.js/): A tool for interacting with the Aztec network. It communicates via the [Private Execution Environment (PXE)](./yarn-project/pxe/). - [Example contracts](./yarn-project/noir-contracts/): Example contracts for the Aztec network, written in Noir. - [End to end tests](./yarn-project/end-to-end/): Integration tests written in Typescript--a good reference for how to use the packages for specific tasks. diff --git a/aztec-up/bin/aztec b/aztec-up/bin/aztec index 30ef8a66fab..93c53907c14 100755 --- a/aztec-up/bin/aztec +++ b/aztec-up/bin/aztec @@ -1,4 +1,21 @@ #!/usr/bin/env bash set -euo pipefail -$(dirname $0)/.aztec-run aztecprotocol/aztec-sandbox $@ \ No newline at end of file +# Call cli image if used with `aztec cli ...args` +if [ -n "${1-}" ] && [ "$1" != "--help" ]; then + if [ "$1" == "cli" ]; then + shift + $(dirname $0)/.aztec-run aztecprotocol/cli "$@" + elif [ "$1" == "sandbox" ]; then + $(dirname $0)/aztec-sandbox + else + $(dirname $0)/.aztec-run aztecprotocol/aztec "$@" + fi +else + # TODO - display help message + echo + echo "Using 'aztec' CLI:" + echo " aztec start - Start aztec infrastructure components. See 'aztec start --help' for detailed command info." + echo " aztec sandbox - Run a local sandbox network (same as aztec-sandbox)." + echo " aztec cli - Run the aztec client CLI. See 'aztec cli --help' for detailed command info." +fi diff --git a/aztec-up/bin/aztec-cli b/aztec-up/bin/aztec-cli index 6bdbb0473ba..3624338b5c3 100755 --- a/aztec-up/bin/aztec-cli +++ b/aztec-up/bin/aztec-cli @@ -3,5 +3,6 @@ set -euo pipefail export ENV_VARS_TO_INJECT="PXE_URL PRIVATE_KEY DEBUG" export PXE_URL=${PXE_URL:-"http://host.docker.internal:8080"} +export ETHEREUM_HOST=${ETHEREUM_HOST:-"http://host.docker.internal:8545"} -$(dirname $0)/.aztec-run aztecprotocol/cli $@ \ No newline at end of file +$(dirname $0)/.aztec-run aztecprotocol/cli $@ diff --git a/aztec-up/bin/aztec-install b/aztec-up/bin/aztec-install index a49c37fefff..3c7dec94844 100755 --- a/aztec-up/bin/aztec-install +++ b/aztec-up/bin/aztec-install @@ -40,7 +40,7 @@ function title() { echo -e "${r}" fi echo -e "This will install the following scripts and update your PATH if necessary:" - echo -e " ${bold}${g}aztec${r} - launches various infrastructure subsystems (sequencer, prover, pxe, etc)." + echo -e " ${bold}${g}aztec${r} - launches various infrastructure subsystems (node, sequencer, prover, pxe, etc)." echo -e " ${bold}${g}aztec-cli${r} - a command line tool for interfacing and experimenting with infrastructure." echo -e " ${bold}${g}aztec-nargo${r} - aztec's build of nargo, the noir compiler toolchain." echo -e " ${bold}${g}aztec-sandbox${r} - a wrapper around docker-compose that launches services needed for sandbox testing." @@ -106,12 +106,12 @@ export DOCKER_CLI_HINTS=false if [ -z "${SKIP_PULL:-}" ]; then info "Pulling aztec version $VERSION..." - pull_container aztec-sandbox + pull_container aztec pull_container cli pull_container noir fi -# Download the Docker Compose file. Used by aztec-sandbox. +# Download the Docker Compose file. Used by aztec. curl -fsSL http://$INSTALL_HOST/docker-compose.yml -o $AZTEC_PATH/docker-compose.yml function install_bin { diff --git a/aztec-up/bin/docker-compose.yml b/aztec-up/bin/docker-compose.yml index a1d1e3e646c..7b3cab5e311 100644 --- a/aztec-up/bin/docker-compose.yml +++ b/aztec-up/bin/docker-compose.yml @@ -17,9 +17,8 @@ services: ANVIL_PORT: ${ANVIL_PORT:-8545} aztec: - image: "aztecprotocol/aztec-sandbox" + image: "aztecprotocol/aztec" ports: - - "${AZTEC_NODE_PORT:-8079}:${AZTEC_NODE_PORT:-8079}" - "${PXE_PORT:-8080}:${PXE_PORT:-8080}" environment: DEBUG: # Loaded from the user shell if explicitly set @@ -32,7 +31,6 @@ services: WS_BLOCK_CHECK_INTERVAL_MS: 50 PXE_BLOCK_POLLING_INTERVAL_MS: 50 ARCHIVER_VIEM_POLLING_INTERVAL_MS: 500 - AZTEC_NODE_PORT: ${AZTEC_NODE_PORT:-8079} PXE_PORT: ${PXE_PORT:-8080} volumes: - - ./log:/usr/src/yarn-project/aztec-sandbox/log:rw + - ./log:/usr/src/yarn-project/aztec/log:rw diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 3f3cac42a75..2fa3bb38c8e 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 9e88d98006deb4981c980bbbf9f0ddb568e476ed - parent = a56e418b0fe90b77b7a9fd6bcb0e40cd15260fd6 + commit = 74d4bbd1c283af2f2c3b034c002fea3740c32705 + parent = 9e6250aacbe2d47aa71dee9fa5e43c66eec73e75 method = merge cmdver = 0.4.6 diff --git a/barretenberg/cpp/.gitignore b/barretenberg/cpp/.gitignore index 73dd72cd074..860dfe85cf9 100644 --- a/barretenberg/cpp/.gitignore +++ b/barretenberg/cpp/.gitignore @@ -9,3 +9,5 @@ CMakeUserPresets.json acir_tests # we may download go in scripts/collect_heap_information.sh go*.tar.gz +barretenberg_modules.dot +barretenberg_modules.png \ No newline at end of file diff --git a/barretenberg/cpp/scripts/barretenberg_module_digraph.sh b/barretenberg/cpp/scripts/barretenberg_module_digraph.sh new file mode 100755 index 00000000000..f02b6a01aac --- /dev/null +++ b/barretenberg/cpp/scripts/barretenberg_module_digraph.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eu + +TMP=tmp.dot +RESULT_DOT=barretenberg_modules.dot +RESULT_PNG=barretenberg_modules.png + +# initialize a directed graph for graphviz +echo digraph BarretenbergModules { > $TMP +# populate the directed graph +for file in $(find ./src/barretenberg/ -iname CMakeLists.txt); do + opening_chars=$(head -c 19 "$file") + if [ "$opening_chars" == barretenberg_module ]; then + awk -f ./scripts/barretenberg_module_digraph_edges.awk $file >> $TMP + fi +done +echo } >> $TMP + +# apply transitive reduction to remove dependcies that are implied by other dependencies +cat $TMP | tred > $RESULT_DOT +rm $TMP + +# produce a PNG of the graph +dot -Tpng $RESULT_DOT -o $RESULT_PNG \ No newline at end of file diff --git a/barretenberg/cpp/scripts/barretenberg_module_digraph_edges.awk b/barretenberg/cpp/scripts/barretenberg_module_digraph_edges.awk new file mode 100644 index 00000000000..c5d4c4c2e35 --- /dev/null +++ b/barretenberg/cpp/scripts/barretenberg_module_digraph_edges.awk @@ -0,0 +1,35 @@ +# Function to extract words between parentheses +function extract_edges(line) { + match(line, /\(.*\)/); # Find the portion within parentheses + line = substr(line, RSTART + 1, RLENGTH - 2); # Extract the words + gsub(/^[ ]+/, "", line); # Remove leading spaces and tabs + gsub(/[ ]+$/, "", line); # Remove trailing spaces and tabs + gsub(/[ ]+/, " ", line); # Sub multiple spaces for a single space + split(line, modules, " "); # Split into an array of words + + # If node has no dependencies, just add the node + if (length(modules)==1) { + print modules[1]; + } + else { # add edges + for (i = 2; i <= length(modules); i++) { + print modules[1]" -> "modules[i]; + } + } +} + +# Main AWK script +{ + # Concatenate lines if the opening parenthesis is not closed + while (!/\)/) { + current_line = $0; + getline; + $0 = current_line $0; + } + + # Check if the line begins with "barretenberg_module". If so, extact the digraph edges + function_name = "barretenberg_module"; + if ($0 ~ "^" function_name "\\(") { + extract_edges($0); + } +} diff --git a/barretenberg/cpp/src/barretenberg/common/utils.cpp b/barretenberg/cpp/src/barretenberg/common/utils.cpp new file mode 100644 index 00000000000..00431bd4a74 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/common/utils.cpp @@ -0,0 +1,17 @@ +#include "./utils.hpp" + +namespace bb::utils { + +std::vector hex_to_bytes(const std::string& hex) +{ + std::vector bytes; + + for (unsigned int i = 0; i < hex.length(); i += 2) { + std::string byteString = hex.substr(i, 2); + bytes.push_back(static_cast(strtol(byteString.c_str(), nullptr, 16))); + } + + return bytes; +} + +} // namespace bb::utils \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/utils.hpp b/barretenberg/cpp/src/barretenberg/common/utils.hpp new file mode 100644 index 00000000000..f1ff5acffcb --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/common/utils.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +namespace bb::utils { + +/** + * @brief Routine to transform hexstring to vector of bytes. + * + * @param Hexadecimal string representation. + * @return Vector of uint8_t values. + */ +std::vector hex_to_bytes(const std::string& hex); + +} // namespace bb::utils \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/ecdsa/ecdsa.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/ecdsa/ecdsa.test.cpp index 76b324682a0..507c3378f26 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/ecdsa/ecdsa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/ecdsa/ecdsa.test.cpp @@ -1,5 +1,6 @@ #include "ecdsa.hpp" #include "barretenberg/common/serialize.hpp" +#include "barretenberg/common/utils.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/ecc/curves/secp256r1/secp256r1.hpp" #include "barretenberg/serialize/test_helper.hpp" @@ -89,23 +90,10 @@ TEST(ecdsa, recover_public_key_secp256r1_sha256) EXPECT_EQ(recovered_public_key, account.public_key); } -std::vector HexToBytes(const std::string& hex) -{ - std::vector bytes; - - for (unsigned int i = 0; i < hex.length(); i += 2) { - std::string byteString = hex.substr(i, 2); - uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16); - bytes.push_back(byte); - } - - return bytes; -} - TEST(ecdsa, check_overflowing_r_and_s_are_rejected) { - std::vector message_vec = HexToBytes("41414141"); + std::vector message_vec = utils::hex_to_bytes("41414141"); std::string message(message_vec.begin(), message_vec.end()); crypto::ecdsa_signature signature; @@ -181,10 +169,10 @@ TEST(ecdsa, verify_signature_secp256r1_sha256_NIST_1) }; crypto::ecdsa_signature sig{ r, s, 27 }; - std::vector message_vec = - HexToBytes("5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46" - "c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9" - "d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8"); + std::vector message_vec = utils::hex_to_bytes( + "5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46" + "c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9" + "d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8"); std::string message(message_vec.begin(), message_vec.end()); bool result = crypto::ecdsa_verify_signature( diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index e017ee8a3e9..97e73a25c69 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -265,6 +265,16 @@ struct BlackBoxFuncCall { static Poseidon2Permutation bincodeDeserialize(std::vector); }; + struct Sha256Compression { + std::vector inputs; + std::vector hash_values; + std::vector outputs; + + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; + std::variant + Poseidon2Permutation, + Sha256Compression> value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); @@ -685,6 +696,16 @@ struct BlackBoxOp { static Poseidon2Permutation bincodeDeserialize(std::vector); }; + struct Sha256Compression { + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; + + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; + std::variant + Poseidon2Permutation, + Sha256Compression> value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); @@ -3350,6 +3372,64 @@ Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable< namespace Circuit { +inline bool operator==(const BlackBoxFuncCall::Sha256Compression& lhs, const BlackBoxFuncCall::Sha256Compression& rhs) +{ + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.hash_values == rhs.hash_values)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } + return true; +} + +inline std::vector BlackBoxFuncCall::Sha256Compression::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression::bincodeDeserialize( + std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Sha256Compression& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable< + Circuit::BlackBoxFuncCall::Sha256Compression>::deserialize(Deserializer& deserializer) +{ + Circuit::BlackBoxFuncCall::Sha256Compression obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + inline bool operator==(const BlackBoxOp& lhs, const BlackBoxOp& rhs) { if (!(lhs.value == rhs.value)) { @@ -4490,6 +4570,63 @@ Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable BlackBoxOp::Sha256Compression::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::Sha256Compression& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); + serde::Serializable::serialize(obj.output, serializer); +} + +template <> +template +Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BlackBoxOp::Sha256Compression obj; + obj.input = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + inline bool operator==(const BlockId& lhs, const BlockId& rhs) { if (!(lhs.value == rhs.value)) { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp index 10b3c347330..f8e06ef180b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp @@ -2,6 +2,7 @@ #include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" #include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp" +#include using Flavor = bb::honk::flavor::AvmMiniFlavor; using FF = Flavor::FF; @@ -12,6 +13,9 @@ namespace avm_trace { // Number of rows static const size_t AVM_TRACE_SIZE = 256; enum class IntermRegister : uint32_t { IA = 0, IB = 1, IC = 2 }; + +// Keep following enum in sync with MAX_NEM_TAG below enum class AvmMemoryTag : uint32_t { U0 = 0, U8 = 1, U16 = 2, U32 = 3, U64 = 4, U128 = 5, FF = 6 }; +static const uint32_t MAX_MEM_TAG = 6; } // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp new file mode 100644 index 00000000000..1cbf7b5e353 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp @@ -0,0 +1,238 @@ +#include "AvmMini_execution.hpp" +#include "barretenberg/common/serialize.hpp" +#include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_instructions.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_trace.hpp" +#include "barretenberg/vm/generated/AvmMini_composer.hpp" +#include +#include +#include +#include + +namespace avm_trace { + +/** + * @brief Run the bytecode, generate the corresponding execution trace and prove the correctness + * of the execution of the supplied bytecode. + * + * @param bytecode A vector of bytes representing the bytecode to execute. + * @param calldata expressed as a vector of finite field elements. + * @throws runtime_error exception when the bytecode is invalid. + * @return A zk proof of the execution. + */ +plonk::proof Execution::run_and_prove(std::vector const& bytecode, std::vector const& calldata) +{ + auto instructions = parse(bytecode); + auto trace = gen_trace(instructions, calldata); + auto circuit_builder = bb::AvmMiniCircuitBuilder(); + circuit_builder.set_trace(std::move(trace)); + + auto composer = bb::honk::AvmMiniComposer(); + auto prover = composer.create_prover(circuit_builder); + return prover.construct_proof(); +} + +/** + * @brief Parsing of the supplied bytecode into a vector of instructions. It essentially + * checks that each opcode value is in the defined range and extracts the operands + * for each opcode. + * + * @param bytecode The bytecode to be parsed as a vector of bytes/uint8_t + * @throws runtime_error exception when the bytecode is invalid. + * @return Vector of instructions + */ +std::vector Execution::parse(std::vector const& bytecode) +{ + std::vector instructions; + size_t pos = 0; + const auto length = bytecode.size(); + + while (pos < length) { + const uint8_t opcode_byte = bytecode.at(pos); + pos += AVM_OPCODE_BYTE_LENGTH; + + if (!Bytecode::is_valid(opcode_byte)) { + throw std::runtime_error("Invalid opcode byte: " + std::to_string(opcode_byte)); + } + + const auto opcode = static_cast(opcode_byte); + auto in_tag_u8 = static_cast(AvmMemoryTag::U0); + + if (Bytecode::has_in_tag(opcode)) { + if (pos + AVM_IN_TAG_BYTE_LENGTH > length) { + throw std::runtime_error("Instruction tag missing at position " + std::to_string(pos)); + } + in_tag_u8 = bytecode.at(pos); + if (in_tag_u8 == static_cast(AvmMemoryTag::U0) || in_tag_u8 > MAX_MEM_TAG) { + throw std::runtime_error("Instruction tag is invalid at position " + std::to_string(pos) + + " value: " + std::to_string(in_tag_u8)); + } + pos += AVM_IN_TAG_BYTE_LENGTH; + } + + auto const in_tag = static_cast(in_tag_u8); + std::vector operands{}; + size_t num_of_operands{}; + size_t operands_size{}; + + // SET opcode particularity about the number of operands depending on the + // instruction tag. Namely, a constant of type instruction tag and not a + // memory address is passed in the operands. + // The bytecode of the operands is of the form CONSTANT || dst_offset + // CONSTANT is of size k bits for type Uk, k=8,16,32,64,128 + // dst_offset is of size 32 bits + // CONSTANT has to be decomposed into 32-bit chunks + if (opcode == OpCode::SET) { + switch (in_tag) { + case AvmMemoryTag::U8: + num_of_operands = 2; + operands_size = 5; + break; + case AvmMemoryTag::U16: + num_of_operands = 2; + operands_size = 6; + break; + case AvmMemoryTag::U32: + num_of_operands = 2; + operands_size = 8; + break; + case AvmMemoryTag::U64: + num_of_operands = 3; + operands_size = 12; + break; + case AvmMemoryTag::U128: + num_of_operands = 5; + operands_size = 20; + break; + default: + throw std::runtime_error("Instruction tag for SET opcode is invalid at position " + + std::to_string(pos) + " value: " + std::to_string(in_tag_u8)); + break; + } + } else { + num_of_operands = Bytecode::OPERANDS_NUM.at(opcode); + operands_size = AVM_OPERAND_BYTE_LENGTH * num_of_operands; + } + + if (pos + operands_size > length) { + throw std::runtime_error("Operand is missing at position " + std::to_string(pos)); + } + + // We handle operands which are encoded with less than 4 bytes. + // This occurs for opcode SET and tag U8 and U16. + if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U8) { + operands.push_back(static_cast(bytecode.at(pos))); + pos++; + num_of_operands--; + } else if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U16) { + uint8_t const* ptr = &bytecode.at(pos); + uint16_t operand{}; + serialize::read(ptr, operand); + operands.push_back(static_cast(operand)); + pos += 2; + num_of_operands--; + } + + // Operands of size of 32 bits. + for (size_t i = 0; i < num_of_operands; i++) { + uint8_t const* ptr = &bytecode.at(pos); + uint32_t operand{}; + serialize::read(ptr, operand); + operands.push_back(operand); + pos += AVM_OPERAND_BYTE_LENGTH; + } + + instructions.emplace_back(opcode, operands, static_cast(in_tag)); + } + + return instructions; +} + +/** + * @brief Generate the execution trace pertaining to the supplied instructions. + * + * @param instructions A vector of the instructions to be executed. + * @param calldata expressed as a vector of finite field elements. + * @return The trace as a vector of Row. + */ +std::vector Execution::gen_trace(std::vector const& instructions, std::vector const& calldata) +{ + AvmMiniTraceBuilder trace_builder{}; + + // copied version of pc maintained in trace builder. The value of pc is evolving based + // on opcode logic and therefore is not maintained here. However, the next opcode in the execution + // is determined by this value which require read access to the code below. + uint32_t pc = 0; + auto const inst_size = instructions.size(); + + while ((pc = trace_builder.getPc()) < inst_size) { + auto inst = instructions.at(pc); + + switch (inst.op_code) { + case OpCode::ADD: + trace_builder.add(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + break; + case OpCode::SUB: + trace_builder.sub(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + break; + case OpCode::MUL: + trace_builder.mul(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + break; + case OpCode::DIV: + trace_builder.div(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + break; + case OpCode::CALLDATACOPY: + trace_builder.calldata_copy(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), calldata); + break; + case OpCode::JUMP: + trace_builder.jump(inst.operands.at(0)); + break; + case OpCode::INTERNALCALL: + trace_builder.internal_call(inst.operands.at(0)); + break; + case OpCode::INTERNALRETURN: + trace_builder.internal_return(); + break; + case OpCode::SET: { + uint32_t dst_offset{}; + uint128_t val{}; + switch (inst.in_tag) { + case AvmMemoryTag::U8: + case AvmMemoryTag::U16: + case AvmMemoryTag::U32: + // U8, U16, U32 value represented in a single uint32_t operand + val = inst.operands.at(0); + dst_offset = inst.operands.at(1); + break; + case AvmMemoryTag::U64: // value represented as 2 uint32_t operands + val = inst.operands.at(0); + val <<= 32; + val += inst.operands.at(1); + dst_offset = inst.operands.at(2); + break; + case AvmMemoryTag::U128: // value represented as 4 uint32_t operands + for (size_t i = 0; i < 4; i++) { + val += inst.operands.at(i); + val <<= 32; + } + dst_offset = inst.operands.at(4); + break; + default: + break; + } + trace_builder.set(val, dst_offset, inst.in_tag); + break; + } + case OpCode::RETURN: + trace_builder.return_op(inst.operands.at(0), inst.operands.at(1)); + break; + default: + break; + } + } + return trace_builder.finalize(); +} + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp new file mode 100644 index 00000000000..42baa71f5c0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_instructions.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_trace.hpp" +#include +#include +#include + +namespace avm_trace { + +class Execution { + public: + Execution() = default; + + static size_t const AVM_OPERAND_BYTE_LENGTH = 4; // Keep in sync with TS code + static_assert(sizeof(uint32_t) / sizeof(uint8_t) == AVM_OPERAND_BYTE_LENGTH); + + static size_t const AVM_OPCODE_BYTE_LENGTH = 1; // Keep in sync with TS code + static size_t const AVM_IN_TAG_BYTE_LENGTH = 1; // Keep in sync with TS code + + static std::vector parse(std::vector const& bytecode); + static std::vector gen_trace(std::vector const& instructions, std::vector const& calldata); + static plonk::proof run_and_prove(std::vector const& bytecode, std::vector const& calldata); +}; + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp new file mode 100644 index 00000000000..0cc18e56087 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" +#include +#include + +namespace avm_trace { + +class Instruction { + public: + OpCode op_code; + std::vector operands; + AvmMemoryTag in_tag; + + Instruction() = delete; + explicit Instruction(OpCode op_code, std::vector operands, AvmMemoryTag in_tag) + : op_code(op_code) + , operands(std::move(operands)) + , in_tag(in_tag){}; +}; + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.cpp new file mode 100644 index 00000000000..ec3d7568f09 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.cpp @@ -0,0 +1,153 @@ +#include "AvmMini_opcode.hpp" +#include + +namespace avm_trace { + +const std::unordered_map Bytecode::OPERANDS_NUM = { + // Compute + // Compute - Arithmetic + { OpCode::ADD, 3 }, + { OpCode::SUB, 3 }, + { OpCode::MUL, 3 }, + { OpCode::DIV, 3 }, + //// Compute - Comparators + //{OpCode::EQ, }, + //{OpCode::LT, }, + //{OpCode::LTE, }, + //// Compute - Bitwise + //{OpCode::AND, }, + //{OpCode::OR, }, + //{OpCode::XOR, }, + //{OpCode::NOT, }, + //{OpCode::SHL, }, + //{OpCode::SHR, }, + //// Compute - Type Conversions + //{OpCode::CAST, }, + + //// Execution Environment + //{OpCode::ADDRESS, }, + //{OpCode::STORAGEADDRESS, }, + //{OpCode::ORIGIN, }, + //{OpCode::SENDER, }, + //{OpCode::PORTAL, }, + //{OpCode::FEEPERL1GAS, }, + //{OpCode::FEEPERL2GAS, }, + //{OpCode::FEEPERDAGAS, }, + //{OpCode::CONTRACTCALLDEPTH, }, + //// Execution Environment - Globals + //{OpCode::CHAINID, }, + //{OpCode::VERSION, }, + //{OpCode::BLOCKNUMBER, }, + //{OpCode::TIMESTAMP, }, + //{OpCode::COINBASE, }, + //{OpCode::BLOCKL1GASLIMIT, }, + //{OpCode::BLOCKL2GASLIMIT, }, + //{OpCode::BLOCKDAGASLIMIT, }, + // Execution Environment - Calldata + { OpCode::CALLDATACOPY, 3 }, + + //// Machine State + // Machine State - Gas + //{ OpCode::L1GASLEFT, }, + //{ OpCode::L2GASLEFT, }, + //{ OpCode::DAGASLEFT, }, + //// Machine State - Internal Control Flow + { OpCode::JUMP, 1 }, + { OpCode::JUMPI, 1 }, + { OpCode::INTERNALCALL, 1 }, + { OpCode::INTERNALRETURN, 0 }, + + //// Machine State - Memory + { OpCode::SET, 5 }, + //{ OpCode::MOV, }, + //{ OpCode::CMOV, }, + + //// World State + //{ OpCode::BLOCKHEADERBYNUMBER, }, + //{ OpCode::SLOAD, }, // Public Storage + //{ OpCode::SSTORE, }, // Public Storage + //{ OpCode::READL1TOL2MSG, }, // Messages + //{ OpCode::SENDL2TOL1MSG, }, // Messages + //{ OpCode::EMITNOTEHASH, }, // Notes & Nullifiers + //{ OpCode::EMITNULLIFIER, }, // Notes & Nullifiers + + //// Accrued Substate + //{ OpCode::EMITUNENCRYPTEDLOG, }, + + //// Control Flow - Contract Calls + //{ OpCode::CALL, }, + //{ OpCode::STATICCALL, }, + { OpCode::RETURN, 2 }, + // { OpCode::REVERT, }, + + //// Gadgets + //{ OpCode::KECCAK, }, + //{ OpCode::POSEIDON, }, +}; + +/** + * @brief Test whether a given byte reprents a valid opcode. + * + * @param byte The input byte. + * @return A boolean telling whether a corresponding opcode does match the input byte. + */ +bool Bytecode::is_valid(const uint8_t byte) +{ + return byte <= static_cast(OpCode::POSEIDON); +} + +/** + * @brief A function returning whether a supplied opcode has an instruction tag as argument. + * + * @param op_code The opcode + * @return A boolean set to true if the corresponding instruction needs a tag as argument. + */ +bool Bytecode::has_in_tag(OpCode const op_code) +{ + switch (op_code) { + case OpCode::ADDRESS: + case OpCode::STORAGEADDRESS: + case OpCode::ORIGIN: + case OpCode::SENDER: + case OpCode::PORTAL: + case OpCode::FEEPERL1GAS: + case OpCode::FEEPERL2GAS: + case OpCode::FEEPERDAGAS: + case OpCode::CONTRACTCALLDEPTH: + case OpCode::CHAINID: + case OpCode::VERSION: + case OpCode::BLOCKNUMBER: + case OpCode::TIMESTAMP: + case OpCode::COINBASE: + case OpCode::BLOCKL1GASLIMIT: + case OpCode::BLOCKL2GASLIMIT: + case OpCode::BLOCKDAGASLIMIT: + case OpCode::CALLDATACOPY: + case OpCode::L1GASLEFT: + case OpCode::L2GASLEFT: + case OpCode::DAGASLEFT: + case OpCode::JUMP: + case OpCode::JUMPI: + case OpCode::INTERNALCALL: + case OpCode::INTERNALRETURN: + case OpCode::MOV: + case OpCode::CMOV: + case OpCode::BLOCKHEADERBYNUMBER: + case OpCode::SLOAD: + case OpCode::SSTORE: + case OpCode::READL1TOL2MSG: + case OpCode::SENDL2TOL1MSG: + case OpCode::EMITNOTEHASH: + case OpCode::EMITNULLIFIER: + case OpCode::EMITUNENCRYPTEDLOG: + case OpCode::CALL: + case OpCode::STATICCALL: + case OpCode::RETURN: + case OpCode::REVERT: + return false; + default: + return true; + } +} + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp new file mode 100644 index 00000000000..c945f6158c6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include + +namespace avm_trace { +using std::size_t; + +/** + * All AVM opcodes (Keep in sync with TS counterpart code opcodes.ts) + * TODO: Once opcode values are definitive, we should assign them explicitly in the enum below + * and typescript code. This would increase robustness against unintended modifications. + * i.e.: ADD = 0, SUB = 1, etc, .... + * CAUTION: Any change in the list below needs to be carefully followed by + * a potential adaptation of Bytecode::is_valid method. + */ +enum class OpCode : uint8_t { + // Compute + // Compute - Arithmetic + ADD, + SUB, + MUL, + DIV, + // Compute - Comparators + EQ, + LT, + LTE, + // Compute - Bitwise + AND, + OR, + XOR, + NOT, + SHL, + SHR, + // Compute - Type Conversions + CAST, + + // Execution Environment + ADDRESS, + STORAGEADDRESS, + ORIGIN, + SENDER, + PORTAL, + FEEPERL1GAS, + FEEPERL2GAS, + FEEPERDAGAS, + CONTRACTCALLDEPTH, + // Execution Environment - Globals + CHAINID, + VERSION, + BLOCKNUMBER, + TIMESTAMP, + COINBASE, + BLOCKL1GASLIMIT, + BLOCKL2GASLIMIT, + BLOCKDAGASLIMIT, + // Execution Environment - Calldata + CALLDATACOPY, + + // Machine State + // Machine State - Gas + L1GASLEFT, + L2GASLEFT, + DAGASLEFT, + // Machine State - Internal Control Flow + JUMP, + JUMPI, + INTERNALCALL, + INTERNALRETURN, + // Machine State - Memory + SET, + MOV, + CMOV, + + // World State + BLOCKHEADERBYNUMBER, + SLOAD, // Public Storage + SSTORE, // Public Storage + READL1TOL2MSG, // Messages + SENDL2TOL1MSG, // Messages + EMITNOTEHASH, // Notes & Nullifiers + EMITNULLIFIER, // Notes & Nullifiers + + // Accrued Substate + EMITUNENCRYPTEDLOG, + + // Control Flow - Contract Calls + CALL, + STATICCALL, + RETURN, + REVERT, + + // Gadgets + KECCAK, + POSEIDON, +}; + +class Bytecode { + public: + static bool is_valid(uint8_t byte); + static bool has_in_tag(OpCode); + static const std::unordered_map OPERANDS_NUM; +}; + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp index 771a1590ea1..88aac4a09e6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp @@ -279,10 +279,10 @@ void AvmMiniTraceBuilder::set(uint128_t val, uint32_t dst_offset, AvmMemoryTag i * @param dst_offset The starting index of memory where calldata will be copied to. * @param call_data_mem The vector containing calldata. */ -void AvmMiniTraceBuilder::call_data_copy(uint32_t cd_offset, - uint32_t copy_size, - uint32_t dst_offset, - std::vector const& call_data_mem) +void AvmMiniTraceBuilder::calldata_copy(uint32_t cd_offset, + uint32_t copy_size, + uint32_t dst_offset, + std::vector const& call_data_mem) { // We parallelize storing memory operations in chunk of 3, i.e., 1 per intermediate register. // The variable pos is an index pointing to the first storing operation (pertaining to intermediate @@ -375,6 +375,11 @@ void AvmMiniTraceBuilder::call_data_copy(uint32_t cd_offset, */ std::vector AvmMiniTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_size) { + if (ret_size == 0) { + halt(); + return std::vector{}; + } + // We parallelize loading memory operations in chunk of 3, i.e., 1 per intermediate register. // The variable pos is an index pointing to the first storing operation (pertaining to intermediate // register Ia) relative to ret_offset: @@ -447,6 +452,7 @@ std::vector AvmMiniTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret pos = ret_size; } } + pc = UINT32_MAX; // This ensures that no subsequent opcode will be executed. return returnMem; } @@ -466,6 +472,8 @@ void AvmMiniTraceBuilder::halt() .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_sel_halt = FF(1), }); + + pc = UINT32_MAX; // This ensures that no subsequent opcode will be executed. } /** diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp index af09f2e4d14..381f8f1586b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp @@ -4,6 +4,7 @@ #include "AvmMini_alu_trace.hpp" #include "AvmMini_common.hpp" +#include "AvmMini_instructions.hpp" #include "AvmMini_mem_trace.hpp" #include "barretenberg/common/throw_or_abort.hpp" @@ -25,6 +26,8 @@ class AvmMiniTraceBuilder { std::vector finalize(); void reset(); + uint32_t getPc() const { return pc; } + // Addition with direct memory access. void add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); @@ -55,10 +58,10 @@ class AvmMiniTraceBuilder { // CALLDATACOPY opcode with direct memory access, i.e., // M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] - void call_data_copy(uint32_t cd_offset, - uint32_t copy_size, - uint32_t dst_offset, - std::vector const& call_data_mem); + void calldata_copy(uint32_t cd_offset, + uint32_t copy_size, + uint32_t dst_offset, + std::vector const& call_data_mem); // RETURN opcode with direct memory access, i.e., // return(M[ret_offset:ret_offset+ret_size]) diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp index 15f4e0a37ee..6cde3d10186 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp @@ -3,8 +3,8 @@ #include "barretenberg/numeric/uint128/uint128.hpp" using namespace numeric; -using namespace tests_avm; namespace { +using namespace tests_avm; void common_validate_arithmetic_op(Row const& main_row, Row const& alu_row, @@ -35,7 +35,7 @@ void common_validate_arithmetic_op(Row const& main_row, // Check the instruction tag EXPECT_EQ(main_row.avmMini_in_tag, FF(static_cast(tag))); - // Check that intermediate rgiesters are correctly copied in Alu trace + // Check that intermediate registers are correctly copied in Alu trace EXPECT_EQ(alu_row.aluChip_alu_ia, a); EXPECT_EQ(alu_row.aluChip_alu_ib, b); EXPECT_EQ(alu_row.aluChip_alu_ic, c); @@ -184,7 +184,9 @@ std::vector gen_mutated_trace_mul(FF const& a, FF const& b, FF const& c_mut } // anonymous namespace +namespace tests_avm { using namespace avm_trace; + class AvmMiniArithmeticTests : public ::testing::Test { public: AvmMiniTraceBuilder trace_builder; @@ -244,7 +246,7 @@ class AvmMiniArithmeticNegativeTestsU128 : public AvmMiniArithmeticTests {}; TEST_F(AvmMiniArithmeticTestsFF, addition) { // trace_builder - trace_builder.call_data_copy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.calldata_copy(0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] trace_builder.add(0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] @@ -263,7 +265,7 @@ TEST_F(AvmMiniArithmeticTestsFF, addition) // Test on basic subtraction over finite field type. TEST_F(AvmMiniArithmeticTestsFF, subtraction) { - trace_builder.call_data_copy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.calldata_copy(0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] trace_builder.sub(2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] @@ -282,7 +284,7 @@ TEST_F(AvmMiniArithmeticTestsFF, subtraction) // Test on basic multiplication over finite field type. TEST_F(AvmMiniArithmeticTestsFF, multiplication) { - trace_builder.call_data_copy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.calldata_copy(0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] trace_builder.mul(2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] @@ -302,7 +304,7 @@ TEST_F(AvmMiniArithmeticTestsFF, multiplication) // Test on multiplication by zero over finite field type. TEST_F(AvmMiniArithmeticTestsFF, multiplicationByZero) { - trace_builder.call_data_copy(0, 1, 0, std::vector{ 127 }); + trace_builder.calldata_copy(0, 1, 0, std::vector{ 127 }); // Memory layout: [127,0,0,0,0,0,....] trace_builder.mul(0, 1, 2, AvmMemoryTag::FF); // [127,0,0,0,0,0....] @@ -322,7 +324,7 @@ TEST_F(AvmMiniArithmeticTestsFF, multiplicationByZero) // Test on basic division over finite field type. TEST_F(AvmMiniArithmeticTestsFF, division) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] trace_builder.div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] @@ -345,7 +347,7 @@ TEST_F(AvmMiniArithmeticTestsFF, division) // Test on division with zero numerator over finite field type. TEST_F(AvmMiniArithmeticTestsFF, divisionNumeratorZero) { - trace_builder.call_data_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(1, 0, 0, AvmMemoryTag::FF); // [0,0,0,0,0,0....] @@ -369,7 +371,7 @@ TEST_F(AvmMiniArithmeticTestsFF, divisionNumeratorZero) // We check that the operator error flag is raised. TEST_F(AvmMiniArithmeticTestsFF, divisionByZeroError) { - trace_builder.call_data_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] @@ -419,7 +421,7 @@ TEST_F(AvmMiniArithmeticTestsFF, divisionZeroByZeroError) // No check on the evaluation is performed here. TEST_F(AvmMiniArithmeticTestsFF, mixedOperationsWithError) { - trace_builder.call_data_copy(0, 3, 2, std::vector{ 45, 23, 12 }); + trace_builder.calldata_copy(0, 3, 2, std::vector{ 45, 23, 12 }); // Memory layout: [0,0,45,23,12,0,0,0,....] trace_builder.add(2, 3, 4, AvmMemoryTag::FF); // [0,0,45,23,68,0,0,0,....] @@ -1397,7 +1399,7 @@ TEST_F(AvmMiniArithmeticNegativeTestsFF, multiplication) // Test on basic incorrect division over finite field type. TEST_F(AvmMiniArithmeticNegativeTestsFF, divisionFF) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] trace_builder.div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] @@ -1414,7 +1416,7 @@ TEST_F(AvmMiniArithmeticNegativeTestsFF, divisionFF) // in the trace. TEST_F(AvmMiniArithmeticNegativeTestsFF, divisionNoZeroButError) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] trace_builder.div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] @@ -1440,7 +1442,7 @@ TEST_F(AvmMiniArithmeticNegativeTestsFF, divisionNoZeroButError) // Test with division by zero occurs and no error is raised (remove error flag) TEST_F(AvmMiniArithmeticNegativeTestsFF, divisionByZeroNoError) { - trace_builder.call_data_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] @@ -1477,7 +1479,7 @@ TEST_F(AvmMiniArithmeticNegativeTestsFF, divisionZeroByZeroNoError) // the addition, subtraction, multiplication. TEST_F(AvmMiniArithmeticNegativeTestsFF, operationWithErrorFlag) { - trace_builder.call_data_copy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.calldata_copy(0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] trace_builder.add(0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] @@ -1495,7 +1497,7 @@ TEST_F(AvmMiniArithmeticNegativeTestsFF, operationWithErrorFlag) trace_builder.reset(); - trace_builder.call_data_copy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.calldata_copy(0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] trace_builder.sub(2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] @@ -1512,7 +1514,7 @@ TEST_F(AvmMiniArithmeticNegativeTestsFF, operationWithErrorFlag) trace_builder.reset(); - trace_builder.call_data_copy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.calldata_copy(0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] trace_builder.mul(2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] @@ -1675,4 +1677,6 @@ TEST_F(AvmMiniArithmeticNegativeTestsU128, multiplication) FF{ uint256_t::from_uint128(c) }, AvmMemoryTag::U128); EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "ALU_MULTIPLICATION_OUT_U128"); -} \ No newline at end of file +} + +} // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp index 657ae8e25b1..11ede61acfc 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp @@ -1,7 +1,7 @@ #include "AvmMini_common.test.hpp" +namespace tests_avm { using namespace avm_trace; -using namespace tests_avm; class AvmMiniControlFlowTests : public ::testing::Test { public: @@ -285,3 +285,4 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) validate_trace_proof(std::move(trace)); } +} // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp new file mode 100644 index 00000000000..afe4386816d --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp @@ -0,0 +1,505 @@ +#include "barretenberg/vm/avm_trace/AvmMini_execution.hpp" +#include "AvmMini_common.test.hpp" +#include "barretenberg/common/utils.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_helper.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" +#include "barretenberg/vm/tests/helpers.test.hpp" +#include +#include +#include +#include + +namespace { +void gen_proof_and_validate(std::vector const& bytecode, + std::vector&& trace, + std::vector const& calldata) +{ + auto circuit_builder = AvmMiniCircuitBuilder(); + circuit_builder.set_trace(std::move(trace)); + EXPECT_TRUE(circuit_builder.check_circuit()); + + auto composer = honk::AvmMiniComposer(); + auto verifier = composer.create_verifier(circuit_builder); + + auto proof = avm_trace::Execution::run_and_prove(bytecode, calldata); + + EXPECT_TRUE(verifier.verify_proof(proof)); +} +} // namespace + +namespace tests_avm { +using namespace avm_trace; +using bb::utils::hex_to_bytes; + +class AvmMiniExecutionTests : public ::testing::Test { + public: + AvmMiniTraceBuilder trace_builder; + + protected: + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override + { + srs::init_crs_factory("../srs_db/ignition"); + trace_builder = AvmMiniTraceBuilder(); // Clean instance for every run. + }; +}; + +// Basic positive test with an ADD and RETURN opcode. +// Parsing, trace generation and proving is verified. +TEST_F(AvmMiniExecutionTests, basicAddReturn) +{ + std::string bytecode_hex = "00" // ADD + "01" // U8 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "34" // RETURN + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Execution::parse(bytecode); + + // 2 instructions + EXPECT_EQ(instructions.size(), 2); + + // ADD + EXPECT_EQ(instructions.at(0).op_code, OpCode::ADD); + EXPECT_EQ(instructions.at(0).operands.size(), 3); + EXPECT_EQ(instructions.at(0).operands.at(0), 7); + EXPECT_EQ(instructions.at(0).operands.at(1), 9); + EXPECT_EQ(instructions.at(0).operands.at(2), 1); + EXPECT_EQ(instructions.at(0).in_tag, AvmMemoryTag::U8); + + // RETURN + EXPECT_EQ(instructions.at(1).op_code, OpCode::RETURN); + EXPECT_EQ(instructions.at(1).operands.size(), 2); + EXPECT_EQ(instructions.at(1).operands.at(0), 0); + EXPECT_EQ(instructions.at(1).operands.at(0), 0); + + auto trace = Execution::gen_trace(instructions, std::vector{}); + + gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); +} + +// Positive test for SET and SUB opcodes +TEST_F(AvmMiniExecutionTests, setAndSubOpcodes) +{ + std::string bytecode_hex = "27" // SET 39 = 0x27 + "02" // U16 + "B813" // val 47123 + "000000AA" // dst_offset 170 + "27" // SET 39 = 0x27 + "02" // U16 + "9103" // val 37123 + "00000033" // dst_offset 51 + "01" // SUB + "02" // U16 + "000000AA" // addr a + "00000033" // addr b + "00000001" // addr c 1 + "34" // RETURN + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Execution::parse(bytecode); + + EXPECT_EQ(instructions.size(), 4); + + // SET + EXPECT_EQ(instructions.at(0).op_code, OpCode::SET); + EXPECT_EQ(instructions.at(0).operands.size(), 2); + EXPECT_EQ(instructions.at(0).operands.at(0), 47123); + EXPECT_EQ(instructions.at(0).operands.at(1), 170); + EXPECT_EQ(instructions.at(0).in_tag, AvmMemoryTag::U16); + + // SET + EXPECT_EQ(instructions.at(1).op_code, OpCode::SET); + EXPECT_EQ(instructions.at(1).operands.size(), 2); + EXPECT_EQ(instructions.at(1).operands.at(0), 37123); + EXPECT_EQ(instructions.at(1).operands.at(1), 51); + EXPECT_EQ(instructions.at(1).in_tag, AvmMemoryTag::U16); + + // SUB + EXPECT_EQ(instructions.at(2).op_code, OpCode::SUB); + EXPECT_EQ(instructions.at(2).operands.size(), 3); + EXPECT_EQ(instructions.at(2).operands.at(0), 170); + EXPECT_EQ(instructions.at(2).operands.at(1), 51); + EXPECT_EQ(instructions.at(2).in_tag, AvmMemoryTag::U16); + + auto trace = Execution::gen_trace(instructions, std::vector{}); + + // Find the first row enabling the subtraction selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == 1; }); + EXPECT_EQ(row->avmMini_ic, 10000); // 47123 - 37123 = 10000 + + gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); +} + +// Positive test for multiple MUL opcodes +// We compute 5^12 based on U64 multiplications +// 5 is stored at offset 0 and 1 at offset 1 +// Repeat 12 times a multiplication of value +// at offset 0 (5) with value at offset 1 and store +// the result at offset 1. +TEST_F(AvmMiniExecutionTests, powerWithMulOpcodes) +{ + std::string bytecode_hex = "27" // SET 39 = 0x27 + "04" // U64 + "00000000" // val 5 higher 32 bits + "00000005" // val 5 lower 32 bits + "00000000" // dst_offset 0 + "27" // SET 39 = 0x27 + "04" // U64 + "00000000" // val 1 higher 32 bits + "00000001" // val 1 lower 32 bits + "00000001"; // dst_offset 1 + + std::string const mul_hex = "02" // MUL + "04" // U64 + "00000000" // addr a + "00000001" // addr b + "00000001"; // addr c 1 + + std::string const ret_hex = "34" // RETURN + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + uint8_t num = 12; + while (num-- > 0) { + bytecode_hex.append(mul_hex); + } + + bytecode_hex.append(ret_hex); + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Execution::parse(bytecode); + + EXPECT_EQ(instructions.size(), 15); + + // MUL first pos + EXPECT_EQ(instructions.at(2).op_code, OpCode::MUL); + EXPECT_EQ(instructions.at(2).operands.size(), 3); + EXPECT_EQ(instructions.at(2).operands.at(0), 0); + EXPECT_EQ(instructions.at(2).operands.at(1), 1); + EXPECT_EQ(instructions.at(2).operands.at(2), 1); + EXPECT_EQ(instructions.at(2).in_tag, AvmMemoryTag::U64); + + // MUL last pos + EXPECT_EQ(instructions.at(13).op_code, OpCode::MUL); + EXPECT_EQ(instructions.at(13).operands.size(), 3); + EXPECT_EQ(instructions.at(13).operands.at(0), 0); + EXPECT_EQ(instructions.at(13).operands.at(1), 1); + EXPECT_EQ(instructions.at(13).operands.at(2), 1); + EXPECT_EQ(instructions.at(13).in_tag, AvmMemoryTag::U64); + + // RETURN + EXPECT_EQ(instructions.at(14).op_code, OpCode::RETURN); + EXPECT_EQ(instructions.at(14).operands.size(), 2); + EXPECT_EQ(instructions.at(14).operands.at(0), 0); + EXPECT_EQ(instructions.at(14).operands.at(0), 0); + + auto trace = Execution::gen_trace(instructions, std::vector{}); + + // Find the first row enabling the multiplication selector and pc = 13 + auto row = std::ranges::find_if( + trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == 1 && r.avmMini_pc == 13; }); + EXPECT_EQ(row->avmMini_ic, 244140625); // 5^12 = 244140625 + + gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); +} + +// Positive test about a single internal_call and internal_return +// Code of internal routine is SET U32 value 123456789 at memory address 7 +// The bytecode execution is: +// SET U32 val. 222111000 at memory address 4 +// CALL internal routine +// ADD M[4] with M[7] and output in M[9] +// Internal routine bytecode is at the end. +// Bytecode layout: SET INTERNAL_CALL ADD RETURN SET INTERNAL_RETURN +// 0 1 2 3 4 5 +TEST_F(AvmMiniExecutionTests, simpleInternalCall) +{ + std::string bytecode_hex = "27" // SET 39 = 0x27 + "03" // U32 + "0D3D2518" // val 222111000 = 0xD3D2518 + "00000004" // dst_offset 4 + "25" // INTERNALCALL 37 + "00000004" // jmp_dest + "00" // ADD + "03" // U32 + "00000004" // addr a 4 + "00000007" // addr b 7 + "00000009" // addr c9 + "34" // RETURN + "00000000" // ret offset 0 + "00000000" // ret size 0 + "27" // SET 39 = 0x27 + "03" // U32 + "075BCD15" // val 123456789 = 0x75BCD15 + "00000007" // dst_offset 7 + "26" // INTERNALRETURN 38 + ; + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Execution::parse(bytecode); + + EXPECT_EQ(instructions.size(), 6); + + // We test parsing step for INTERNALCALL and INTERNALRETURN. + + // INTERNALCALL + EXPECT_EQ(instructions.at(1).op_code, OpCode::INTERNALCALL); + EXPECT_EQ(instructions.at(1).operands.size(), 1); + EXPECT_EQ(instructions.at(1).operands.at(0), 4); + + // INTERNALRETURN + EXPECT_EQ(instructions.at(5).op_code, OpCode::INTERNALRETURN); + + auto trace = Execution::gen_trace(instructions, std::vector{}); + + // Expected sequence of PCs during execution + std::vector pc_sequence{ 0, 1, 4, 5, 2, 3 }; + + for (size_t i = 0; i < 6; i++) { + EXPECT_EQ(trace.at(i + 1).avmMini_pc, pc_sequence.at(i)); + } + + // Find the first row enabling the addition selector. + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_add == 1; }); + EXPECT_EQ(row->avmMini_ic, 345567789); + + gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); +} + +// Positive test with some nested internall calls +// We use the following functions (internal calls): +// F1: ADD(2,3,2) M[2] = M[2] + M[3] +// F2: MUL(2,3,2) M[2] = M[2] * M[3] +// G: F1 SET(17,3) F2 where SET(17,3) means M[3] = 17 +// MAIN: SET(4,2) SET(7,3) G +// Whole execution should compute: (4 + 7) * 17 = 187 +// Bytecode layout: SET(4,2) SET(7,3) INTERNAL_CALL_G RETURN BYTECODE(F2) BYTECODE(F1) BYTECODE(G) +// 0 1 2 3 4 6 8 +// BYTECODE(F1): ADD(2,3,2) INTERNAL_RETURN +// BYTECODE(F2): MUL(2,3,2) INTERNAL_RETURN +// BYTECODE(G): INTERNAL_CALL(6) SET(17,3) INTERNAL_CALL(4) INTERNAL_RETURN +TEST_F(AvmMiniExecutionTests, nestedInternalCalls) +{ + auto internalCallHex = [](std::string const& dst_offset) { + return "25" + "000000" + + dst_offset; + }; + + auto setHex = [](std::string const& val, std::string const& dst_offset) { + return "2701" // SET U8 + + val + "000000" + dst_offset; + }; + + const std::string tag_address_arguments = "01" // U8 + "00000002" // addr a 2 + "00000003" // addr b 3 + "00000002"; // addr c 2 + + const std::string return_hex = "34" // RETURN + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + const std::string internal_ret_hex = "26"; + const std::string add_hex = "00"; + const std::string mul_hex = "02"; + + const std::string bytecode_f1 = add_hex + tag_address_arguments + internal_ret_hex; + const std::string bytecode_f2 = mul_hex + tag_address_arguments + internal_ret_hex; + const std::string bytecode_g = + internalCallHex("06") + setHex("11", "03") + internalCallHex("04") + internal_ret_hex; + + std::string bytecode_hex = setHex("04", "02") + setHex("07", "03") + internalCallHex("08") + return_hex + + bytecode_f2 + bytecode_f1 + bytecode_g; + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Execution::parse(bytecode); + + EXPECT_EQ(instructions.size(), 12); + + // Expected sequence of opcodes + std::vector const opcode_sequence{ OpCode::SET, OpCode::SET, + OpCode::INTERNALCALL, OpCode::RETURN, + OpCode::MUL, OpCode::INTERNALRETURN, + OpCode::ADD, OpCode::INTERNALRETURN, + OpCode::INTERNALCALL, OpCode::SET, + OpCode::INTERNALCALL, OpCode::INTERNALRETURN }; + + for (size_t i = 0; i < 12; i++) { + EXPECT_EQ(instructions.at(i).op_code, opcode_sequence.at(i)); + } + + auto trace = Execution::gen_trace(instructions, std::vector{}); + + // Expected sequence of PCs during execution + std::vector pc_sequence{ 0, 1, 2, 8, 6, 7, 9, 10, 4, 5, 11, 3 }; + + for (size_t i = 0; i < 6; i++) { + EXPECT_EQ(trace.at(i + 1).avmMini_pc, pc_sequence.at(i)); + } + + // Find the first row enabling the multiplication selector. + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == 1; }); + EXPECT_EQ(row->avmMini_ic, 187); + EXPECT_EQ(row->avmMini_pc, 4); + + gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); +} + +// Positive test with JUMP and CALLDATACOPY +// We test bytecode which first invoke CALLDATACOPY on a FF array of two values. +// Then, a JUMP call skips a SUB opcode to land to a DIV operation and RETURN. +// Calldata: [13, 156] +// Bytecode layout: CALLDATACOPY JUMP SUB DIV RETURN +// 0 1 2 3 4 +TEST_F(AvmMiniExecutionTests, jumpAndCalldatacopy) +{ + std::string bytecode_hex = "1F" // CALLDATACOPY 31 (no in_tag) + "00000000" // cd_offset + "00000002" // copy_size + "0000000A" // dst_offset // M[10] = 13, M[11] = 156 + "23" // JUMP 35 + "00000003" // jmp_dest (DIV located at 3) + "01" // SUB + "06" // FF + "0000000B" // addr 11 + "0000000A" // addr 10 + "00000001" // addr c 1 (If executed would be 156 - 13 = 143) + "03" // DIV + "06" // FF + "0000000B" // addr 11 + "0000000A" // addr 10 + "00000001" // addr c 1 (156 / 13 = 12) + "34" // RETURN + "00000000" // ret offset 0 + "00000000" // ret size 0 + ; + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Execution::parse(bytecode); + + EXPECT_EQ(instructions.size(), 5); + + // We test parsing steps for CALLDATACOPY and JUMP. + + // CALLDATACOPY + EXPECT_EQ(instructions.at(0).op_code, OpCode::CALLDATACOPY); + EXPECT_EQ(instructions.at(0).operands.size(), 3); + EXPECT_EQ(instructions.at(0).operands.at(0), 0); + EXPECT_EQ(instructions.at(0).operands.at(1), 2); + EXPECT_EQ(instructions.at(0).operands.at(2), 10); + + // JUMP + EXPECT_EQ(instructions.at(1).op_code, OpCode::JUMP); + EXPECT_EQ(instructions.at(1).operands.size(), 1); + EXPECT_EQ(instructions.at(1).operands.at(0), 3); + + auto trace = Execution::gen_trace(instructions, std::vector{ 13, 156 }); + + // Expected sequence of PCs during execution + std::vector pc_sequence{ 0, 1, 3, 4 }; + + for (size_t i = 0; i < 4; i++) { + EXPECT_EQ(trace.at(i + 1).avmMini_pc, pc_sequence.at(i)); + } + + // Find the first row enabling the division selector. + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == 1; }); + EXPECT_EQ(row->avmMini_ic, 12); + + // Find the first row enabling the subtraction selector. + row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == 1; }); + // It must have failed as subtraction was "jumped over". + EXPECT_EQ(row, trace.end()); + + gen_proof_and_validate(bytecode, std::move(trace), std::vector{ 13, 156 }); +} + +// Negative test detecting an invalid opcode byte. +TEST_F(AvmMiniExecutionTests, invalidOpcode) +{ + std::string bytecode_hex = "00" // ADD + "02" // U16 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "AB" // Invalid opcode byte + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "opcode"); +} + +// Negative test detecting an invalid memmory instruction tag. +TEST_F(AvmMiniExecutionTests, invalidInstructionTag) +{ + std::string bytecode_hex = "00" // ADD + "00" // Wrong type + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "34" // RETURN + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Instruction tag is invalid"); +} + +// Negative test detecting SET opcode with instruction memory tag set to FF. +TEST_F(AvmMiniExecutionTests, ffInstructionTagSetOpcode) +{ + std::string bytecode_hex = "00" // ADD + "05" // U128 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "27" // SET 39 = 0x27 + "06" // tag FF + "00002344"; // + + auto bytecode = hex_to_bytes(bytecode_hex); + EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Instruction tag for SET opcode is invalid"); +} + +// Negative test detecting an incomplete instruction: missing instruction tag +TEST_F(AvmMiniExecutionTests, truncatedInstructionNoTag) +{ + std::string bytecode_hex = "00" // ADD + "02" // U16 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "01"; // SUB + + auto bytecode = hex_to_bytes(bytecode_hex); + EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Instruction tag missing"); +} + +// Negative test detecting an incomplete instruction: instruction tag present but an operand is missing +TEST_F(AvmMiniExecutionTests, truncatedInstructionNoOperand) +{ + std::string bytecode_hex = "00" // ADD + "02" // U16 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "01" // SUB + "04" // U64 + "AB2373E7" // addr a + "FFFFFFBB"; // addr b and missing address for c = a-b + + auto bytecode = hex_to_bytes(bytecode_hex); + EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Operand is missing"); +} + +} // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp index a5ccfd1076a..f51e4139539 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp @@ -1,7 +1,7 @@ #include "AvmMini_common.test.hpp" - -using namespace tests_avm; +namespace tests_avm { using namespace avm_trace; + class AvmMiniMemoryTests : public ::testing::Test { public: AvmMiniTraceBuilder trace_builder; @@ -32,7 +32,7 @@ class AvmMiniMemoryTests : public ::testing::Test { // The proof must pass and we check that the AVM error is raised. TEST_F(AvmMiniMemoryTests, mismatchedTag) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); trace_builder.add(0, 1, 4, AvmMemoryTag::U8); trace_builder.halt(); @@ -79,7 +79,7 @@ TEST_F(AvmMiniMemoryTests, mismatchedTag) // in the memory trace TEST_F(AvmMiniMemoryTests, mLastAccessViolation) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 4, 9 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 4, 9 }); // Memory layout: [4,9,0,0,0,0,....] trace_builder.sub(1, 0, 2, AvmMemoryTag::U8); // [4,9,5,0,0,0.....] @@ -109,7 +109,7 @@ TEST_F(AvmMiniMemoryTests, mLastAccessViolation) // written into memory TEST_F(AvmMiniMemoryTests, readWriteConsistencyValViolation) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 4, 9 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 4, 9 }); // Memory layout: [4,9,0,0,0,0,....] trace_builder.mul(1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] @@ -139,7 +139,7 @@ TEST_F(AvmMiniMemoryTests, readWriteConsistencyValViolation) // written into memory TEST_F(AvmMiniMemoryTests, readWriteConsistencyTagViolation) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 4, 9 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 4, 9 }); // Memory layout: [4,9,0,0,0,0,....] trace_builder.mul(1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] @@ -180,7 +180,7 @@ TEST_F(AvmMiniMemoryTests, readUninitializedMemoryViolation) // must raise a VM error. TEST_F(AvmMiniMemoryTests, mismatchedTagErrorViolation) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); trace_builder.sub(0, 1, 4, AvmMemoryTag::U8); trace_builder.halt(); @@ -214,7 +214,7 @@ TEST_F(AvmMiniMemoryTests, mismatchedTagErrorViolation) // must not set a VM error. TEST_F(AvmMiniMemoryTests, consistentTagNoErrorViolation) { - trace_builder.call_data_copy(0, 2, 0, std::vector{ 84, 7 }); + trace_builder.calldata_copy(0, 2, 0, std::vector{ 84, 7 }); trace_builder.div(0, 1, 4, AvmMemoryTag::FF); trace_builder.halt(); @@ -236,3 +236,4 @@ TEST_F(AvmMiniMemoryTests, consistentTagNoErrorViolation) EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); } +} // namespace tests_avm \ No newline at end of file diff --git a/boxes/Dockerfile b/boxes/Dockerfile index 963e664c5db..4191b3559a6 100644 --- a/boxes/Dockerfile +++ b/boxes/Dockerfile @@ -1,11 +1,11 @@ # Builds the boxes (they were copied into yarn-project-base so the cli can unbox). # Produces a container that can be run to test a specific box. See docker-compose.yml. -FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/aztec-sandbox AS aztec-sandbox +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/aztec AS aztec FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/noir as noir # We need yarn. Start fresh container. FROM node:18.19.0 -COPY --from=aztec-sandbox /usr/src /usr/src +COPY --from=aztec /usr/src /usr/src COPY --from=noir /usr/src/noir/target/release/nargo /usr/src/noir/target/release/nargo WORKDIR /usr/src/boxes ENV AZTEC_NARGO=/usr/src/noir/target/release/nargo diff --git a/boxes/blank-react/README.md b/boxes/blank-react/README.md index 3a1035d8a79..29a96433a8d 100644 --- a/boxes/blank-react/README.md +++ b/boxes/blank-react/README.md @@ -10,7 +10,7 @@ yarn install:noir yarn install:sandbox ``` -This sandbox requires [Docker](https://www.docker.com/) to be installed _and running_ locally. In the event the image needs updating, you can run `yarn install:sandbox` (see [sandbox docs](https://aztec-docs-dev.netlify.app/dev_docs/getting_started/sandbox) for more information.) +This sandbox requires [Docker](https://www.docker.com/) to be installed _and running_ locally. In the event the image needs updating, you can run `yarn install:sandbox` (see [sandbox docs](https://docs.aztec.network/developers/cli/main) for more information.) In addition to the usual javascript dependencies, this project requires `nargo` (package manager) and `noir` (Aztec ZK smart contract language) in addition to `@aztec/aztec-cli`. The former two are installed by `yarn install:noir`. diff --git a/boxes/blank/README.md b/boxes/blank/README.md index 36504fefc83..6443e4f34cc 100644 --- a/boxes/blank/README.md +++ b/boxes/blank/README.md @@ -10,7 +10,7 @@ yarn install:noir yarn install:sandbox ``` -This sandbox requires [Docker](https://www.docker.com/) to be installed _and running_ locally. In the event the image needs updating, you can run `yarn install:sandbox` (see [sandbox docs](https://aztec-docs-dev.netlify.app/dev_docs/getting_started/sandbox) for more information.) +This sandbox requires [Docker](https://www.docker.com/) to be installed _and running_ locally. In the event the image needs updating, you can run `yarn install:sandbox` (see [sandbox docs](https://docs.aztec.network/developers/cli/main) for more information.) In addition to the usual javascript dependencies, this project requires `nargo` (package manager) and `noir` (a Domain Specific Language for SNARK proving systems) in addition to `@aztec/aztec-cli`. The former are installed within `yarn install:noir`. diff --git a/boxes/blank/webpack.config.js b/boxes/blank/webpack.config.js index abbbfa719b5..606e154a4f8 100644 --- a/boxes/blank/webpack.config.js +++ b/boxes/blank/webpack.config.js @@ -56,6 +56,7 @@ export default (_, argv) => ({ crypto: false, fs: false, path: false, + events: require.resolve('events/'), stream: require.resolve('stream-browserify'), tty: require.resolve('tty-browserify'), util: require.resolve('util/'), diff --git a/boxes/docker-compose.yml b/boxes/docker-compose.yml index f916d56c810..e731d25c01e 100644 --- a/boxes/docker-compose.yml +++ b/boxes/docker-compose.yml @@ -5,7 +5,7 @@ services: command: "'anvil --silent -p 8545 --host 0.0.0.0 --chain-id 31337'" aztec: - image: aztecprotocol/aztec-sandbox + image: aztecprotocol/aztec environment: ETHEREUM_HOST: http://ethereum:8545 CHAIN_ID: 31337 diff --git a/boxes/token/src/contracts/src/types/transparent_note.nr b/boxes/token/src/contracts/src/types/transparent_note.nr index deb2bcdf6f1..361413bc82b 100644 --- a/boxes/token/src/contracts/src/types/transparent_note.nr +++ b/boxes/token/src/contracts/src/types/transparent_note.nr @@ -3,7 +3,7 @@ use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }, hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext, @@ -75,8 +75,7 @@ impl TransparentNote { } pub fn compute_nullifier_without_context(self) -> Field { - // TODO(#1386): should use `compute_note_hash_for_read_or_nullify` once public functions inject nonce! - let siloed_note_hash = compute_siloed_note_hash(TransparentNoteMethods, self); + let siloed_note_hash = compute_note_hash_for_read_or_nullify(TransparentNoteMethods, self); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([self.secret, siloed_note_hash],0) } diff --git a/boxes/yarn.lock b/boxes/yarn.lock index 5719e430a8d..0f764e1dd06 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -302,6 +302,7 @@ __metadata: resolution: "@aztec/types@portal:../yarn-project/types::locator=%40aztec%2Fboxes%40workspace%3A." dependencies: "@aztec/ethereum": "workspace:^" + "@aztec/foundation": "workspace:^" languageName: node linkType: soft diff --git a/build_manifest.yml b/build_manifest.yml index ea8880f74d0..861b632af04 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -152,9 +152,9 @@ yarn-project-prod: - yarn-project multiarch: buildx -aztec-sandbox: +aztec: buildDir: yarn-project - projectDir: yarn-project/aztec-sandbox + projectDir: yarn-project/aztec dependencies: - yarn-project-prod multiarch: buildx @@ -175,10 +175,10 @@ cli: boxes: buildDir: boxes dependencies: - - aztec-sandbox + - aztec - noir runDependencies: - - aztec-sandbox + - aztec end-to-end: buildDir: yarn-project @@ -186,7 +186,7 @@ end-to-end: dependencies: - yarn-project runDependencies: - - aztec-sandbox + - aztec mainnet-fork: buildDir: iac/mainnet-fork diff --git a/docs/docs/about_aztec/history/differences_to_aztec_connect.md b/docs/docs/about_aztec/history/differences_to_aztec_connect.md deleted file mode 100644 index e94c8d1f551..00000000000 --- a/docs/docs/about_aztec/history/differences_to_aztec_connect.md +++ /dev/null @@ -1,15 +0,0 @@ -## Heuristics that differ from 'Aztec Connect' (a.k.a. 'Connect') - -**A contract cannot manipulate another contract's state** - -In Connect, we had multiple circuits that could each create/destroy a unified set of value notes. This was acceptable because all Connect circuits had a single author (us!). - -In Aztec our architecture must process arbitrary circuits written by potentially dishonest actors. Contract state must therefore be siloed at the architecture level similar to Ethereum. Fortunately, this does not require splitting up the privacy set. - -**Privacy set must be shared across all contracts** - -In Connect observers knew when different note types were being created (value note, account note etc). This cannot be the case in Aztec, as we want to provide strong privacy guarantees to all private contracts even if they have few transactions interacting with their contract. - -**Support for call semantics** - -If a contract can only modify its own state, we need a way for a contract to "call" another contract to request state modifications. diff --git a/docs/docs/concepts/advanced/circuits/kernels/main.md b/docs/docs/concepts/advanced/circuits/kernels/main.md deleted file mode 100644 index 66491cc446c..00000000000 --- a/docs/docs/concepts/advanced/circuits/kernels/main.md +++ /dev/null @@ -1,5 +0,0 @@ -import DocCardList from '@theme/DocCardList'; - -# Kernel Circuits - - diff --git a/docs/docs/concepts/advanced/data_structures/main.md b/docs/docs/concepts/advanced/data_structures/main.md deleted file mode 100644 index 43c378b2ec7..00000000000 --- a/docs/docs/concepts/advanced/data_structures/main.md +++ /dev/null @@ -1,5 +0,0 @@ -import DocCardList from '@theme/DocCardList'; - -# Data Structures - - diff --git a/docs/docs/concepts/advanced/main.md b/docs/docs/concepts/advanced/main.md deleted file mode 100644 index a1234235739..00000000000 --- a/docs/docs/concepts/advanced/main.md +++ /dev/null @@ -1,5 +0,0 @@ -import DocCardList from '@theme/DocCardList'; - -# Advanced Concepts - - diff --git a/docs/docs/dev_docs/contracts/syntax/storage/main.md b/docs/docs/dev_docs/contracts/syntax/storage/main.md deleted file mode 100644 index 263363832f1..00000000000 --- a/docs/docs/dev_docs/contracts/syntax/storage/main.md +++ /dev/null @@ -1,539 +0,0 @@ ---- -title: Storage ---- - -Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its hybrid, privacy-first architecture, the management of this storage is more complex than other blockchains like Ethereum. - -You control this storage in Aztec using the `Storage` struct. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. - -These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. - -Aztec.nr has a few abstractions to help define the type of data your contract holds. These include Singletons, ImmutableSingletons, Set, and Map. - -On this page, you’ll learn: - -- How to manage a smart contract's storage structure -- The distinctions and applications of public and private state variables -- How to use Singleton, ImmutableSingleton, Set, and Map -- An overview of 'notes' and the UTXO model -- Practical implications of Storage in real smart contracts - In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. - -## Public and private state variables - -Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data or note viewing key with). - -Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (pre-images) are only known by the sender and those able to decrypt them - see ([state model](../../../../concepts/foundation/state_model/main.md) and [private/public execution](../../../../concepts/foundation/communication/public_private_calls/main.md)) for more background. - -## Storage struct - -:::info -The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (this will be relaxed in the future). -::: - -```rust -struct Storage { - // public state variables - // private state variables -} -``` - -:::danger -If your contract works with storage (has Storage struct defined), you **MUST** include a `compute_note_hash_and_nullifier` function to allow PXE to process encrypted events. See [encrypted events](../events.md#processing-encrypted-events) for more. - -If you don't yet have any private state variables defined put there a placeholder function: - -#include_code compute_note_hash_and_nullifier_placeholder /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust -::: - -Since Aztec.nr is written in Noir, which on its own is state-less, we need to specify how the storage struct should be initialized to read and write data correctly. This is done by specifying an `init` function that is run in functions that rely on reading or altering the state variables. This `init` function must declare the storage struct with an instantiation defining how variables are accessed and manipulated. The function MUST be called `init` for the Aztec.nr library to properly handle it (this will be relaxed in the future). - -```rust -impl Storage { - fn init(context: Context) -> Self { - Storage { - // (public state variables)::new() - // (private state variables)::new() - } - } -} -``` - -If you have defined a `Storage` struct following this naming scheme, then it will be made available to you through the reserved `storage` keyword within your contract functions. - -:::warning Using slot `0` is not supported! -No storage values should be initialized at slot `0` - storage slots begin at `1`. This is a known issue that will be fixed in the future. -::: - -## Map - -A `map` is a state variable that "maps" a key to a value. It can be used with private or public storage variables. - -:::info -In Aztec.nr, keys are always `Field`s (or types that can be serialized as Fields) and values can be any type - even other maps. `Field`s are finite field elements, but you can think of them as integers for now. -::: - -It includes a [`Context`](../context.mdx) to specify the private or public domain, a `storage_slot` to specify where in storage the map is stored, and a `start_var_constructor` which tells the map how it should operate on the underlying type. This includes how to serialize and deserialize the type, as well as how commitments and nullifiers are computed for the type if it's private. - -You can view the implementation in the Aztec.nr library [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/map.nr). - -### `new` - -When declaring the storage for a map, we use the `Map::new()` constructor. As seen below, this takes the `storage_slot` and the `start_var_constructor` along with the [`Context`](../context.mdx). - -We will see examples of map constructors for public and private variables in later sections. - -#### As private storage - -When declaring a mapping in private storage, we have to specify which type of Note to use. In the example below, we are specifying that we want to use the `Singleton` note type. See the [Singleton](#singletonnotetype) section for more information. - -In the Storage struct: - -#include_code storage-map-singleton-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -In the `Storage::init` function: - -#include_code state_vars-MapSingleton /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -#### Public Example - -When declaring a public mapping in Storage, we have to specify that the type is public by declaring it as `PublicState` instead of specifying a note type like with private storage above. - -In the Storage struct: - -#include_code storage_minters /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -In the `Storage::init` function: - -#include_code storage_minters_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -### `at` - -When dealing with a map, we can access the value at a given key using the `::at` method. This takes the key as an argument and returns the value at that key. - -This function behaves similarly for both private and public maps. An example could be if we have a map with `minters`, which is mapping addresses to a flag for whether they are allowed to mint tokens or not. - -#include_code read_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -Above, we are specifying that we want to get the storage in the Map `at` the `msg_sender()`, read the value stored and check that `msg_sender()` is indeed a minter. Doing a similar operation in Solidity code would look like: - -```solidity -require(minters[msg.sender], "caller is not minter"); -``` - -## Public State Variables - -To define that a variable is public, it is wrapped in the `PublicState` struct. - -The `PublicState` struct is generic over the variable type `T` and its serialized size `T_SERIALIZED_LEN`. -:::info -Currently, the length of the types must be specified when declaring the storage struct but the intention is that this will be inferred in the future. -::: - -The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out _where_ in storage the variable is located. Notice that while we don't have the exact same [state model](../../../../concepts/foundation/state_model/main.md) as EVM chains it will look similar from the contract developers point of view. - -Beyond the struct, the `PublicState` also contains `serialization_methods`, which is a struct with methods that instruct the `PublicState` how to serialize and deserialize the variable. You can find the details of `PublicState` in the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr). - -:::info -The British haven't surrendered fully to US spelling, so serialization is currently inconsistent. -::: - -The Aztec.nr library provides serialization methods for various common types. - -:::info -An example using a larger struct can be found in the [lending example](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/lending_contract)'s use of an [`Asset`](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/lending_contract/src/asset.nr). -::: - -### `new` - -When declaring the storage for `T` as a persistent public storage variable, we use the `PublicState::new()` constructor. As seen below, this takes the `storage_slot` and the `serialization_methods` as arguments along with the [`Context`](../context.mdx), which in this case is used to share interface with other structures. - -#include_code public_state_struct_new /yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr rust - -#### Single value example - -Say that we wish to add `admin` public state variable into our storage struct. In the struct we can define it as: - -#include_code storage_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -And then when initializing it in the `Storage::init` function we can do: - -#include_code storage_admin_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -We have specified that we are storing a `Field` that should be placed in storage slot `1`. This is just a single value, and is similar to the following in solidity: - -```solidity -address internal admin; -``` - -:::info -We know its verbose, and are working on making it less so. -::: - -#### Mapping example - -Say we want to have a group of `minters` that are able to mint assets in our contract, and we want them in public storage, because [access control in private is quite cumbersome](../../../../concepts/foundation/communication/public_private_calls/main.md#a-note-on-l2-access-control). In the `Storage` struct we can add it as follows: - -#include_code storage_minters /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -And then when initializing it in the `Storage::init` function we can do it as follows: - -#include_code storage_minters_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -In this case, specifying that we are dealing with a map of Fields, and that it should be put at slot 2. - -This would be similar to the following in solidity: - -```solidity -mapping(address => bool) internal minters; -``` - -### `read` - -On the `PublicState` structs we have a `read` method to read the value at the location in storage and using the specified deserialization method to deserialize it. - -#### Reading from our `admin` example - -For our `admin` example from earlier, this could be used as follows to check that the stored value matches the `msg_sender()`. - -#include_code read_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -#### Reading from our `minters` example - -As we saw in the Map earlier, a very similar operation can be done to perform a lookup in a map. - -#include_code read_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -### `write` - -We have a `write` method on the `PublicState` struct that takes the value to write as an input and saves this in storage. It uses the serialization method to serialize the value which inserts (possibly multiple) values into storage. - -#### Writing to our `admin` example - -#include_code write_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -#### Writing to our `minters` example - -#include_code write_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -## Private State Variables - -In contrast to public state, private state is persistent state that is **not** visible to the whole world. Depending on the logic of the smart contract, a private state variable's current value will only be known to one entity, or a closed group of entities. - -The value of a private state variable can either be shared via an [encrypted log](../events.md#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. - -Aztec private state follows a utxo-based model. That is, a private state's current value is represented as one or many [notes](#notes). Each note is stored as an individual leaf in a utxo-based merkle tree: the [private state tree](../../../../concepts/foundation/state_model/main.md). - -To greatly simplify the experience of writing private state, Aztec.nr provides three different types of private state variable: - -- [Singleton](#singletonnotetype) -- [ImmutableSingleton](#immutablesingletonnotetype) -- [Set](#setnotetype) - -These three structs abstract-away many of Aztec's protocol complexities, by providing intuitive methods to modify notes in the utxo tree in a privacy-preserving way. - -:::info -An app can also choose to emit data via unencrypted log, or to define a note whose data is easy to figure out, then the information is technically not private and could be visible to anyone. -::: - -### Notes - -Unlike public state variables, which can be arbitrary types, private state variables operate on `NoteType`. - -Notes are the fundamental elements in the private world. - -A note should conform to the following interface: - -#include_code NoteInterface /yarn-project/aztec-nr/aztec/src/note/note_interface.nr rust - -The interplay between a private state variable and its notes can be confusing. Here's a summary to aid intuition: - -A private state variable (of type `Singleton`, `ImmutableSingleton` or `Set`) may be declared in storage. - -Every note contains (as a 'header') the contract address and storage slot of the state variable to which it "belongs". A note is said to "belong" to a private state if the storage slot of the private state matches the storage slot contained in the note's header. The header provides information that helps the user interpret the note's data. Without it the user would have to figure out where it belongs by brute-forcing the address and contract space. - -Management of this 'header' is abstracted-away from developers who use the `ImmutableSingleton`, `Singleton` and `Set` types. - -A private state variable is colloquially said to "point" to one or many notes (depending on the type), if those note(s) all "belong" to that private state, and those note(s) haven't-yet been nullified. - -An `ImmutableSingleton` will point to _one_ note over the lifetime of the contract. ("One", hence "Singleton"). This note is a struct of information that is persisted forever. - -A `Singleton` may point to _one_ note at a time. ("One", hence "Singleton"). But since it's not "immutable", the note that it points to may be [replaced](#replace) by functions of the contract, over time. The "current value" of a `Singleton` is interpreted as the one note which has not-yet been nullified. The act of 'replacing' a Singleton's note is how a `Singleton` state may be modified by functions. - -`Singleton` is a useful type when declaring a private state which may only ever be modified by those who are privy to the current value of that state. - -A `Set` may point to _multiple_ notes at a time. The "current value" of a private state variable of type `Set` is some 'accumulation' of all not-yet nullified notes which "belong" to the `Set`. The term "some accumulation" is intentionally vague. The interpretation of the "current value" of a `Set` must be expressed by the smart contract developer. A common use case for a `Set` is to represent the sum of a collection of values (in which case 'accumulation' is 'summation'). - -Think of a ZCash balance (or even a Bitcoin balance). The "current value" of a user's ZCash balance is the sum of all unspent (not-yet nullified) notes belonging to that user. To modify the "current value" of a `Set` state variable, is to [`insert`](#insert) new notes into the `Set`, or [`remove`](#remove) notes from that set. - -Interestingly, if a developer requires a private state to be modifiable by users who _aren't_ privy to the value of that state, a `Set` is a very useful type. The `insert` method allows new notes to be added to the `Set` without knowing any of the other notes in the set! (Like posting an envelope into a post box, you don't know what else is in there!). - -## `Singleton` - -Singleton is a private state variable that is unique in a way. When a Singleton is initialized, a note is created to represent its value. And the way to update the value is to destroy the current note, and create a new one with the updated value. - -Like for public state, we define the struct to have context, a storage slot and `note_interface` specifying how the note should be constructed and manipulated. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr). - -An example of singleton usage in the account contracts is keeping track of public keys. The `Singleton` is added to the `Storage` struct as follows: - -#include_code storage-singleton-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -### `new` - -As part of the initialization of the `Storage` struct, the `Singleton` is created as follows, here at the specified storage slot and with the `NoteInterface` for `CardNote`. - -#include_code start_vars_singleton /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -### `initialize` - -As mentioned, the Singleton is initialized to create the first note and value. - -When this function is called, a nullifier of the storage slot is created, preventing this Singleton from being initialized again. - -:::danger Privacy-Leak -Beware that because this nullifier is created only from the storage slot without randomness it is "leaky". This means that if the storage slot depends on the an address then it is possible to link the nullifier to the address. For example, if the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. -::: - -Unlike public states, which have a default initial value of `0` (or many zeros, in the case of a struct, array or map), a private state (of type `Singleton`, `ImmutableSingleton` or `Set`) does not have a default initial value. The `initialize` method (or `insert`, in the case of a `Set`) must be called. - -:::info -Extend on what happens if you try to use non-initialized state. -::: - -### `is_initialized` - -An unconstrained method to check whether the Singleton has been initialized or not. It takes an optional owner and returns a boolean. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr). - -### `replace` - -To update the value of a `Singleton`, we can use the `replace` method. The method takes a new note as input, and replaces the current note with the new one. It emits a nullifier for the old value, and inserts the new note into the data tree. - -An example of this is seen in a example card game, where we create a new note (a `CardNote`) containing some new data, and replace the current note with it: - -#include_code state_vars-SingletonReplace /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -If two people are trying to modify the Singleton at the same time, only one will succeed as we don't allow duplicate nullifiers! Developers should put in place appropriate access controls to avoid race conditions (unless a race is intended!). - -### `get_note` - -This function allows us to get the note of a Singleton, essentially reading the value. - -#include_code state_vars-SingletonGet /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -#### Nullifying Note reads - -It's possible that at the time this function is called, the system hasn't synced to the block where the latest note was created. Or a malicious user might feed an old state to this function, tricking the proving system into thinking that the value hasn't changed. To avoid an attack around it, this function will destroy the current note, and replace it with a duplicated note that has the same fields. Because the nullifier of the latest note will be emitted, if two people are trying to use this function against the same note, only one will succeed (no duplicate nullifiers allowed). - -### `view_note` - -Functionally similar to [`get_note`](#get_note), but executed in unconstrained functions and can be used by the wallet to fetch notes for use by front-ends etc. - -## `ImmutableSingleton` - -ImmutableSingleton represents a unique private state variable that, as the name suggests, is immutable. Once initialized, its value cannot be altered. - -#include_code struct /yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr rust - -### `new` - -As part of the initialization of the `Storage` struct, the `Singleton` is created as follows, here at storage slot 1 and with the `NoteInterface` for `PublicKeyNote`. - -#include_code storage_init /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust - -### `initialize` - -When this function is invoked, it creates a nullifier for the storage slot, ensuring that the ImmutableSingleton cannot be initialized again. - -:::danger Privacy-Leak -Beware that because this nullifier is created only from the storage slot without randomness it is "leaky". This means that if the storage slot depends on the an address then it is possible to link the nullifier to the address. For example, if the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. -::: - -Set the value of an ImmutableSingleton by calling the `initialize` method: - -#include_code initialize /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust - -Once initialized, an ImmutableSingleton's value remains unchangeable. This method can only be called once. - -### `is_initialized` - -An unconstrained method to check if the ImmutableSingleton has been initialized. Takes an optional owner and returns a boolean. You can find the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master//yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr). - -### `get_note` - -Similar to the `Singleton`, we can use the `get_note` method to read the value of an ImmutableSingleton. - -Use this method to retrieve the value of an initialized ImmutableSingleton. - -#include_code get_note /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust - -Unlike a `Singleton`, the `get_note` function for an ImmutableSingleton doesn't destroy the current note in the background. This means that multiple accounts can concurrently call this function to read the value. - -This function will throw if the ImmutableSingleton hasn't been initialized. - -### `view_note` - -Functionally similar to `get_note`, but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. - -## `Set` - -Set is used for managing a collection of notes. All notes in a set are of the same `NoteType`. But whether these notes all belong to one entity, or are accessible and editable by different entities, is totally up to the developer. Due to our state model, the set is a collection of notes inserted into the data-tree, but notes are never removed from the tree itself, they are only nullified. - -#include_code struct /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust - -And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](../functions.md#public---private)). - -#include_code storage_pending_shields /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -### `new` - -The `new` method tells the contract how to operate on the underlying storage. - -We can initialize the set as follows: - -#include_code storage_pending_shields_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -### `insert` - -Allows us to modify the storage by inserting a note into the set. - -A commitment from the note will be generated, and inserted into data-tree, allowing us to later use in contract interactions. - -A commitment from the note will be generated, and inserted into data-tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an [encrypted log](../events.md#encrypted-events), or offchain via web2, or completely offline. - -#include_code insert /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust - -### `insert_from_public` - -While we don't support private functions to directly alter public storage, the opposite direction is possible. The `insert_from_public` allow public function to insert notes into private storage. This is very useful when we want to support private function calls that must have been initiated in public, such as shielding or the like. - -The usage is rather straight-forward and very similar to using the `insert` method with the difference that this one is called in public functions. - -#include_code insert_from_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -### `remove` - -Will remove a note from the set if it previously has been read from storage, e.g. you have fetched it through a `get_notes` call. This is useful when you want to remove a note that you have previously read from storage and do not have to read it again. - -Nullifiers are emitted when reading values to make sure that they are up to date. - -An example of how to use this operation is visible in the `easy_private_state`: - -#include_code remove /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust - -### `get_notes` - -This function returns the notes the account has access to. - -The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. - -Because of this limit, we should always consider using the second argument `NoteGetterOptions` to limit the number of notes we need to read and constrain in our programs. This is quite important as every extra call increases the time used to prove the program and we don't want to spend more time than necessary. - -An example of such options is using the [filter_notes_min_sum](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/value-note/src/filter.nr) to get "enough" notes to cover a given value. Essentially, this function will return just enough notes to cover the amount specified such that we don't need to read all our notes. For users with a lot of notes, this becomes increasingly important. - -#include_code get_notes /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust - -### `view_notes` - -Functionally similar to [`get_notes`](#get_notes), but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. - -#include_code view_notes /yarn-project/aztec-nr/value-note/src/balance_utils.nr rust - -There's also a limit on the maximum number of notes that can be returned in one go. To find the current limit, refer to [this file](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr) and look for `MAX_NOTES_PER_PAGE`. - -The key distinction is that this method is unconstrained. It does not perform a check to verify if the notes actually exist, which is something the [`get_notes`](#get_notes) method does under the hood. Therefore, it should only be used in an unconstrained contract function. - -This function requires a `NoteViewerOptions`. The `NoteViewerOptions` is essentially similar to the [`NoteGetterOptions`](#notegetteroptions), except that it doesn't take a custom filter. - -### NoteGetterOptions - -`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a [data oracle](../functions.md#oracle-functions). Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. - -#include_code NoteGetterOptions /yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr rust - -#### `selects: BoundedVec, N>` - -`selects` is a collection of filtering criteria, specified by `Select { field_index: u8, value: Field }` structs. It instructs the data oracle to find notes whose (`field_index`)th field matches the provided `value`. - -#### `sorts: BoundedVec, N>` - -`sorts` is a set of sorting instructions defined by `Sort { field_index: u8, order: u2 }` structs. This directs the data oracle to sort the matching notes based on the value of the specified field index and in the indicated order. The value of order is **1** for _DESCENDING_ and **2** for _ASCENDING_. - -#### `limit: u32` - -When the `limit` is set to a non-zero value, the data oracle will return a maximum of `limit` notes. - -#### `offset: u32` - -This setting enables us to skip the first `offset` notes. It's particularly useful for pagination. - -#### `filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL]` - -Developers have the option to provide a custom filter. This allows specific logic to be applied to notes that meet the criteria outlined above. The filter takes the notes returned from the oracle and `filter_args` as its parameters. - -It's important to note that the process of applying the custom filter to get the final notes is not constrained. It's crucial to verify the returned notes even if certain assumptions are made in the custom filter. - -#### `filter_args: FILTER_ARGS` - -`filter_args` provides a means to furnish additional data or context to the custom filter. - -#### Methods - -Several methods are available on `NoteGetterOptions` to construct the options in a more readable manner: - -#### `fn new() -> NoteGetterOptions` - -This function initializes a `NoteGetterOptions` that simply returns the maximum number of notes allowed in a call. - -#### `fn with_filter(filter, filter_args) -> NoteGetterOptions` - -This function initializes a `NoteGetterOptions` with a [`filter`](#filter-fn-optionnote-max_read_requests_per_call-filter_args---optionnote-max_read_requests_per_call) and [`filter_args`](#filter_args-filter_args). - -#### `.select` - -This method adds a [`Select`](#selects-boundedvecoptionselect-n) criterion to the options. - -#### `.sort` - -This method adds a [`Sort`](#sorts-boundedvecoptionsort-n) criterion to the options. - -#### `.set_limit` - -This method lets you set a limit for the maximum number of notes to be retrieved. - -#### `.set_offset` - -This method sets the offset value, which determines where to start retrieving notes. - -#### Examples - -The following code snippet creates an instance of `NoteGetterOptions`, which has been configured to find the cards that belong to `account_address`. The returned cards are sorted by their points in descending order, and the first `offset` cards with the highest points are skipped. - -#include_code state_vars-NoteGetterOptionsSelectSortOffset /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust - -The first value of `.select` and `.sort` is the index of a field in a note type. For the note type `CardNote` that has the following fields: - -#include_code state_vars-CardNote /yarn-project/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust - -The indices are: 0 for `points`, 1 for `secret`, and 2 for `owner`. - -In the example, `.select(2, account_address)` matches the 2nd field of `CardNote`, which is `owner`, and returns the cards whose `owner` field equals `account_address`. - -`.sort(0, SortOrder.DESC)` sorts the 0th field of `CardNote`, which is `points`, in descending order. - -There can be as many conditions as the number of fields a note type has. The following example finds cards whose fields match the three given values: - -#include_code state_vars-NoteGetterOptionsMultiSelects /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust - -While `selects` lets us find notes with specific values, `filter` lets us find notes in a more dynamic way. The function below picks the cards whose points are at least `min_points`: - -#include_code state_vars-OptionFilter /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust - -We can use it as a filter to further reduce the number of the final notes: - -#include_code state_vars-NoteGetterOptionsFilter /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust - -One thing to remember is, `filter` will be applied on the notes after they are picked from the database. Therefore, it's possible that the actual notes we end up getting are fewer than the limit. - -The limit is `MAX_READ_REQUESTS_PER_CALL` by default. But we can set it to any value **smaller** than that: - -#include_code state_vars-NoteGetterOptionsPickOne /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust diff --git a/docs/docs/dev_docs/getting_started/core-concepts.md b/docs/docs/dev_docs/getting_started/core-concepts.md deleted file mode 100644 index e4549fb9731..00000000000 --- a/docs/docs/dev_docs/getting_started/core-concepts.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Core Concepts ---- - -import Image from '@theme/IdealImage'; - -This page outlines Aztec concepts that are essential for developers to understand. Understanding these concepts will help you as you start to dive deeper into smart contracts. - -A little bit of time here can save a lot down the road. - -## Aztec Overview - - - -To sum this up: - -1. A user interacts with Aztec through Aztec.js (like web3js or ethersjs) or Aztec CLI -2. Private functions are executed in the PXE, which is client-side -3. They are rolled up and sent to the Public VM (running on an Aztec node) -4. Public functions are executed in the Public VM -5. The Public VM rolls up the private & public transaction rollups -6. These rollups are submitted to Ethereum - -## Composability between private and public state - -The PXE is unaware of the Public VM. And the Public VM is unaware of the PXE. They are completely separate execution environments. This means: - -- The PXE and the Public VM cannot directly communicate with each other -- Private transactions in the PXE are executed first, followed by public transactions - -You can call a public function from a private function by using `context.call_public_function`, like this: - -#include_code call_public_function yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr rust - -You cannot call a private function from a public function, but you can use a [slow updates tree](../contracts/syntax/slow_updates_tree.md) to read historical public state and stage writes to public state from a private function. - -### Data types - -Private state works with UTXOs, or what we call notes. To keep things private, everything is stored in an [append-only UTXO tree](../../concepts/advanced/data_structures/trees.md#note-hash-tree), and a nullifier is created when notes are invalidated. - -Public state works similarly to other chains like Ethereum, behaving like a public ledger. - -Working with private state is like creating commitments and nullifiers to state, whereas working with public state is like directly updating state. - -We have abstractions for working with private state so you don't have to worry about these commitments and nullifiers. However, it is important to understand that the types and libraries you use will be different when working with private state and public state. - -For example, let's say you're trying to work with an integer. We have a library called `EasyPrivateUint` that acts like an integer but in the background is actually updating notes in private state. For the public side, we instead have something called `SafeU120`. You cannot use EasyPrivateUint in a public environment, and you cannot use SafeU120 in a private environment. - -## Storage - -Currently, when writing Aztec.nr smart contracts, you will need to define two things when initiating storage: - -1. The storage struct, ie what you are storing and their types -2. A storage `impl` block with `init` function that will be called when you use the storage in a function - -The `init` function must declare the storage struct with an instantiation defining how variables are accessed and manipulated. Each variable must be given a storage slot, which can be anything except 0. - -The impl block is likely to be abstracted away at a later date. - -Learn more about how to use storage [here](../contracts/syntax/storage/main.md). - -## Portals - -Aztec allows you to interact with Ethereum privately - ie no-one knows where the transaction is coming from, just that it is coming from somewhere on Aztec. - -This is achieved through portals - these are smart contracts written in Solidity that are related to the Ethereum smart contract you want to interact with. - -A portal can be associated with multiple Aztec contracts, but an Aztec contract can only be associated with one portal. - -Learn more about how to work with portals [here](../contracts/portals/main.md). - -## Accounts - -Every account in Aztec is a smart contract (account abstraction). This allows implementing different schemes for transaction signing, nonce management, and fee payments. - -You can write your own account contract to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed. - -Learn more about account contracts [here](../../concepts/foundation/accounts/main.md). - -## Noir Language - -Aztec smart contracts are written in a framework on top of Noir, the zero-knowledge domain-specific language developed specifically for Aztec. Its syntax is similar to Rust. Outside of Aztec, Noir is used for writing circuits that can be verified in Solidity. - -A cursory understanding of Noir is sufficient for writing Aztec contracts. The [Noir docs](https://noir-lang.org) will be a helpful reference when you start writing more advanced contracts. - -## Next steps - -Continue through the getting started section by reviewing how to write a smart contract contract in [Getting started with Aztec.nr](./aztecnr-getting-started.md). diff --git a/docs/docs/dev_docs/aztecjs/main.md b/docs/docs/developers/aztecjs/main.md similarity index 100% rename from docs/docs/dev_docs/aztecjs/main.md rename to docs/docs/developers/aztecjs/main.md diff --git a/docs/docs/dev_docs/cli/blank_box.md b/docs/docs/developers/cli/blank_box.md similarity index 100% rename from docs/docs/dev_docs/cli/blank_box.md rename to docs/docs/developers/cli/blank_box.md diff --git a/docs/docs/dev_docs/cli/cli-commands.md b/docs/docs/developers/cli/cli-commands.md similarity index 97% rename from docs/docs/dev_docs/cli/cli-commands.md rename to docs/docs/developers/cli/cli-commands.md index 080dd071ab5..83c107365d8 100644 --- a/docs/docs/dev_docs/cli/cli-commands.md +++ b/docs/docs/developers/cli/cli-commands.md @@ -41,11 +41,11 @@ You can find more information about compiling contracts [on this page](../contra ## Creating Accounts -The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../concepts/foundation/accounts/keys.md): +The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../learn/concepts/accounts/keys.md): #include_code create-account yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys). +Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../learn/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys). Save the Address and Private key as environment variables. We will be using them later. diff --git a/docs/docs/dev_docs/cli/main.md b/docs/docs/developers/cli/main.md similarity index 100% rename from docs/docs/dev_docs/cli/main.md rename to docs/docs/developers/cli/main.md diff --git a/docs/docs/dev_docs/cli/run_more_than_one_pxe_sandbox.md b/docs/docs/developers/cli/run_more_than_one_pxe_sandbox.md similarity index 100% rename from docs/docs/dev_docs/cli/run_more_than_one_pxe_sandbox.md rename to docs/docs/developers/cli/run_more_than_one_pxe_sandbox.md diff --git a/docs/docs/dev_docs/cli/sandbox-reference.md b/docs/docs/developers/cli/sandbox-reference.md similarity index 93% rename from docs/docs/dev_docs/cli/sandbox-reference.md rename to docs/docs/developers/cli/sandbox-reference.md index 97dfc98998a..8fb0866d331 100644 --- a/docs/docs/dev_docs/cli/sandbox-reference.md +++ b/docs/docs/developers/cli/sandbox-reference.md @@ -56,13 +56,24 @@ cd ~/.aztec && docker-compose up ## Running Aztec PXE / Node / P2P-Bootstrap node -If you wish to run components of the Aztec network stack separately, you can still use the Sandbox by including a `MODE` variable. -The values for `MODE` can be: +If you wish to run components of the Aztec network stack separately, you can use the `aztec start` command with various options for enabling components. -- sandbox (default) -- node -- pxe -- p2p-bootstrap +```bash +aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] ----p2p-bootstrap [p2pOptions] +``` + +Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node. If you want to e.g. run a PXE separately to a node, you can: +Start a node: + +```bash +aztec start --node [node] --archiver [archiverOptions] +``` + +Then start a PXE on a separate terminal that connects to that node: + +```bash +aztec start --pxe nodeUrl=http://localhost:8080 +``` ## Environment Variables diff --git a/docs/docs/dev_docs/contracts/abi.md b/docs/docs/developers/contracts/abi.md similarity index 100% rename from docs/docs/dev_docs/contracts/abi.md rename to docs/docs/developers/contracts/abi.md diff --git a/docs/docs/dev_docs/contracts/artifacts.md b/docs/docs/developers/contracts/artifacts.md similarity index 100% rename from docs/docs/dev_docs/contracts/artifacts.md rename to docs/docs/developers/contracts/artifacts.md diff --git a/docs/docs/dev_docs/contracts/compiling.md b/docs/docs/developers/contracts/compiling.md similarity index 98% rename from docs/docs/dev_docs/contracts/compiling.md rename to docs/docs/developers/contracts/compiling.md index 8d19f7811a8..1351006ed65 100644 --- a/docs/docs/dev_docs/contracts/compiling.md +++ b/docs/docs/developers/contracts/compiling.md @@ -217,7 +217,7 @@ At the moment, the compiler generates these interfaces from already compiled ABI ## Next steps -Once you have compiled your contracts, you can use the generated artifacts via the `Contract` class in the `aztec.js` package to deploy and interact with them, or rely on the type-safe typescript classes directly. Alternatively, use the CLI [to deploy](../../dev_docs/cli/main.md#deploying-a-token-contract) and [interact](../../dev_docs/cli/main.md#sending-a-transaction) with them. +Once you have compiled your contracts, you can use the generated artifacts via the `Contract` class in the `aztec.js` package to deploy and interact with them, or rely on the type-safe typescript classes directly. Alternatively, use the CLI [to deploy](../../developers/cli/main.md#deploying-a-token-contract) and [interact](../../developers/cli/main.md#sending-a-transaction) with them. import Disclaimer from "../../misc/common/\_disclaimer.mdx"; diff --git a/docs/docs/dev_docs/contracts/deploying.md b/docs/docs/developers/contracts/deploying.md similarity index 98% rename from docs/docs/dev_docs/contracts/deploying.md rename to docs/docs/developers/contracts/deploying.md index c2db9fc764a..ec9d88ef1f4 100644 --- a/docs/docs/dev_docs/contracts/deploying.md +++ b/docs/docs/developers/contracts/deploying.md @@ -6,7 +6,7 @@ Once you have [compiled](./compiling.md) your contracts you can proceed to deplo - `aztec-cli` and `aztec-nargo` installed (go to [CLI main section](../cli/main.md) for installation instructions) - contract artifacts ready (go to [Compiling contracts section](./compiling.md) for instructions on how to compile contracts) -- aztec-sandbox running (go to [Sandbox section](../getting_started/quickstart.md) for instructions on how to install and run the sandbox) +- Aztec Sandbox running (go to [Sandbox section](../getting_started/quickstart.md) for instructions on how to install and run the sandbox) ## Deploy diff --git a/docs/docs/dev_docs/contracts/example-contract.md b/docs/docs/developers/contracts/example-contract.md similarity index 100% rename from docs/docs/dev_docs/contracts/example-contract.md rename to docs/docs/developers/contracts/example-contract.md diff --git a/docs/docs/dev_docs/contracts/layout.md b/docs/docs/developers/contracts/layout.md similarity index 100% rename from docs/docs/dev_docs/contracts/layout.md rename to docs/docs/developers/contracts/layout.md diff --git a/docs/docs/dev_docs/contracts/main.md b/docs/docs/developers/contracts/main.md similarity index 100% rename from docs/docs/dev_docs/contracts/main.md rename to docs/docs/developers/contracts/main.md diff --git a/docs/docs/dev_docs/contracts/portals/data_structures.md b/docs/docs/developers/contracts/portals/data_structures.md similarity index 100% rename from docs/docs/dev_docs/contracts/portals/data_structures.md rename to docs/docs/developers/contracts/portals/data_structures.md diff --git a/docs/docs/dev_docs/contracts/portals/inbox.md b/docs/docs/developers/contracts/portals/inbox.md similarity index 100% rename from docs/docs/dev_docs/contracts/portals/inbox.md rename to docs/docs/developers/contracts/portals/inbox.md diff --git a/docs/docs/dev_docs/contracts/portals/main.md b/docs/docs/developers/contracts/portals/main.md similarity index 97% rename from docs/docs/dev_docs/contracts/portals/main.md rename to docs/docs/developers/contracts/portals/main.md index ab0654dba98..11fc1c0b9de 100644 --- a/docs/docs/dev_docs/contracts/portals/main.md +++ b/docs/docs/developers/contracts/portals/main.md @@ -7,7 +7,7 @@ description: Documentation of Aztec's Portals and Cross-chain communication. A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. -As outlined in the [foundational concepts](../../../concepts/foundation/communication/cross_chain_calls.md), an Aztec L2 contract is linked to _ONE_ L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. +As outlined in [Communication](../../../learn/concepts/communication/cross_chain_calls.md), an Aztec L2 contract is linked to _ONE_ L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. ## Passing data to the rollup diff --git a/docs/docs/dev_docs/contracts/portals/outbox.md b/docs/docs/developers/contracts/portals/outbox.md similarity index 100% rename from docs/docs/dev_docs/contracts/portals/outbox.md rename to docs/docs/developers/contracts/portals/outbox.md diff --git a/docs/docs/dev_docs/contracts/portals/registry.md b/docs/docs/developers/contracts/portals/registry.md similarity index 100% rename from docs/docs/dev_docs/contracts/portals/registry.md rename to docs/docs/developers/contracts/portals/registry.md diff --git a/docs/docs/dev_docs/contracts/resources/common_patterns/authwit.md b/docs/docs/developers/contracts/resources/common_patterns/authwit.md similarity index 97% rename from docs/docs/dev_docs/contracts/resources/common_patterns/authwit.md rename to docs/docs/developers/contracts/resources/common_patterns/authwit.md index 54e5c3c8dd3..5700644561b 100644 --- a/docs/docs/dev_docs/contracts/resources/common_patterns/authwit.md +++ b/docs/docs/developers/contracts/resources/common_patterns/authwit.md @@ -5,13 +5,13 @@ description: Developer Documentation to use Authentication Witness for authentic ## Prerequisite reading -- [Authwit from Foundational Concepts](./../../../../concepts/foundation/accounts/authwit.md) +- [Authwit](./../../../../learn/concepts/accounts/authwit.md) ## Introduction Authentication Witness is a scheme for authentication actions on Aztec, so users can allow third-parties (eg protocols or other users) to execute an action on their behalf. -How it works logically is explained in the [foundational concepts](./../../../../concepts/foundation/accounts/authwit.md) but we will do a short recap here. +How it works logically is explained in the [foundational concepts](./../../../../learn/concepts/accounts/authwit.md) but we will do a short recap here. An authentication witness is defined for a specific action, such as allowing a Defi protocol to transfer funds on behalf of the user. An action is here something that could be explained as `A is allowed to perform X operation on behalf of B` and we define it as a hash computed as such: @@ -168,7 +168,7 @@ With private functions covered, how can we use this in a public function? Well, Authenticating an action in the public domain is quite similar to the private domain, with the difference that we are executing a function on the account contract to add the witness, if you recall, this is because we don't have access to the oracle in the public domain. -In the snippet below, this is done as a separate contract call, but can also be done as part of a batch as mentioned in the [foundational concepts](./../../../../concepts/foundation/accounts/authwit.md#what-about-public). +In the snippet below, this is done as a separate contract call, but can also be done as part of a batch as mentioned in the [Accounts concepts](./../../../../learn/concepts/accounts/authwit.md#what-about-public). #include_code authwit_public_transfer_example /yarn-project/end-to-end/src/e2e_token_contract.test.ts typescript diff --git a/docs/docs/dev_docs/contracts/resources/common_patterns/main.md b/docs/docs/developers/contracts/resources/common_patterns/main.md similarity index 96% rename from docs/docs/dev_docs/contracts/resources/common_patterns/main.md rename to docs/docs/developers/contracts/resources/common_patterns/main.md index 18592c18902..5d54f7b6e35 100644 --- a/docs/docs/dev_docs/contracts/resources/common_patterns/main.md +++ b/docs/docs/developers/contracts/resources/common_patterns/main.md @@ -48,7 +48,7 @@ Note - you could also create a note and send it to the user. The problem is ther You can't read public storage in private domain. But nevertheless reading public storage is desirable. There are two ways: -1. For public storage that changes infrequently, use the slow updates tree! Learn more about it [here](../../../../concepts/foundation/communication/public_private_calls/slow_updates_tree.md). +1. For public storage that changes infrequently, use the slow updates tree! Learn more about it [here](../../../../learn/concepts/communication/public_private_calls/slow_updates_tree.md). 2. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.: @@ -93,7 +93,7 @@ This pattern is discussed in detail in [writing a token contract section in the ### Discovering my notes -When you send someone a note, the note hash gets added to the [note hash tree](../../../../concepts/advanced/data_structures/trees#note-hash-tree). To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes: +When you send someone a note, the note hash gets added to the [note hash tree](../../../../learn/concepts/storage/trees/main.md#note-hash-tree). To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes: 1. When sending someone a note, use `emit_encrypted_log` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](../../syntax/events.md) 2. Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`emit_encrypted_log` shouldn't be called in the public domain because everything is public), like in the previous section where we created a TransparentNote in public. @@ -169,6 +169,6 @@ PS: when calling from private to public, `msg_sender` is the contract address wh In the [Prevent the same user flow from happening twice using nullifier](#prevent-the-same-user-flow-from-happening-twice-using-nullifiers), we recommended using nullifiers. But what you put in the nullifier is also as important. -E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](../../../../concepts/foundation/accounts/keys.md#nullifier-secrets). E.g.: +E.g. for a voting contract, if your nullifier simply emits just the `user_address`, then privacy can easily be leaked as nullifiers are deterministic (have no randomness), especially if there are few users of the contract. So you need some kind of randomness. You can add the user's secret key into the nullifier to add randomness. We call this "nullifier secrets" as explained [here](../../../../learn/concepts/accounts/keys.md#nullifier-secrets). E.g.: #include_code nullifier /yarn-project/aztec-nr/value-note/src/value_note.nr rust diff --git a/docs/docs/dev_docs/contracts/resources/dependencies.md b/docs/docs/developers/contracts/resources/dependencies.md similarity index 100% rename from docs/docs/dev_docs/contracts/resources/dependencies.md rename to docs/docs/developers/contracts/resources/dependencies.md diff --git a/docs/docs/dev_docs/contracts/resources/main.md b/docs/docs/developers/contracts/resources/main.md similarity index 100% rename from docs/docs/dev_docs/contracts/resources/main.md rename to docs/docs/developers/contracts/resources/main.md diff --git a/docs/docs/dev_docs/contracts/resources/style_guide.md b/docs/docs/developers/contracts/resources/style_guide.md similarity index 100% rename from docs/docs/dev_docs/contracts/resources/style_guide.md rename to docs/docs/developers/contracts/resources/style_guide.md diff --git a/docs/docs/dev_docs/contracts/security/breaking_changes/main.md b/docs/docs/developers/contracts/security/breaking_changes/main.md similarity index 100% rename from docs/docs/dev_docs/contracts/security/breaking_changes/main.md rename to docs/docs/developers/contracts/security/breaking_changes/main.md diff --git a/docs/docs/dev_docs/contracts/security/breaking_changes/v0.md b/docs/docs/developers/contracts/security/breaking_changes/v0.md similarity index 100% rename from docs/docs/dev_docs/contracts/security/breaking_changes/v0.md rename to docs/docs/developers/contracts/security/breaking_changes/v0.md diff --git a/docs/docs/dev_docs/contracts/security/main.md b/docs/docs/developers/contracts/security/main.md similarity index 100% rename from docs/docs/dev_docs/contracts/security/main.md rename to docs/docs/developers/contracts/security/main.md diff --git a/docs/docs/dev_docs/contracts/setup.md b/docs/docs/developers/contracts/setup.md similarity index 100% rename from docs/docs/dev_docs/contracts/setup.md rename to docs/docs/developers/contracts/setup.md diff --git a/docs/docs/dev_docs/contracts/syntax/constrain.md b/docs/docs/developers/contracts/syntax/constrain.md similarity index 100% rename from docs/docs/dev_docs/contracts/syntax/constrain.md rename to docs/docs/developers/contracts/syntax/constrain.md diff --git a/docs/docs/dev_docs/contracts/syntax/context.mdx b/docs/docs/developers/contracts/syntax/context.mdx similarity index 93% rename from docs/docs/dev_docs/contracts/syntax/context.mdx rename to docs/docs/developers/contracts/syntax/context.mdx index 3321cd91c4a..8f6ee0d937f 100644 --- a/docs/docs/dev_docs/contracts/syntax/context.mdx +++ b/docs/docs/developers/contracts/syntax/context.mdx @@ -10,7 +10,7 @@ import Image from "@theme/IdealImage"; ## What is the context -The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. +The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../../learn/concepts/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. Behind the scenes, Aztec.nr will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. @@ -23,7 +23,7 @@ On this page, you'll learn - Differences between the private and public contexts, especially the unique features and variables in the public context ## Two context's one API -The `Aztec` blockchain contains two environments [public and private](../../../concepts/foundation/state_model/main.md). +The `Aztec` blockchain contains two environments [public and private](../../../learn/concepts/hybrid_state/main.md). - Private, for private transactions taking place on user's devices. - Public, for public transactions taking place on the network's sequencers. @@ -129,7 +129,7 @@ The public call stack contains all of the external function calls that are creat ### New L2 to L1 msgs -New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../../concepts/foundation/communication/cross_chain_calls.md) on the execution of each rollup. +New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../../learn/concepts/communication/cross_chain_calls.md) on the execution of each rollup. ## Public Context diff --git a/docs/docs/dev_docs/contracts/syntax/control_structure.md b/docs/docs/developers/contracts/syntax/control_structure.md similarity index 100% rename from docs/docs/dev_docs/contracts/syntax/control_structure.md rename to docs/docs/developers/contracts/syntax/control_structure.md diff --git a/docs/docs/dev_docs/contracts/syntax/events.md b/docs/docs/developers/contracts/syntax/events.md similarity index 100% rename from docs/docs/dev_docs/contracts/syntax/events.md rename to docs/docs/developers/contracts/syntax/events.md diff --git a/docs/docs/dev_docs/contracts/syntax/functions.md b/docs/docs/developers/contracts/syntax/functions.md similarity index 95% rename from docs/docs/dev_docs/contracts/syntax/functions.md rename to docs/docs/developers/contracts/syntax/functions.md index 7bda2b14e87..763f6349cdb 100644 --- a/docs/docs/dev_docs/contracts/syntax/functions.md +++ b/docs/docs/developers/contracts/syntax/functions.md @@ -19,7 +19,7 @@ In Aztec there are multiple different types of visibility that can be applied to ### Data Visibility -Data visibility is used to describe whether the data (or state) used in a function is generally accessible (public) or on a need to know basis (private). Functions with public data visibility are executed by the sequencer, and functions with private data visibility are executed by the user. For more information on why this is the case, see [communication](../../../concepts/foundation/communication/public_private_calls/main.md). +Data visibility is used to describe whether the data (or state) used in a function is generally accessible (public) or on a need to know basis (private). Functions with public data visibility are executed by the sequencer, and functions with private data visibility are executed by the user. For more information on why this is the case, see [communication](../../../learn/concepts/communication/public_private_calls/main.md). In the following sections, we are going to see how these two "types" co-exists and interact. @@ -114,7 +114,7 @@ You can learn how to use oracles in your smart contracts [here](../syntax/oracle ### Private -> Private -In Aztec Private to Private function calls are handled by the [private kernel circuit](../../../concepts/advanced/circuits/kernels/private_kernel.md), and take place on the user's device. +In Aztec Private to Private function calls are handled by the [private kernel circuit](../../../learn/concepts/circuits/kernels/private_kernel.md), and take place on the user's device. Behind the scenes, the `Private Execution Environment (PXE)` (the beating heart of Aztec that runs in your wallet) will execute all of the functions in the desired order "simulating" them in sequence. For example, a very common use-case of Private to Private interaction is calling another private function from an `account contract` (Account contracts are a general concept, more information about them can be found [here](../../wallets/writing_an_account_contract.md)). Take, for example, the following call stack: @@ -187,13 +187,13 @@ The following snippet is from a token bridge that is burning the underlying toke ### Public -> Public -The public execution environment in Aztec takes place on the sequencer through a [Public VM](../../../concepts/advanced/public_vm.md). This execution model is conceptually much simpler than the private transaction model as code is executed and proven on the sequencer. +The public execution environment in Aztec takes place on the sequencer through a [Public VM](../../../learn/concepts/hybrid_state/public_vm.md). This execution model is conceptually much simpler than the private transaction model as code is executed and proven on the sequencer. Using the same example code and call stack from the section [above](#private----private-function-calls), we will walk through how it gets executed in public. The first key difference is that public functions are not compiled to circuits, rather they are compiled to `Aztec Bytecode` (might also be referred to as brillig). -This bytecode is run by the sequencer in the `Aztec VM`, which is in turn proven by the [`Aztec VM circuit`](../../../concepts/advanced/public_vm.md). +This bytecode is run by the sequencer in the `Aztec VM`, which is in turn proven by the [`Aztec VM circuit`](../../../learn/concepts/hybrid_state/public_vm.md). The mental model for public execution carries many of the same idea as are carried by Ethereum. Programs are compiled into a series of opcodes (known as bytecode). This bytecode is then executed. The extra step for the Aztec VM is that each opcode is then proven for correctness. Calling a public function from another public function is quite similar to what we saw for private to private, with the keyword private swapped for public. @@ -203,7 +203,7 @@ Calling a public function from another public function is quite similar to what ### Private -> Public -As discussed above, private function execution and calls take place on the user's device, while public function execution and calls take place on a sequencer, in two different places at two different times, it is natural to question how we can achieve composability between the two. The solution is asynchronicity. Further reading can be found in the foundational concepts [here](../../../concepts/foundation/communication/public_private_calls/main.md). +As discussed above, private function execution and calls take place on the user's device, while public function execution and calls take place on a sequencer, in two different places at two different times, it is natural to question how we can achieve composability between the two. The solution is asynchronicity. Further reading can be found in the foundational concepts [here](../../../learn/concepts/communication/public_private_calls/main.md)). Private function execution takes place on the users device, where it keeps track of any public function calls that have been made. Whenever private execution completes, and a kernel proof is produced, the transaction sent to the network will include all of the public calls that were dispatched. When the sequencer receives the messages, it will take over and execute the public parts of the transaction. @@ -249,7 +249,7 @@ Below, we go more into depth of what is happening under the hood when you create Aztec.nr uses an attribute system to annotate a function's type. Annotating a function with the `#[aztec(private)]` attribute tells the framework that this will be a private function that will be executed on a users device. Thus the compiler will create a circuit to define this function. -However; `#aztec(private)` is just syntactic sugar. At compile time, the framework inserts code that allows the function to interact with the [kernel](../../../concepts/advanced/circuits/kernels/private_kernel.md). +However; `#aztec(private)` is just syntactic sugar. At compile time, the framework inserts code that allows the function to interact with the [kernel](../../../learn/concepts/circuits/kernels/private_kernel.md). To help illustrate how this interacts with the internals of Aztec and its kernel circuits, we can take an example private function, and explore what it looks like after Aztec.nr's macro expansion. @@ -263,12 +263,12 @@ To help illustrate how this interacts with the internals of Aztec and its kernel #### The expansion broken down? -Viewing the expanded noir contract uncovers a lot about how noir contracts interact with the [kernel](../../../concepts/advanced/circuits/kernels/private_kernel.md). To aid with developing intuition, we will break down each inserted line. +Viewing the expanded noir contract uncovers a lot about how noir contracts interact with the [kernel](../../../learn/concepts/circuits/kernels/private_kernel.md). To aid with developing intuition, we will break down each inserted line. **Receiving context from the kernel.** #include_code context-example-inputs /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust -Private function calls are able to interact with each other through orchestration from within the [kernel circuit](../../../concepts/advanced/circuits/kernels/private_kernel.md). The kernel circuit forwards information to each app circuit. This information then becomes part of the private context. +Private function calls are able to interact with each other through orchestration from within the [kernel circuit](../../../learn/concepts/circuits/kernels/private_kernel.md). The kernel circuit forwards information to each app circuit. This information then becomes part of the private context. For example, within each circuit we can access some global variables. To access them we can call `context.chain_id()`. The value of this chain ID comes from the values passed into the circuit from the kernel. The kernel can then check that all of the values passed to each circuit in a function call are the same. diff --git a/docs/docs/dev_docs/contracts/syntax/globals.md b/docs/docs/developers/contracts/syntax/globals.md similarity index 100% rename from docs/docs/dev_docs/contracts/syntax/globals.md rename to docs/docs/developers/contracts/syntax/globals.md diff --git a/docs/docs/dev_docs/contracts/syntax/historical_access/history_lib_reference.md b/docs/docs/developers/contracts/syntax/historical_access/history_lib_reference.md similarity index 98% rename from docs/docs/dev_docs/contracts/syntax/historical_access/history_lib_reference.md rename to docs/docs/developers/contracts/syntax/historical_access/history_lib_reference.md index b798a129243..d7688909262 100644 --- a/docs/docs/dev_docs/contracts/syntax/historical_access/history_lib_reference.md +++ b/docs/docs/developers/contracts/syntax/historical_access/history_lib_reference.md @@ -21,7 +21,7 @@ Note inclusion proves that a note existed (its hash was included in a note hash ## prove_note_commitment_inclusion -A **commitment**, also referred to as a **note hash** is a public acknowledgment of the existence of a note without revealing the content of the note. You can learn more about how to compress a note to a note hash [here](../../../../concepts/advanced/data_structures/trees.md#example-note). +A **commitment**, also referred to as a **note hash** is a public acknowledgment of the existence of a note without revealing the content of the note. You can learn more about how to compress a note to a note hash [here](../../../../learn/concepts/storage/trees/main.md#example-note). `prove_note_commitment_inclusion` takes 3 parameters: diff --git a/docs/docs/dev_docs/contracts/syntax/historical_access/how_to_prove_history.md b/docs/docs/developers/contracts/syntax/historical_access/how_to_prove_history.md similarity index 97% rename from docs/docs/dev_docs/contracts/syntax/historical_access/how_to_prove_history.md rename to docs/docs/developers/contracts/syntax/historical_access/how_to_prove_history.md index 28e3ea04ccf..8441611dbf2 100644 --- a/docs/docs/dev_docs/contracts/syntax/historical_access/how_to_prove_history.md +++ b/docs/docs/developers/contracts/syntax/historical_access/how_to_prove_history.md @@ -2,7 +2,7 @@ title: How to prove existence of historical notes and nullifiers --- -The Aztec Protocol uses an append-only Merkle tree to store hashes of the headers of all previous blocks in the chain as its leaves. This is known as an archive tree. You can learn more about how it works in the [concepts section](../../../../concepts/advanced/data_structures/trees.md#archive-tree). +The Aztec Protocol uses an append-only Merkle tree to store hashes of the headers of all previous blocks in the chain as its leaves. This is known as an archive tree. You can learn more about how it works in the [concepts section](../../../../learn/concepts/storage/trees/main.md#archive-tree). # History library diff --git a/docs/docs/dev_docs/contracts/syntax/main.md b/docs/docs/developers/contracts/syntax/main.md similarity index 100% rename from docs/docs/dev_docs/contracts/syntax/main.md rename to docs/docs/developers/contracts/syntax/main.md diff --git a/docs/docs/dev_docs/contracts/syntax/oracles.md b/docs/docs/developers/contracts/syntax/oracles.md similarity index 100% rename from docs/docs/dev_docs/contracts/syntax/oracles.md rename to docs/docs/developers/contracts/syntax/oracles.md diff --git a/docs/docs/dev_docs/contracts/syntax/slow_updates_tree.md b/docs/docs/developers/contracts/syntax/slow_updates_tree.md similarity index 98% rename from docs/docs/dev_docs/contracts/syntax/slow_updates_tree.md rename to docs/docs/developers/contracts/syntax/slow_updates_tree.md index cfe7d5905f9..3f8538baeb9 100644 --- a/docs/docs/dev_docs/contracts/syntax/slow_updates_tree.md +++ b/docs/docs/developers/contracts/syntax/slow_updates_tree.md @@ -2,7 +2,7 @@ title: Slow Updates Tree --- -Slow Updates Tree is a data structure that allows for historical public data to be accessed in both private and public domains. Read the high level overview in the [concepts section](../../../concepts/foundation/communication/public_private_calls/slow_updates_tree.md). +Slow Updates Tree is a data structure that allows for historical public data to be accessed in both private and public domains. Read the high level overview in the [Communication section](../../../learn/concepts/communication/public_private_calls/slow_updates_tree.md). The slow updates tree works by having a current tree and a pending tree, and replacing the current tree with the pending tree after an epoch has passed. Public functions can read directly from the current tree, and private functions can perform a membership proof that values are part of a commitment to the current state of the tree. diff --git a/docs/docs/developers/contracts/syntax/storage/main.md b/docs/docs/developers/contracts/syntax/storage/main.md new file mode 100644 index 00000000000..7e9b382f82d --- /dev/null +++ b/docs/docs/developers/contracts/syntax/storage/main.md @@ -0,0 +1,133 @@ +--- +title: Storage +--- + +Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its hybrid, privacy-first architecture, the management of this storage is more complex than other blockchains like Ethereum. + +You control this storage in Aztec using the `Storage` struct. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. + +These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. + +Aztec.nr has a few abstractions to help define the type of data your contract holds. These include Singletons, ImmutableSingletons, Set, and Map. + +On this and the following pages in this section, you’ll learn: + +- How to manage a smart contract's storage structure +- The distinctions and applications of public and private state variables +- How to use Singleton, ImmutableSingleton, Set, and Map +- An overview of 'notes' and the UTXO model +- Practical implications of Storage in real smart contracts + In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. + +## Public and private state variables + +Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data or note viewing key with). + +Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (pre-images) are only known by the sender and those able to decrypt them - see ([state model](../../../../learn/concepts/hybrid_state/main.md) and [private/public execution](../../../../learn/concepts/communication/public_private_calls/main.md)) for more background. + +## Storage struct + +:::info +The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (this will be relaxed in the future). +::: + +```rust +struct Storage { + // public state variables + // private state variables +} +``` + +:::danger +If your contract uses storage (has Storage struct defined), you **MUST** include a `compute_note_hash_and_nullifier` function to allow PXE to process encrypted events. See [encrypted events](../events.md#processing-encrypted-events) for more. + +If you don't yet have any private state variables defined you can use this placeholder function: + +#include_code compute_note_hash_and_nullifier_placeholder /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust +::: + +Since Aztec.nr is written in Noir, which is state-less, we need to specify how the storage struct should be initialized to read and write data correctly. This is done by specifying an `init` function that is run in functions that rely on reading or altering the state variables. This `init` function must declare the Storage struct with an instantiation defining how variables are accessed and manipulated. The function MUST be called `init` for the Aztec.nr library to properly handle it (this will be relaxed in the future). + +```rust +impl Storage { + fn init(context: Context) -> Self { + Storage { + // (public state variables)::new() + // (private state variables)::new() + } + } +} +``` + +If you have defined a `Storage` struct following this naming scheme, then it will be made available to you through the reserved `storage` keyword within your contract functions. + +:::warning Using slot `0` is not supported! +No storage values should be initialized at slot `0` - storage slots begin at `1`. This is a known issue that will be fixed in the future. +::: + +## Map + +A `map` is a state variable that "maps" a key to a value. It can be used with private or public storage variables. + +:::info +In Aztec.nr, keys are always `Field`s, or types that can be serialized as Fields, and values can be any type - even other maps. `Field`s are finite field elements, but you can think of them as integers. +::: + +It includes a [`Context`](../context.mdx) to specify the private or public domain, a `storage_slot` to specify where in storage the map is stored, and a `start_var_constructor` which tells the map how it should operate on the underlying type. This includes how to serialize and deserialize the type, as well as how commitments and nullifiers are computed for the type if it's private. + +You can view the implementation in the Aztec.nr library [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/map.nr). + +### `new` + +When declaring the storage for a map, we use the `Map::new()` constructor. As seen below, this takes the `storage_slot` and the `start_var_constructor` along with the [`Context`](../context.mdx). + +We will see examples of map constructors for public and private variables in later sections. + +#### As private storage + +When declaring a mapping in private storage, we have to specify which type of Note to use. In the example below, we are specifying that we want to use the `Singleton` note type. + +In the Storage struct: + +#include_code storage-map-singleton-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +In the `Storage::init` function: + +#include_code state_vars-MapSingleton /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +#### Public Example + +When declaring a public mapping in Storage, we have to specify that the type is public by declaring it as `PublicState` instead of specifying a note type like with private storage above. + +In the Storage struct: + +#include_code storage_minters /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +In the `Storage::init` function: + +#include_code storage_minters_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### `at` + +When dealing with a Map, we can access the value at a given key using the `::at` method. This takes the key as an argument and returns the value at that key. + +This function behaves similarly for both private and public maps. An example could be if we have a map with `minters`, which is mapping addresses to a flag for whether they are allowed to mint tokens or not. + +#include_code read_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +Above, we are specifying that we want to get the storage in the Map `at` the `msg_sender()`, read the value stored and check that `msg_sender()` is indeed a minter. Doing a similar operation in Solidity code would look like: + +```solidity +require(minters[msg.sender], "caller is not minter"); +``` + +## Further Reading + +- Managing [Public State](./public_state.md) +- Jump to the page on [Private State](./private_state.md) + +## Concepts mentioned + +- [Hybrid State Model](../../../../learn/concepts/hybrid_state/main.md) +- [Public-private execution](../../../../learn/concepts/communication/public_private_calls/main.md) +- [Function Contexts](../context.mdx) diff --git a/docs/docs/developers/contracts/syntax/storage/private_state.md b/docs/docs/developers/contracts/syntax/storage/private_state.md new file mode 100644 index 00000000000..e1b2064dfa0 --- /dev/null +++ b/docs/docs/developers/contracts/syntax/storage/private_state.md @@ -0,0 +1,337 @@ +--- +title: Private State +--- + +On this page we will look at how to manage private state in Aztec contracts. We will look at how to declare private state, how to read and write to it, and how to use it in your contracts. + +For a higher level overview of the state model in Aztec, see the [hybrid state model](../../../../learn/concepts/hybrid_state/main.md) page, or jump back to the previous page on [Storage](./main.md). + +## Overview + +In contrast to public state, private state is persistent state that is **not** visible to the whole world. Depending on the logic of the smart contract, a private state variable's current value will only be known to one entity, or a closed group of entities. + +The value of a private state variable can either be shared via an [encrypted log](../events.md#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. + +Aztec private state follows a [utxo](https://en.wikipedia.org/wiki/Unspent_transaction_output)-based model. That is, a private state's current value is represented as one or many [notes](#notes). Each note is stored as an individual leaf in a utxo-based merkle tree: the [private state tree](../../../../learn/concepts/storage/trees/main.md). + +To greatly simplify the experience of writing private state, Aztec.nr provides three different types of private state variable: + +- [Singleton](#singletonnotetype) +- [ImmutableSingleton](#immutablesingletonnotetype) +- [Set](#setnotetype) + +These three structs abstract-away many of Aztec's protocol complexities, by providing intuitive methods to modify notes in the utxo tree in a privacy-preserving way. + +:::info +An app can also choose to emit data via unencrypted log, or to define a note whose data is easy to figure out, then the information is technically not private and could be visible to anyone. +::: + +### Notes + +Unlike public state variables, which can be arbitrary types, private state variables operate on `NoteType`. + +Notes are the fundamental elements in the private world. + +A note should conform to the following interface: + +#include_code NoteInterface /yarn-project/aztec-nr/aztec/src/note/note_interface.nr rust + +The interplay between a private state variable and its notes can be confusing. Here's a summary to aid intuition: + +A private state variable (of type `Singleton`, `ImmutableSingleton` or `Set`) may be declared in storage. + +Every note contains a header, which contains the contract address and storage slot of the state variable to which it is associated. A note is associated with a private state variable if the storage slot of the private state variable matches the storage slot contained in the note's header. The header provides information that helps the user interpret the note's data. + +Management of the header is abstracted-away from developers who use the `ImmutableSingleton`, `Singleton` and `Set` types. + +A private state variable points to one or many notes (depending on the type). The note(s) are all valid private state if the note(s) haven't yet been nullified. + +An `ImmutableSingleton` will point to _one_ note over the lifetime of the contract. This note is a struct of information that is persisted forever. + +A `Singleton` may point to _one_ note at a time. But since it's not "immutable", the note that it points to may be [replaced](#replace) by functions of the contract. The current value of a `Singleton` is interpreted as the one note which has not-yet been nullified. The act of replacing a Singleton's note is how a `Singleton` state may be modified by functions. + +`Singleton` is a useful type when declaring a private state variable which may only ever be modified by those who are privy to the current value of that state. + +A `Set` may point to _multiple_ notes at a time. The "current value" of a private state variable of type `Set` is some accumulation of all not-yet nullified notes which belong to the `Set`. + +:::note +The term "some accumulation" is intentionally vague. The interpretation of the "current value" of a `Set` must be expressed by the smart contract developer. A common use case for a `Set` is to represent the sum of a collection of values (in which case 'accumulation' is 'summation'). + +Think of a ZCash balance (or even a Bitcoin balance). The "current value" of a user's ZCash balance is the sum of all unspent (not-yet nullified) notes belonging to that user. To modify the "current value" of a `Set` state variable, is to [`insert`](#insert) new notes into the `Set`, or [`remove`](#remove) notes from that set. +::: + +Interestingly, if a developer requires a private state to be modifiable by users who _aren't_ privy to the value of that state, a `Set` is a very useful type. The `insert` method allows new notes to be added to the `Set` without knowing any of the other notes in the set! (Like posting an envelope into a post box, you don't know what else is in there!). + +## `Singleton` + +Singleton is a private state variable that is unique in a way. When a Singleton is initialized, a note is created to represent its value. And the way to update the value is to destroy the current note, and create a new one with the updated value. + +Like for public state, we define the struct to have context, a storage slot and `note_interface` specifying how the note should be constructed and manipulated. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr). + +An example of singleton usage in the account contracts is keeping track of public keys. The `Singleton` is added to the `Storage` struct as follows: + +#include_code storage-singleton-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +### `new` + +As part of the initialization of the `Storage` struct, the `Singleton` is created as follows, here at the specified storage slot and with the `NoteInterface` for `CardNote`. + +#include_code start_vars_singleton /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +### `initialize` + +As mentioned, the Singleton is initialized to create the first note and value. + +When this function is called, a nullifier of the storage slot is created, preventing this Singleton from being initialized again. + +:::danger Privacy-Leak +Beware that because this nullifier is created only from the storage slot without randomness it leaks privacy. This means that it is possible for an external observer to determine when the note is nullified. + +For example, if the storage slot depends on the an address then it is possible to link the nullifier to the address. If the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. +::: + +Unlike public states, which have a default initial value of `0` (or many zeros, in the case of a struct, array or map), a private state (of type `Singleton`, `ImmutableSingleton` or `Set`) does not have a default initial value. The `initialize` method (or `insert`, in the case of a `Set`) must be called. + +:::info +Extend on what happens if you try to use non-initialized state. +::: + +### `is_initialized` + +An unconstrained method to check whether the Singleton has been initialized or not. It takes an optional owner and returns a boolean. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/singleton.nr). + +#include_code singleton_is_initialized /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +### `replace` + +To update the value of a `Singleton`, we can use the `replace` method. The method takes a new note as input, and replaces the current note with the new one. It emits a nullifier for the old value, and inserts the new note into the data tree. + +An example of this is seen in a example card game, where we create a new note (a `CardNote`) containing some new data, and replace the current note with it: + +#include_code state_vars-SingletonReplace /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +If two people are trying to modify the Singleton at the same time, only one will succeed as we don't allow duplicate nullifiers! Developers should put in place appropriate access controls to avoid race conditions (unless a race is intended!). + +### `get_note` + +This function allows us to get the note of a Singleton, essentially reading the value. + +#include_code state_vars-SingletonGet /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust + +#### Nullifying Note reads + +To ensure that a user's private execution always uses the latest value of a Singleton, the `get_note` function will nullify the note that it is reading. This means that if two people are trying to use this function with the same note, only one will succeed (no duplicate nullifiers allowed). + +This also makes read operations indistinguishable from write operations and allows the sequencer to verifying correct execution without learning anything about the value of the note. + +### `view_note` + +Functionally similar to [`get_note`](#get_note), but executed in unconstrained functions and can be used by the wallet to fetch notes for use by front-ends etc. + +## `ImmutableSingleton` + +`ImmutableSingleton` represents a unique private state variable that, as the name suggests, is immutable. Once initialized, its value cannot be altered. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr). + +### `new` + +As part of the initialization of the `Storage` struct, the `Singleton` is created as follows, here at storage slot 1 and with the `NoteInterface` for `PublicKeyNote`. + +#include_code storage_init /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust + +### `initialize` + +When this function is invoked, it creates a nullifier for the storage slot, ensuring that the ImmutableSingleton cannot be initialized again. + +:::danger Privacy-Leak +Beware that because this nullifier is created only from the storage slot without randomness it leaks privacy. This means that it is possible for an external observer to determine when the note is nullified. + +For example, if the storage slot depends on the an address then it is possible to link the nullifier to the address. If the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. +::: + +Set the value of an ImmutableSingleton by calling the `initialize` method: + +#include_code initialize /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust + +Once initialized, an ImmutableSingleton's value remains unchangeable. This method can only be called once. + +### `is_initialized` + +An unconstrained method to check if the ImmutableSingleton has been initialized. Takes an optional owner and returns a boolean. You can find the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr). + +### `get_note` + +Similar to the `Singleton`, we can use the `get_note` method to read the value of an ImmutableSingleton. + +Use this method to retrieve the value of an initialized ImmutableSingleton. + +#include_code get_note /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust + +Unlike a `Singleton`, the `get_note` function for an ImmutableSingleton doesn't nullify the current note in the background. This means that multiple accounts can concurrently call this function to read the value. + +This function will throw if the `ImmutableSingleton` hasn't been initialized. + +### `view_note` + +Functionally similar to `get_note`, but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. + +## `Set` + +Set is used for managing a collection of notes. All notes in a Set are of the same `NoteType`. But whether these notes all belong to one entity, or are accessible and editable by different entities, is up to the developer. The set is a collection of notes inserted into the data-tree, but notes are never removed from the tree itself, they are only nullified. + +You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/set.nr). + +And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](../functions.md#public---private)). + +#include_code storage_pending_shields /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### `new` + +The `new` method tells the contract how to operate on the underlying storage. + +We can initialize the set as follows: + +#include_code storage_pending_shields_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### `insert` + +Allows us to modify the storage by inserting a note into the set. + +A hash of the note will be generated, and inserted into the note hash tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an [encrypted log](../events.md#encrypted-events), or offchain via web2, or completely offline. + +#include_code insert /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust + +### `insert_from_public` + +The `insert_from_public` allow public function to insert notes into private storage. This is very useful when we want to support private function calls that have been initiated in public, such as shielding in the [example token contract](../../../tutorials/writing_token_contract.md#shield). + +The usage is similar to using the `insert` method with the difference that this one is called in public functions. + +#include_code insert_from_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### `remove` + +Will remove a note from the set if it previously has been read from storage, e.g. you have fetched it through a `get_notes` call. This is useful when you want to remove a note that you have previously read from storage and do not have to read it again. + +Nullifiers are emitted when reading values to make sure that they are up to date. + +An example of how to use this operation is visible in the `easy_private_state`: + +#include_code remove /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust + +### `get_notes` + +This function returns the notes the account has access to. + +The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. + +Because of this limit, we should always consider using the second argument `NoteGetterOptions` to limit the number of notes we need to read and constrain in our programs. This is quite important as every extra call increases the time used to prove the program and we don't want to spend more time than necessary. + +An example of such options is using the [filter_notes_min_sum](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/value-note/src/filter.nr) to get "enough" notes to cover a given value. Essentially, this function will return just enough notes to cover the amount specified such that we don't need to read all our notes. For users with a lot of notes, this becomes increasingly important. + +#include_code get_notes /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust + +### `view_notes` + +Functionally similar to [`get_notes`](#get_notes), but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. + +#include_code view_notes /yarn-project/aztec-nr/value-note/src/balance_utils.nr rust + +There's also a limit on the maximum number of notes that can be returned in one go. To find the current limit, refer to [this file](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr) and look for `MAX_NOTES_PER_PAGE`. + +The key distinction is that this method is unconstrained. It does not perform a check to verify if the notes actually exist, which is something the [`get_notes`](#get_notes) method does under the hood. Therefore, it should only be used in an unconstrained contract function. + +This function requires a `NoteViewerOptions`. The `NoteViewerOptions` is essentially similar to the [`NoteGetterOptions`](#notegetteroptions), except that it doesn't take a custom filter. + +### NoteGetterOptions + +`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a [data oracle](../functions.md#oracle-functions). Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. + +You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr). + +#### `selects: BoundedVec, N>` + +`selects` is a collection of filtering criteria, specified by `Select { field_index: u8, value: Field }` structs. It instructs the data oracle to find notes whose (`field_index`)th field matches the provided `value`. + +#### `sorts: BoundedVec, N>` + +`sorts` is a set of sorting instructions defined by `Sort { field_index: u8, order: u2 }` structs. This directs the data oracle to sort the matching notes based on the value of the specified field index and in the indicated order. The value of order is **1** for _DESCENDING_ and **2** for _ASCENDING_. + +#### `limit: u32` + +When the `limit` is set to a non-zero value, the data oracle will return a maximum of `limit` notes. + +#### `offset: u32` + +This setting enables us to skip the first `offset` notes. It's particularly useful for pagination. + +#### `filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL]` + +Developers have the option to provide a custom filter. This allows specific logic to be applied to notes that meet the criteria outlined above. The filter takes the notes returned from the oracle and `filter_args` as its parameters. + +It's important to note that the process of applying the custom filter to get the final notes is not constrained. It's crucial to verify the returned notes even if certain assumptions are made in the custom filter. + +#### `filter_args: FILTER_ARGS` + +`filter_args` provides a means to furnish additional data or context to the custom filter. + +#### Methods + +Several methods are available on `NoteGetterOptions` to construct the options in a more readable manner: + +#### `fn new() -> NoteGetterOptions` + +This function initializes a `NoteGetterOptions` that simply returns the maximum number of notes allowed in a call. + +#### `fn with_filter(filter, filter_args) -> NoteGetterOptions` + +This function initializes a `NoteGetterOptions` with a [`filter`](#filter-fn-optionnote-max_read_requests_per_call-filter_args---optionnote-max_read_requests_per_call) and [`filter_args`](#filter_args-filter_args). + +#### `.select` + +This method adds a [`Select`](#selects-boundedvecoptionselect-n) criterion to the options. + +#### `.sort` + +This method adds a [`Sort`](#sorts-boundedvecoptionsort-n) criterion to the options. + +#### `.set_limit` + +This method lets you set a limit for the maximum number of notes to be retrieved. + +#### `.set_offset` + +This method sets the offset value, which determines where to start retrieving notes. + +#### Examples + +The following code snippet creates an instance of `NoteGetterOptions`, which has been configured to find the cards that belong to `account_address`. The returned cards are sorted by their points in descending order, and the first `offset` cards with the highest points are skipped. + +#include_code state_vars-NoteGetterOptionsSelectSortOffset /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust + +The first value of `.select` and `.sort` is the index of a field in a note type. For the note type `CardNote` that has the following fields: + +#include_code state_vars-CardNote /yarn-project/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr rust + +The indices are: 0 for `points`, 1 for `secret`, and 2 for `owner`. + +In the example, `.select(2, account_address)` matches the 2nd field of `CardNote`, which is `owner`, and returns the cards whose `owner` field equals `account_address`. + +`.sort(0, SortOrder.DESC)` sorts the 0th field of `CardNote`, which is `points`, in descending order. + +There can be as many conditions as the number of fields a note type has. The following example finds cards whose fields match the three given values: + +#include_code state_vars-NoteGetterOptionsMultiSelects /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust + +While `selects` lets us find notes with specific values, `filter` lets us find notes in a more dynamic way. The function below picks the cards whose points are at least `min_points`: + +#include_code state_vars-OptionFilter /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust + +We can use it as a filter to further reduce the number of the final notes: + +#include_code state_vars-NoteGetterOptionsFilter /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust + +One thing to remember is, `filter` will be applied on the notes after they are picked from the database. Therefore, it's possible that the actual notes we end up getting are fewer than the limit. + +The limit is `MAX_READ_REQUESTS_PER_CALL` by default. But we can set it to any value **smaller** than that: + +#include_code state_vars-NoteGetterOptionsPickOne /yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr rust diff --git a/docs/docs/developers/contracts/syntax/storage/public_state.md b/docs/docs/developers/contracts/syntax/storage/public_state.md new file mode 100644 index 00000000000..fa66f66ec6f --- /dev/null +++ b/docs/docs/developers/contracts/syntax/storage/public_state.md @@ -0,0 +1,95 @@ +--- +title: Public State +--- + +On this page we will look at how to manage public state in Aztec contracts. We will look at how to declare public state, how to read and write to it, and how to use it in your contracts. + +For a higher level overview of the state model in Aztec, see the [state model](../../../../learn/concepts/hybrid_state/main.md) page, or jump back to the previous page on [Storage](./main.md). + +## Overview + +The `PublicState` struct is generic over the variable type `T` and its serialized size `T_SERIALIZED_LEN`. + +:::info +Currently, the length of the types must be specified when declaring the storage struct but the intention is that this will be inferred in the future. +::: + +The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out _where_ in storage the variable is located. Notice that while we don't have the exact same [state model](../../../../learn/concepts/hybrid_state/main.md) as EVM chains it will look similar from the contract developers point of view. + +Beyond the struct, the `PublicState` also contains `serialization_methods`, which is a struct with methods that instruct the `PublicState` how to serialize and deserialize the variable. You can find the details of `PublicState` in the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr). + +The Aztec.nr library provides serialization methods for various common types. + +:::info +An example using a larger struct can be found in the [lending example](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/lending_contract)'s use of an [`Asset`](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/noir-contracts/contracts/lending_contract/src/asset.nr). +::: + +### `new` + +When declaring the storage for `T` as a persistent public storage variable, we use the `PublicState::new()` constructor. As seen below, this takes the `storage_slot` and the `serialization_methods` as arguments along with the [`Context`](../context.mdx), which in this case is used to share interface with other structures. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr). + +#### Single value example + +Say that we wish to add `admin` public state variable into our storage struct. In the struct we can define it as: + +#include_code storage_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +And then when initializing it in the `Storage::init` function we can do: + +#include_code storage_admin_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +We have specified that we are storing a `Field` that should be placed in storage slot `1`. This is just a single value, and is similar to the following in solidity: + +```solidity +address internal admin; +``` + +:::info +We know its verbose, and are working on making it less so. +::: + +#### Mapping example + +Say we want to have a group of `minters` that are able to mint assets in our contract, and we want them in public storage, because [access control in private is quite cumbersome](../../../../learn/concepts/communication/cross_chain_calls.md#a-note-on-l2-access-control). In the `Storage` struct we can add it as follows: + +#include_code storage_minters /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +And then when initializing it in the `Storage::init` function we can do it as follows: + +#include_code storage_minters_init /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +In this case, specifying that we are dealing with a map of Fields, and that it should be put at slot 2. + +This would be similar to the following in solidity: + +```solidity +mapping(address => bool) internal minters; +``` + +### `read` + +On the `PublicState` structs we have a `read` method to read the value at the location in storage and using the specified deserialization method to deserialize it. + +#### Reading from our `admin` example + +For our `admin` example from earlier, this could be used as follows to check that the stored value matches the `msg_sender()`. + +#include_code read_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### Reading from our `minters` example + +As we saw in the Map earlier, a very similar operation can be done to perform a lookup in a map. + +#include_code read_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### `write` + +We have a `write` method on the `PublicState` struct that takes the value to write as an input and saves this in storage. It uses the serialization method to serialize the value which inserts (possibly multiple) values into storage. + +#### Writing to our `admin` example + +#include_code write_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### Writing to our `minters` example + +#include_code write_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust diff --git a/docs/docs/dev_docs/contracts/syntax/storage/storage_slots.md b/docs/docs/developers/contracts/syntax/storage/storage_slots.md similarity index 88% rename from docs/docs/dev_docs/contracts/syntax/storage/storage_slots.md rename to docs/docs/developers/contracts/syntax/storage/storage_slots.md index dd8d1b01d18..af14fdeebfa 100644 --- a/docs/docs/dev_docs/contracts/syntax/storage/storage_slots.md +++ b/docs/docs/developers/contracts/syntax/storage/storage_slots.md @@ -2,7 +2,7 @@ title: Storage slots --- -From the description of [storage slot in concepts](./../../../../concepts/foundation/state_model/storage_slots.md) you will get an idea around the logic of storage slots. In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against. +From the description of storage slots [in the Concepts](./../../../../learn/concepts/storage/storage_slots.md) you will get an idea around the logic of storage slots. In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against. For the case of the example, we will look at what is inserted into the note hashes tree when adding a note in the Token contract. Specifically, we are looking at the last part of the `transfer` function: diff --git a/docs/docs/dev_docs/contracts/workflow.md b/docs/docs/developers/contracts/workflow.md similarity index 100% rename from docs/docs/dev_docs/contracts/workflow.md rename to docs/docs/developers/contracts/workflow.md diff --git a/docs/docs/dev_docs/debugging/aztecnr-errors.md b/docs/docs/developers/debugging/aztecnr-errors.md similarity index 98% rename from docs/docs/dev_docs/debugging/aztecnr-errors.md rename to docs/docs/developers/debugging/aztecnr-errors.md index 5d7e14aea2a..9e2e8236702 100644 --- a/docs/docs/dev_docs/debugging/aztecnr-errors.md +++ b/docs/docs/developers/debugging/aztecnr-errors.md @@ -57,7 +57,7 @@ This error occurs when you are trying to interact with a smart contract via an P To execute a transaction, the PXE needs to know the complete address of a contract, portal address (if portal is used) and contract artifacts. -To address the error, add the contract to the PXE by calling [`pxe.addContracts(...)`](../../apis/pxe/interfaces/PXE#addcontracts). +To address the error, add the contract to the PXE by calling [`pxe.addContracts(...)`](../../apis/pxe/interfaces/PXE.md#addcontracts). #### `Simulation error: No public key registered for address 0x0. Register it by calling pxe.registerRecipient(...) or pxe.registerAccount(...)` diff --git a/docs/docs/dev_docs/debugging/main.md b/docs/docs/developers/debugging/main.md similarity index 100% rename from docs/docs/dev_docs/debugging/main.md rename to docs/docs/developers/debugging/main.md diff --git a/docs/docs/dev_docs/debugging/sandbox-errors.md b/docs/docs/developers/debugging/sandbox-errors.md similarity index 89% rename from docs/docs/dev_docs/debugging/sandbox-errors.md rename to docs/docs/developers/debugging/sandbox-errors.md index f95925a4da2..6e1a92f154e 100644 --- a/docs/docs/dev_docs/debugging/sandbox-errors.md +++ b/docs/docs/developers/debugging/sandbox-errors.md @@ -13,7 +13,7 @@ This section contains a list of errors you may encounter when using Aztec Sandbo ### Kernel Circuits -We have several versions of public and private kernels as explained in [our circuits section](../../concepts/advanced/circuits/kernels/main.md). Certain things are only possible in certain versions of the circuits. So always ensure that the right version is being used for proof generation. For example, there is a specific version of the public kernel that only works if the previous kernel iteration was a private kernel. Similarly there is one that only works if the previous kernel was public. +We have several versions of public and private kernels as explained in [our circuits section](../../learn/concepts/circuits/main.md). Certain things are only possible in certain versions of the circuits. So always ensure that the right version is being used for proof generation. For example, there is a specific version of the public kernel that only works if the previous kernel iteration was a private kernel. Similarly there is one that only works if the previous kernel was public. Remember that for each function call (i.e. each item in the call stack), there is a new kernel iteration that gets run. @@ -86,7 +86,7 @@ Calling a private Aztec.nr function in a public kernel is not allowed. #### 3005 - PUBLIC_KERNEL\_\_NON_EMPTY_PRIVATE_CALL_STACK -Public functions are executed after all the private functions are (see [private-public execution](../../concepts/foundation/communication/public_private_calls/main.md)). As such, private call stack must be empty when executing in the public kernel. +Public functions are executed after all the private functions are (see [private-public execution](../../learn/concepts/communication/public_private_calls/main.md)). As such, private call stack must be empty when executing in the public kernel. #### 3011 - PUBLIC_KERNEL\_\_CALCULATED_PRIVATE_CALL_HASH_AND_PROVIDED_PRIVATE_CALL_HASH_MISMATCH @@ -130,7 +130,7 @@ For static calls, no new commitments or nullifiers can be added to the state. ### Rollup circuit errors -These are errors that occur when kernel proofs (transaction proofs) are sent to the rollup circuits to create an L2 block. See [rollup circuits](../../concepts/advanced/circuits/rollup_circuits/main.md) for more information. +These are errors that occur when kernel proofs (transaction proofs) are sent to the rollup circuits to create an L2 block. See [rollup circuits](../../learn/concepts/circuits/rollup_circuits/main.md) for more information. #### 4007 - BASE\_\_INVALID_CHAIN_ID @@ -140,7 +140,7 @@ The L1 chain ID you used in your proof generation (for your private transaction) Same as [section 4007](#4007---base__invalid_chain_id) except the `version` refers to the version of the Aztec L2 instance. -Some scary bugs like `4003 - BASE__INVALID_NULLIFIER_SUBTREE` and `4004 - BASE__INVALID_NULLIFIER_RANGE` which are to do malformed nullifier trees (see [Indexed Merkle Trees](../../concepts/advanced/data_structures/indexed_merkle_tree.md)) etc may seem unrelated at a glance, but at a closer look may be because of some bug in an application's Aztec.nr code. Same is true for certain instances of `7008 - MEMBERSHIP_CHECK_FAILED`. +Some scary bugs like `4003 - BASE__INVALID_NULLIFIER_SUBTREE` and `4004 - BASE__INVALID_NULLIFIER_RANGE` which are to do malformed nullifier trees (see [Indexed Merkle Trees](../../learn/concepts/storage/trees/indexed_merkle_tree.md)) etc may seem unrelated at a glance, but at a closer look may be because of some bug in an application's Aztec.nr code. Same is true for certain instances of `7008 - MEMBERSHIP_CHECK_FAILED`. ### Generic circuit errors @@ -171,7 +171,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit - using invalid historical L1 to L2 message data tree state - inserting a subtree into the greater tree - we make a smaller merkle tree of all the new commitments/nullifiers etc that were created in a transaction or in a rollup and add it to the bigger state tree. Before inserting, we do a merkle membership check to ensure that the index to insert at is indeed an empty subtree (otherwise we would be overwriting state). This can happen when `next_available_leaf_index` in the state tree's snapshot is wrong (it is fetched by the sequencer from the archiver). The error message should reveal which tree is causing this issue - - nullifier tree related errors - The nullifier tree uses an [Indexed Merkle Tree](../../concepts/advanced/data_structures/indexed_merkle_tree.md). It requires additional data from the archiver to know which is the nullifier in the tree that is just below the current nullifier before it can perform batch insertion. If the low nullifier is wrong, or the nullifier is in incorrect range, you may receive this error. + - nullifier tree related errors - The nullifier tree uses an [Indexed Merkle Tree](../../learn/concepts/storage/trees/indexed_merkle_tree.md). It requires additional data from the archiver to know which is the nullifier in the tree that is just below the current nullifier before it can perform batch insertion. If the low nullifier is wrong, or the nullifier is in incorrect range, you may receive this error. --- @@ -191,7 +191,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit - "${treeName} tree next available leaf index mismatch" - validating a tree's root is not enough. It also checks that the `next_available_leaf_index` is as expected. This is the next index we can insert new values into. Note that for the public data tree, this test is skipped since as it is a sparse tree unlike the others. -- "Public call stack size exceeded" - In Aztec, the sequencer executes all enqueued public functions in a transaction (to prevent race conditions - see [private-public execution](../../concepts/foundation/communication/public_private_calls/main.md)). This error says there are too many public functions requested. +- "Public call stack size exceeded" - In Aztec, the sequencer executes all enqueued public functions in a transaction (to prevent race conditions - see [private-public execution](../../learn/concepts/communication/public_private_calls/main.md)). This error says there are too many public functions requested. - "Array size exceeds target length" - happens if you add more items than allowed by the constants set due to our circuit limitations (eg sending too many L2 to L1 messages or creating a function that exceeds the call stack length or returns more values than what Aztec.nr functions allow) diff --git a/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md b/docs/docs/developers/getting_started/aztecjs-getting-started.md similarity index 97% rename from docs/docs/dev_docs/getting_started/aztecjs-getting-started.md rename to docs/docs/developers/getting_started/aztecjs-getting-started.md index 637da709e60..d2f1fd6c2e6 100644 --- a/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md +++ b/docs/docs/developers/getting_started/aztecjs-getting-started.md @@ -152,7 +152,7 @@ The sandbox is preloaded with multiple accounts so you don't have to sit and cre #include_code load_accounts /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript -An explanation on accounts on Aztec can be found [here](../../concepts/foundation/accounts/main.md). +An explanation on accounts on Aztec can be found [here](../../learn/concepts/accounts/main.md). If you want more accounts, you can find instructions in the [Account creation section](../wallets/creating_schnorr_accounts.md). @@ -268,7 +268,7 @@ Now lets transfer some funds from Alice to Bob by calling the `transfer` functio 1. The sender. 2. The recipient. 3. The quantity of tokens to be transferred. -4. The nonce for the [authentication witness](../../concepts//foundation/accounts/main.md#authorizing-actions), or 0 if msg.sender equal sender. +4. The nonce for the [authentication witness](../../learn//concepts/accounts/main.md#authorizing-actions), or 0 if msg.sender equal sender. Here is the Typescript code to call the `transfer` function, add this to your `index.ts` at the bottom of the `main` function: @@ -371,7 +371,7 @@ Our complete output should now be something like: token Bob's balance 10543 +43ms ``` -That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [here](../../concepts/foundation/transactions.md). +That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [here](../../learn/concepts/transactions.md). ## Next Steps diff --git a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md b/docs/docs/developers/getting_started/aztecnr-getting-started.md similarity index 97% rename from docs/docs/dev_docs/getting_started/aztecnr-getting-started.md rename to docs/docs/developers/getting_started/aztecnr-getting-started.md index 27357e5640e..599c50d84e0 100644 --- a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md +++ b/docs/docs/developers/getting_started/aztecnr-getting-started.md @@ -223,7 +223,7 @@ Now you can explore. **Interested in learning more about how Aztec works under the hood?** -Understand the high level architecture [here](../../concepts/foundation/main.md). +Understand the high level architecture [here](../../learn/about_aztec/technical_overview.md). **Want to write more advanced smart contracts?** @@ -231,4 +231,4 @@ Follow the token contract tutorial [here](../tutorials/writing_token_contract.md **Ready to dive into Aztec and Ethereum cross-chain communication?** -Read the [Portals page](../../concepts/foundation/communication/cross_chain_calls.md) and learn how to practically implement portals in the [token bridge tutorial](../tutorials/token_portal/main.md). +Read the [Portals page](../../learn/concepts/communication/cross_chain_calls.md) and learn how to practically implement portals in the [token bridge tutorial](../tutorials/token_portal/main.md). diff --git a/docs/docs/dev_docs/getting_started/main.md b/docs/docs/developers/getting_started/main.md similarity index 91% rename from docs/docs/dev_docs/getting_started/main.md rename to docs/docs/developers/getting_started/main.md index f2f343b0c2e..0ee5ab59990 100644 --- a/docs/docs/dev_docs/getting_started/main.md +++ b/docs/docs/developers/getting_started/main.md @@ -12,7 +12,7 @@ If this is your first time using Aztec, and you want to get started by learning ## Learn -If you want to read more about the high level concepts of Aztec before writing some code, head to the [Foundational Concepts section](../../concepts/foundation/main.md). +If you want to read more about the high level concepts of Aztec before writing some code, head to the [Foundational Concepts section](../../learn/about_aztec/technical_overview.md). ## In this section diff --git a/docs/docs/dev_docs/getting_started/quickstart.md b/docs/docs/developers/getting_started/quickstart.md similarity index 95% rename from docs/docs/dev_docs/getting_started/quickstart.md rename to docs/docs/developers/getting_started/quickstart.md index 62b56e10afe..822cf85f5a7 100644 --- a/docs/docs/dev_docs/getting_started/quickstart.md +++ b/docs/docs/developers/getting_started/quickstart.md @@ -77,7 +77,7 @@ Note that the deployed contract address is exported, so we can use it as `$CONTR Alice is set up as the contract admin and token minter in the `_initialize` function. Let's get Alice some private tokens. -We need to export the `SECRET` and `SECRET_HASH` values in order to privately mint tokens. Private tokens are claimable by anyone with the pre-image to a provided hash, see more about how the token contract works in the [token contract tutorial](../tutorials/writing_token_contract.md). After the tokens have been minted, the notes will have to added to the [Private Execution Environment](../../apis/pxe/interfaces/PXE) (PXE) to be consumed by private functions. Once added, Alice can claim them with the `redeem_shield` function. After this, Alice should have 1000 tokens in their private balance. +We need to export the `SECRET` and `SECRET_HASH` values in order to privately mint tokens. Private tokens are claimable by anyone with the pre-image to a provided hash, see more about how the token contract works in the [token contract tutorial](../tutorials/writing_token_contract.md). After the tokens have been minted, the notes will have to added to the [Private Execution Environment](../../apis/pxe/interfaces/PXE.md) (PXE) to be consumed by private functions. Once added, Alice can claim them with the `redeem_shield` function. After this, Alice should have 1000 tokens in their private balance. #include_code mint-private yarn-project/end-to-end/src/guides/up_quick_start.sh bash diff --git a/docs/docs/dev_docs/limitations/main.md b/docs/docs/developers/limitations/main.md similarity index 93% rename from docs/docs/dev_docs/limitations/main.md rename to docs/docs/developers/limitations/main.md index bc28d3fd480..bc719c9307a 100644 --- a/docs/docs/dev_docs/limitations/main.md +++ b/docs/docs/developers/limitations/main.md @@ -54,7 +54,7 @@ That's right, the Sandbox doesn't actually generate or verify any zk-SNARKs yet! The main goal of the Sandbox is to enable developers to experiment with building apps, and hopefully to provide feedback. We want the developer experience to be as fast as possible, much like how Ethereum developers use Ganache or Anvil to get super-fast block times, instead of the slow-but-realistic 12-second block times that they'll encounter in production. A fast Sandbox enables fast testing, which enables developers to iterate quickly. -That's not to say a super-fast proving system isn't being worked on [as we speak](../../about_aztec/roadmap/cryptography_roadmap.md). +That's not to say a super-fast proving system isn't being worked on [as we speak](../../misc/roadmap/cryptography_roadmap.md). #### What are the consequences? @@ -209,13 +209,13 @@ Not only are there limits on a _per function_ basis, there are also limits on a **In particular, these _per-transaction_ limits will limit transaction call stack depths** in the Sandbox. That means if a function call results in a cascade of nested function calls, and each of those function calls outputs lots of state reads and writes, or logs (etc.), then all of that accumulated output data might exceed the per-transaction limits that we currently have. This would cause such transactions to fail. -There are plans to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](../../concepts/advanced/circuits/kernels/main.md), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. +There are plans to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](../../learn/concepts/circuits/main.md), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. > **In the mean time**, if you encounter a per-transaction limit when testing, and you're feeling adventurous, you could 'hack' the Sandbox to increase the limits. See here (TODO: link) for a guide. **However**, the limits cannot be increased indefinitely. So although we do anticipate that we'll be able to increase them a little bit, don't go mad and provide yourself with 1 million state transitions per transaction. That would be as unrealistic as artificially increasing Ethereum gas limits to 1 trillion. ### Circuits Processing Order Differs from Execution Order -Each function call is represented by a circuit with a dedicated zero-knowledge proof of its execution. The [private kernel circuit](../../concepts/advanced/circuits/kernels/private_kernel.md) is in charge of stitching all these proofs together to produce a zero-knowledge proof that the whole execution of all function calls within a transaction is correct. In doing so, the processing order differs from the execution order. Firstly, the private kernel has to handle one function call in its entirety at a time because a zk proof cannot be verified partially. This property alone makes it impossible for the ordering of kernel circuit validation to match the order in which the functions of the transaction were executed. Secondly, the private kernel processes function calls in a stack-based order, i.e., after having processed a function call, it processes all direct child function calls in an order which is the reverse of the execution order. +Each function call is represented by a circuit with a dedicated zero-knowledge proof of its execution. The [private kernel circuit](../../learn/concepts/circuits/kernels/private_kernel.md) is in charge of stitching all these proofs together to produce a zero-knowledge proof that the whole execution of all function calls within a transaction is correct. In doing so, the processing order differs from the execution order. Firstly, the private kernel has to handle one function call in its entirety at a time because a zk proof cannot be verified partially. This property alone makes it impossible for the ordering of kernel circuit validation to match the order in which the functions of the transaction were executed. Secondly, the private kernel processes function calls in a stack-based order, i.e., after having processed a function call, it processes all direct child function calls in an order which is the reverse of the execution order. Note that there is no plan to change this in the future. @@ -243,7 +243,7 @@ Transaction output elements such as notes in encrypted logs, note hashes (commit ### Chopped Transient Notes are still Emitted in Logs -A note which is created and nullified during the very same transaction is called transient. Such a note is chopped by the [private kernel circuit](../../concepts/advanced/circuits/kernels/private_kernel.md) and is never stored in any persistent data tree. +A note which is created and nullified during the very same transaction is called transient. Such a note is chopped by the [private kernel circuit](../../learn/concepts/circuits/kernels/private_kernel.md) and is never stored in any persistent data tree. For the time being, such chopped notes are still emitted through encrypted logs (which is the communication channel to transmit notes). When a log containing a chopped note is processed, a warning will be logged about a decrypted note which does not exist in data tree. We [improved](https://github.com/AztecProtocol/aztec-packages/issues/1603) error logging to help identify such an occurrence. However, this might be a source of confusion. This issue is tracked in ticket [#1641](https://github.com/AztecProtocol/aztec-packages/issues/1641). diff --git a/docs/docs/dev_docs/privacy/main.md b/docs/docs/developers/privacy/main.md similarity index 100% rename from docs/docs/dev_docs/privacy/main.md rename to docs/docs/developers/privacy/main.md diff --git a/docs/docs/dev_docs/testing/cheat_codes.md b/docs/docs/developers/testing/cheat_codes.md similarity index 100% rename from docs/docs/dev_docs/testing/cheat_codes.md rename to docs/docs/developers/testing/cheat_codes.md diff --git a/docs/docs/dev_docs/testing/main.md b/docs/docs/developers/testing/main.md similarity index 100% rename from docs/docs/dev_docs/testing/main.md rename to docs/docs/developers/testing/main.md diff --git a/docs/docs/dev_docs/tutorials/main.md b/docs/docs/developers/tutorials/main.md similarity index 100% rename from docs/docs/dev_docs/tutorials/main.md rename to docs/docs/developers/tutorials/main.md diff --git a/docs/docs/dev_docs/tutorials/testing.md b/docs/docs/developers/tutorials/testing.md similarity index 95% rename from docs/docs/dev_docs/tutorials/testing.md rename to docs/docs/developers/tutorials/testing.md index ca2d015bd90..3b19d4c3bb7 100644 --- a/docs/docs/dev_docs/tutorials/testing.md +++ b/docs/docs/developers/tutorials/testing.md @@ -154,7 +154,7 @@ To query storage directly, you'll need to know the slot you want to access. This #### Querying private state -Private state in the Aztec Network is represented via sets of [private notes](../../concepts/foundation/state_model/main.md#private-state). In our token contract example, the balance of a user is represented as a set of unspent value notes, each with their own corresponding numeric value. +Private state in the Aztec Network is represented via sets of [private notes](../../learn/concepts/hybrid_state/main.md#private-state). In our token contract example, the balance of a user is represented as a set of unspent value notes, each with their own corresponding numeric value. #include_code value-note-def yarn-project/aztec-nr/value-note/src/value_note.nr rust @@ -164,7 +164,7 @@ We can query the Private eXecution Environment (PXE) for all notes encrypted for #### Querying public state -[Public state](../../concepts/foundation/state_model/main.md#public-state) behaves as a key-value store, much like in the EVM. This scenario is much more straightforward, in that we can directly query the target slot and get the result back as a buffer. Note that we use the [`TokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_contract/src/main.nr) in this example, which defines a mapping of public balances on slot 6. +[Public state](../../learn/concepts/hybrid_state/main.md#public-state) behaves as a key-value store, much like in the EVM. This scenario is much more straightforward, in that we can directly query the target slot and get the result back as a buffer. Note that we use the [`TokenContract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_contract/src/main.nr) in this example, which defines a mapping of public balances on slot 6. #include_code public-storage /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript diff --git a/docs/docs/dev_docs/tutorials/token_portal/cancelling_deposits.md b/docs/docs/developers/tutorials/token_portal/cancelling_deposits.md similarity index 100% rename from docs/docs/dev_docs/tutorials/token_portal/cancelling_deposits.md rename to docs/docs/developers/tutorials/token_portal/cancelling_deposits.md diff --git a/docs/docs/dev_docs/tutorials/token_portal/depositing_to_aztec.md b/docs/docs/developers/tutorials/token_portal/depositing_to_aztec.md similarity index 100% rename from docs/docs/dev_docs/tutorials/token_portal/depositing_to_aztec.md rename to docs/docs/developers/tutorials/token_portal/depositing_to_aztec.md diff --git a/docs/docs/dev_docs/tutorials/token_portal/main.md b/docs/docs/developers/tutorials/token_portal/main.md similarity index 97% rename from docs/docs/dev_docs/tutorials/token_portal/main.md rename to docs/docs/developers/tutorials/token_portal/main.md index 5e9caf8ce54..5739d5b81aa 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/main.md +++ b/docs/docs/developers/tutorials/token_portal/main.md @@ -35,7 +35,7 @@ Aztec has the following core smart contracts on L1 that we need to know about: - `Outbox.sol` - a mailbox to the rollup for L2 to L1 messages (e.g. withdrawing tokens). Aztec contracts emit these messages and the sequencer adds these to the outbox. Portals then consume these messages. - `Registry.sol` - just like L1, we assume there will be various versions of Aztec (due to upgrades, forks etc). In such a case messages must not be replayable in other Aztec “domains”. A portal must decide which version/ID of Aztec the message is for. The registry stores the rollup, inbox and outbox address for each version of Aztec deployments, so the portal can find out the address of the mailbox it wants to talk to -For more information, read [cross-chain calls](../../../concepts/foundation/communication/cross_chain_calls). +For more information, read [cross-chain calls](../../../learn/concepts/communication/cross_chain_calls). ## Building a Token Bridge with Portals diff --git a/docs/docs/dev_docs/tutorials/token_portal/minting_on_aztec.md b/docs/docs/developers/tutorials/token_portal/minting_on_aztec.md similarity index 100% rename from docs/docs/dev_docs/tutorials/token_portal/minting_on_aztec.md rename to docs/docs/developers/tutorials/token_portal/minting_on_aztec.md diff --git a/docs/docs/dev_docs/tutorials/token_portal/setup.md b/docs/docs/developers/tutorials/token_portal/setup.md similarity index 97% rename from docs/docs/dev_docs/tutorials/token_portal/setup.md rename to docs/docs/developers/tutorials/token_portal/setup.md index 3f738e02fc0..fc5d141381a 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/setup.md +++ b/docs/docs/developers/tutorials/token_portal/setup.md @@ -19,7 +19,7 @@ However if you’d rather skip this part, our dev-rels repo contains the starter - [node v18+](https://github.com/tj/n) - [docker](https://docs.docker.com/) -- [Aztec sandbox](https://docs.aztec.network/dev_docs/getting_started/sandbox) - you should have this running before starting the tutorial +- [Aztec sandbox](https://docs.aztec.network/developers/getting_started/sandbox) - you should have this running before starting the tutorial - [Aztec CLI](../../getting_started/quickstart.md) ```bash diff --git a/docs/docs/dev_docs/tutorials/token_portal/typescript_glue_code.md b/docs/docs/developers/tutorials/token_portal/typescript_glue_code.md similarity index 100% rename from docs/docs/dev_docs/tutorials/token_portal/typescript_glue_code.md rename to docs/docs/developers/tutorials/token_portal/typescript_glue_code.md diff --git a/docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md b/docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md similarity index 93% rename from docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md rename to docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md index 8716421c10b..ff0be84bb85 100644 --- a/docs/docs/dev_docs/tutorials/token_portal/withdrawing_to_l1.md +++ b/docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md @@ -17,7 +17,7 @@ For this to work we import the `get_withdraw_content_hash` helper function from The `exit_to_l1_public` function enables anyone to withdraw their L2 tokens back to L1 publicly. This is done by burning tokens on L2 and then creating an L2->L1 message. 1. Like with our deposit function, we need to create the L2 to L1 message. The content is the _amount_ to burn, the recipient address, and who can execute the withdraw on the L1 portal on behalf of the user. It can be `0x0` for anyone, or a specified address. -2. `context.message_portal()` passes this content to the [kernel circuit](../../../concepts/advanced/circuits/kernels/public_kernel.md) which creates the proof for the transaction. The kernel circuit then adds the sender (the L2 address of the bridge + version of aztec) and the recipient (the portal to the L2 address + the chain ID of L1) under the hood, to create the message which gets added as rollup calldata by the sequencer and is stored in the outbox for consumption. +2. `context.message_portal()` passes this content to the [kernel circuit](../../../learn/concepts/circuits/kernels/public_kernel.md) which creates the proof for the transaction. The kernel circuit then adds the sender (the L2 address of the bridge + version of aztec) and the recipient (the portal to the L2 address + the chain ID of L1) under the hood, to create the message which gets added as rollup calldata by the sequencer and is stored in the outbox for consumption. 3. Finally, you also burn the tokens on L2! Note that it burning is done at the end to follow the check effects interaction pattern. Note that the caller has to first approve the bridge contract to burn tokens on its behalf. Refer to [burn_public function on the token contract](../writing_token_contract.md#burn_public). The nonce parameter refers to the approval message that the user creates - also refer to [authorizing token spends here](../writing_token_contract.md#authorizing-token-spends). - We burn the tokens from the `msg_sender()`. Otherwise, a malicious user could burn someone else’s tokens and mint tokens on L1 to themselves. One could add another approval flow on the bridge but that might make it complex for other applications to call the bridge. diff --git a/docs/docs/dev_docs/tutorials/uniswap/execute_private_swap_on_l1.md b/docs/docs/developers/tutorials/uniswap/execute_private_swap_on_l1.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/execute_private_swap_on_l1.md rename to docs/docs/developers/tutorials/uniswap/execute_private_swap_on_l1.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/execute_public_swap_on_l1.md b/docs/docs/developers/tutorials/uniswap/execute_public_swap_on_l1.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/execute_public_swap_on_l1.md rename to docs/docs/developers/tutorials/uniswap/execute_public_swap_on_l1.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/l1_portal.md b/docs/docs/developers/tutorials/uniswap/l1_portal.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/l1_portal.md rename to docs/docs/developers/tutorials/uniswap/l1_portal.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/l2_contract_setup.md b/docs/docs/developers/tutorials/uniswap/l2_contract_setup.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/l2_contract_setup.md rename to docs/docs/developers/tutorials/uniswap/l2_contract_setup.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/main.md b/docs/docs/developers/tutorials/uniswap/main.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/main.md rename to docs/docs/developers/tutorials/uniswap/main.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/redeeming_swapped_assets_on_l2.md b/docs/docs/developers/tutorials/uniswap/redeeming_swapped_assets_on_l2.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/redeeming_swapped_assets_on_l2.md rename to docs/docs/developers/tutorials/uniswap/redeeming_swapped_assets_on_l2.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/setup.md b/docs/docs/developers/tutorials/uniswap/setup.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/setup.md rename to docs/docs/developers/tutorials/uniswap/setup.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/swap_privately.md b/docs/docs/developers/tutorials/uniswap/swap_privately.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/swap_privately.md rename to docs/docs/developers/tutorials/uniswap/swap_privately.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/swap_publicly.md b/docs/docs/developers/tutorials/uniswap/swap_publicly.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/swap_publicly.md rename to docs/docs/developers/tutorials/uniswap/swap_publicly.md diff --git a/docs/docs/dev_docs/tutorials/uniswap/typescript_glue_code.md b/docs/docs/developers/tutorials/uniswap/typescript_glue_code.md similarity index 100% rename from docs/docs/dev_docs/tutorials/uniswap/typescript_glue_code.md rename to docs/docs/developers/tutorials/uniswap/typescript_glue_code.md diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/contract_deployment.md b/docs/docs/developers/tutorials/writing_dapp/contract_deployment.md similarity index 100% rename from docs/docs/dev_docs/tutorials/writing_dapp/contract_deployment.md rename to docs/docs/developers/tutorials/writing_dapp/contract_deployment.md diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md b/docs/docs/developers/tutorials/writing_dapp/contract_interaction.md similarity index 93% rename from docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md rename to docs/docs/developers/tutorials/writing_dapp/contract_interaction.md index 73c0eef546c..058fa3483f5 100644 --- a/docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md +++ b/docs/docs/developers/tutorials/writing_dapp/contract_interaction.md @@ -93,12 +93,12 @@ At the time of this writing, there are no events emitted when new private notes ## Working with public state -While [private and public state](../../../concepts/foundation/state_model/main.md) are fundamentally different, the API for working with private and public functions and state from `aztec.js` is equivalent. To query the balance in public tokens for our user accounts, we can just call the `balance_of_public` view function in the contract: +While [private and public state](../../../learn/concepts/hybrid_state/main.md) are fundamentally different, the API for working with private and public functions and state from `aztec.js` is equivalent. To query the balance in public tokens for our user accounts, we can just call the `balance_of_public` view function in the contract: #include_code showPublicBalances yarn-project/end-to-end/src/sample-dapp/index.mjs javascript :::info -Since this we are working with pubic balances, we can now query the balance for any address, not just those registered in our local PXE. We can also send funds to addresses for which we don't know their [public encryption key](../../../concepts/foundation/accounts/keys.md#encryption-keys). +Since this we are working with pubic balances, we can now query the balance for any address, not just those registered in our local PXE. We can also send funds to addresses for which we don't know their [public encryption key](../../../learn/concepts/accounts/keys.md#encryption-keys). ::: Here, since the token contract does not mint any initial funds upon deployment, the balances for all of our user's accounts will be zero. diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/main.md b/docs/docs/developers/tutorials/writing_dapp/main.md similarity index 100% rename from docs/docs/dev_docs/tutorials/writing_dapp/main.md rename to docs/docs/developers/tutorials/writing_dapp/main.md diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/project_setup.md b/docs/docs/developers/tutorials/writing_dapp/project_setup.md similarity index 100% rename from docs/docs/dev_docs/tutorials/writing_dapp/project_setup.md rename to docs/docs/developers/tutorials/writing_dapp/project_setup.md diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/pxe_service.md b/docs/docs/developers/tutorials/writing_dapp/pxe_service.md similarity index 100% rename from docs/docs/dev_docs/tutorials/writing_dapp/pxe_service.md rename to docs/docs/developers/tutorials/writing_dapp/pxe_service.md diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/testing.md b/docs/docs/developers/tutorials/writing_dapp/testing.md similarity index 98% rename from docs/docs/dev_docs/tutorials/writing_dapp/testing.md rename to docs/docs/developers/tutorials/writing_dapp/testing.md index 7178e895b6e..6e835783d3d 100644 --- a/docs/docs/dev_docs/tutorials/writing_dapp/testing.md +++ b/docs/docs/developers/tutorials/writing_dapp/testing.md @@ -67,4 +67,4 @@ yarn node --experimental-vm-modules $(yarn bin jest) --testRegex '.*\.test\.mjs$ ## Next steps -Now that you have finished the tutorial, you can learn more about [writing contracts with Noir](../../contracts/main.md) or read about the [fundamental concepts behind Aztec Network](../../../concepts/foundation/main.md). +Now that you have finished the tutorial, you can learn more about [writing contracts with Noir](../../contracts/main.md) or read about the [fundamental concepts behind Aztec Network](../../../learn/about_aztec/technical_overview.md). diff --git a/docs/docs/dev_docs/tutorials/writing_private_voting_contract.md b/docs/docs/developers/tutorials/writing_private_voting_contract.md similarity index 97% rename from docs/docs/dev_docs/tutorials/writing_private_voting_contract.md rename to docs/docs/developers/tutorials/writing_private_voting_contract.md index c8ab1e70f64..82f46f860de 100644 --- a/docs/docs/dev_docs/tutorials/writing_private_voting_contract.md +++ b/docs/docs/developers/tutorials/writing_private_voting_contract.md @@ -107,7 +107,7 @@ This `init` function will be called every time we access `storage` in our functi The next step is to initialize the contract with a constructor. The constructor will take an address as a parameter and set the admin. -All constructors must be private, and because the admin is in public storage, we cannot directly update it from the constructor. You can find more information about this [here](../../concepts/foundation/communication/public_private_calls/main.md). +All constructors must be private, and because the admin is in public storage, we cannot directly update it from the constructor. You can find more information about this [here](../../learn/concepts/communication/public_private_calls/main.md). Therefore our constructor must call a public function by using `context.call_public_function()`. Paste this under the `impl` storage block: @@ -141,7 +141,7 @@ Create a private function called `cast_vote`: #include_code cast_vote yarn-project/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -In this function, we do not create a nullifier with the address directly. This would leak privacy as it would be easy to reverse-engineer. We must add some randomness or some form of secret, like [nullifier secrets](../../concepts/foundation/accounts/keys.md#nullifier-secrets). +In this function, we do not create a nullifier with the address directly. This would leak privacy as it would be easy to reverse-engineer. We must add some randomness or some form of secret, like [nullifier secrets](../../learn/concepts/accounts/keys.md#nullifier-secrets). To do this, we make an [oracle call](../contracts/syntax/functions.md#oracle-functions) to fetch the caller's secret key, hash it to create a nullifier, and push the nullifier to Aztec. The `secret.high` and `secret.low` values here refer to how we divide a large [Grumpkin scalar](https://github.com/AztecProtocol/aztec-packages/blob/7fb35874eae3f2cad5cb922282a619206573592c/noir/noir_stdlib/src/grumpkin_scalar.nr) value into its higher and lower parts. This allows for faster cryptographic computations so our hash can still be secure but is calculated faster. @@ -163,7 +163,7 @@ We will create a function that anyone can call that will return the number of vo #include_code get_vote yarn-project/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -We set it as `unconstrained` and do not annotate it because it is only reading from state. You can read more about unconstrained functions [here](../../concepts/advanced/acir_simulator.md#unconstrained-functions). +We set it as `unconstrained` and do not annotate it because it is only reading from state. You can read more about unconstrained functions [here](../../learn/concepts/pxe/acir_simulator.md#unconstrained-functions). ## Allowing an admin to end a voting period diff --git a/docs/docs/dev_docs/tutorials/writing_token_contract.md b/docs/docs/developers/tutorials/writing_token_contract.md similarity index 97% rename from docs/docs/dev_docs/tutorials/writing_token_contract.md rename to docs/docs/developers/tutorials/writing_token_contract.md index f4fda400456..fe3b71421e4 100644 --- a/docs/docs/dev_docs/tutorials/writing_token_contract.md +++ b/docs/docs/developers/tutorials/writing_token_contract.md @@ -155,7 +155,7 @@ These are functions that have transparent logic, will execute in a publicly veri ### Private functions -These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data [commitments](https://en.wikipedia.org/wiki/Commitment_scheme) and [nullifiers](../../concepts/advanced/data_structures/trees#nullifier-tree), so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. +These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data [commitments](https://en.wikipedia.org/wiki/Commitment_scheme) and [nullifiers](../../learn/concepts/storage/trees/main.md#nullifier-tree), so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. - `redeem_shield` enables accounts to claim tokens that have been made private via `mint_private` or `shield` by providing the secret - `unshield` enables an account to send tokens from their private balance to any other account's public balance @@ -208,11 +208,11 @@ Just below the contract definition, add the following imports: #include_code imports /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust -We are importing the Option type, items from the `value_note` library to help manage private value storage, note utilities, context (for managing private and public execution contexts), `state_vars` for helping manage state, `types` for data manipulation and `oracle` for help passing data from the private to public execution context. We also import the `auth` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/auth.nr) to handle token authorizations from [Account Contracts](../../concepts/foundation/accounts/main). Check out the Account Contract with AuthWitness [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr). +We are importing the Option type, items from the `value_note` library to help manage private value storage, note utilities, context (for managing private and public execution contexts), `state_vars` for helping manage state, `types` for data manipulation and `oracle` for help passing data from the private to public execution context. We also import the `auth` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/auth.nr) to handle token authorizations from [Account Contracts](../../learn/concepts/accounts/main). Check out the Account Contract with AuthWitness [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr). [SafeU120](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/safe-math/src/safe_u120.nr) is a library to do safe math operations on unsigned integers that protects against overflows and underflows. -For more detail on execution contexts, see [Contract Communication](../../concepts/foundation/communication/main). +For more detail on execution contexts, see [Contract Communication](../../learn/concepts/communication/main). ### Types files diff --git a/docs/docs/dev_docs/updating.md b/docs/docs/developers/updating.md similarity index 96% rename from docs/docs/dev_docs/updating.md rename to docs/docs/developers/updating.md index e9f0b54abcc..6e9a3b47d57 100644 --- a/docs/docs/dev_docs/updating.md +++ b/docs/docs/developers/updating.md @@ -19,7 +19,7 @@ cd your/aztec/project aztec-cli update . --contract src/contract1 --contract src/contract2 ``` -The sandbox must be running for the update command to work. Make sure it is [installed and running](../dev_docs/cli/sandbox-reference.md). +The sandbox must be running for the update command to work. Make sure it is [installed and running](../developers/cli/sandbox-reference.md). 3. Refer [Migration Notes](../misc/migration_notes.md) on any breaking changes that might affect your dapp diff --git a/docs/docs/dev_docs/wallets/architecture.md b/docs/docs/developers/wallets/architecture.md similarity index 80% rename from docs/docs/dev_docs/wallets/architecture.md rename to docs/docs/developers/wallets/architecture.md index 7785d43e41b..3d010fd3267 100644 --- a/docs/docs/dev_docs/wallets/architecture.md +++ b/docs/docs/developers/wallets/architecture.md @@ -8,7 +8,7 @@ Architecture-wise, a wallet is an instance of an **Private Execution Environment The PXE also communicates with an **Aztec Node** for retrieving public information or broadcasting transactions. Note that the PXE requires a local database for keeping private state, and is also expected to be continuously syncing new blocks for trial-decryption of user notes. -Additionally, a wallet must be able to handle one or more [account contract implementations](../../concepts/foundation/accounts/main.md#account-contracts-and-wallets). When a user creates a new account, the account is represented on-chain by an account contract. The wallet is responsible for deploying and interacting with this contract. A wallet may support multiple flavours of accounts, such as an account that uses ECDSA signatures, or one that relies on WebAuthn, or one that requires multi-factor authentication. For a user, the choice of what account implementation to use is then determined by the wallet they interact with. +Additionally, a wallet must be able to handle one or more [account contract implementations](../../learn/concepts/accounts/main.md#account-contracts-and-wallets). When a user creates a new account, the account is represented on-chain by an account contract. The wallet is responsible for deploying and interacting with this contract. A wallet may support multiple flavours of accounts, such as an account that uses ECDSA signatures, or one that relies on WebAuthn, or one that requires multi-factor authentication. For a user, the choice of what account implementation to use is then determined by the wallet they interact with. In code, this translates to a wallet implementing an **AccountInterface** interface that defines [how to create an _execution request_ out of an array of _function calls_](./main.md#transaction-lifecycle) for the specific implementation of an account contract and [how to generate an _auth witness_](./main.md#authorizing-actions) for authorizing actions on behalf of the user. Think of this interface as the Javascript counterpart of an account contract, or the piece of code that knows how to format a transaction and authenticate an action based on the rules defined by the user's account contract implementation. diff --git a/docs/docs/dev_docs/wallets/creating_schnorr_accounts.md b/docs/docs/developers/wallets/creating_schnorr_accounts.md similarity index 96% rename from docs/docs/dev_docs/wallets/creating_schnorr_accounts.md rename to docs/docs/developers/wallets/creating_schnorr_accounts.md index d4dfa04e2c3..636bf8df4af 100644 --- a/docs/docs/dev_docs/wallets/creating_schnorr_accounts.md +++ b/docs/docs/developers/wallets/creating_schnorr_accounts.md @@ -6,7 +6,7 @@ title: Creating Schnorr Accounts This section shows how to create schnorr account wallets on the Aztec Sandbox. -An in-depth explaining about accounts on aztec can be found [here](../../concepts/foundation/accounts/main.md). But creating an account on the Sandbox does 2 things: +An in-depth explaining about accounts on aztec can be found [here](../../learn/concepts/accounts/main.md). But creating an account on the Sandbox does 2 things: 1. Deploys an account contract -- representing you -- allowing you to perform actions on the network (deploy contracts, call functions etc). 2. Adds your encryption keys to the Private eXecution Environment (PXE) allowing it to decrypt and manage your private state. diff --git a/docs/docs/dev_docs/wallets/main.md b/docs/docs/developers/wallets/main.md similarity index 75% rename from docs/docs/dev_docs/wallets/main.md rename to docs/docs/developers/wallets/main.md index 898acb41c55..6e458d8241d 100644 --- a/docs/docs/dev_docs/wallets/main.md +++ b/docs/docs/developers/wallets/main.md @@ -10,17 +10,17 @@ In this page we will cover the main responsibilities of a wallet in the Aztec ne ## Account setup -The first step for any wallet is to let the user set up their [accounts](../../concepts/foundation/accounts/main.md). An account in Aztec is represented on-chain by its corresponding account contract that the user must deploy to begin interacting with the network. This account contract dictates how transactions are authenticated and executed. +The first step for any wallet is to let the user set up their [accounts](../../learn/concepts/accounts/main.md). An account in Aztec is represented on-chain by its corresponding account contract that the user must deploy to begin interacting with the network. This account contract dictates how transactions are authenticated and executed. A wallet must support at least one specific [account contract implementation](./writing_an_account_contract.md), which means being able to deploy such a contract, as well as interacting with it when sending transactions. Code-wise, this requires [implementing the `AccountContract` interface](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/account_contract/index.ts). -Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin. +Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](../../learn/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin. ## Transaction lifecycle Every transaction in Aztec is broadcast to the network as a zero-knowledge proof of correct execution, in order to preserve privacy. This means that transaction proofs are generated on the wallet and not on a remote node. This is one of the biggest differences with regard to EVM chain wallets. -A wallet is responsible for **creating** an [_execution request_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/tx_execution_request.ts) out of one or more [_function calls_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/function_call.ts) requested by a dapp. For example, a dapp may request a wallet to "invoke the `transfer` function on the contract at `0x1234` with the following arguments", in response to a user action. The wallet [turns that into an execution request](../../concepts/foundation/accounts/main.md#execution-requests) with the signed instructions to execute that function call from the user's account contract. In an [ECDSA-based account](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr), for instance, this is an execution request that encodes the function call in the _entrypoint payload_, and includes its ECDSA signature with the account's signing private key. +A wallet is responsible for **creating** an [_execution request_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/tx_execution_request.ts) out of one or more [_function calls_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/function_call.ts) requested by a dapp. For example, a dapp may request a wallet to "invoke the `transfer` function on the contract at `0x1234` with the following arguments", in response to a user action. The wallet [turns that into an execution request](../../learn/concepts/accounts/main.md#execution-requests) with the signed instructions to execute that function call from the user's account contract. In an [ECDSA-based account](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr), for instance, this is an execution request that encodes the function call in the _entrypoint payload_, and includes its ECDSA signature with the account's signing private key. Once the _execution request_ is created, the wallet is responsible for **simulating** and **proving** the execution of its private functions. The simulation yields an execution trace, which can be used to provide the user with a list of side effects of the private execution of the transaction. During this simulation, the wallet is responsible of providing data to the virtual machine, such as private notes, encryption keys, or nullifier secrets. This execution trace is fed into the prover, which returns a zero-knowledge proof that guarantees correct execution and hides all private information. The output of this process is a [_transaction_](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/types/src/tx/tx.ts) object. @@ -36,20 +36,20 @@ There are no proofs generated as of the Sandbox release. This will be included i ## Authorizing actions -Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](../../concepts/foundation/accounts/main.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else. +Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](../../learn/concepts/accounts/main.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else. Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWitness` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation. ## Key management -As in EVM-based chains, wallets are expected to manage user keys, or provide an interface to hardware wallets or alternative key stores. Keep in mind that in Aztec each account requires [two sets of keys](../../concepts/foundation/accounts/keys.md): privacy keys and authentication keys. Privacy keys are mandated by the protocol and used for encryption and nullification, whereas authentication keys are dependent on the account contract implementation rolled out by the wallet. Should the account contract support it, wallets must provide the user with the means to rotate or recover their authentication keys. +As in EVM-based chains, wallets are expected to manage user keys, or provide an interface to hardware wallets or alternative key stores. Keep in mind that in Aztec each account requires [two sets of keys](../../learn/concepts/accounts/keys.md): privacy keys and authentication keys. Privacy keys are mandated by the protocol and used for encryption and nullification, whereas authentication keys are dependent on the account contract implementation rolled out by the wallet. Should the account contract support it, wallets must provide the user with the means to rotate or recover their authentication keys. :::info Due to limitations in the current architecture, privacy keys need to be available in the wallet software itself and cannot be punted to an external keystore. This restriction may be lifted in a future release. ::: ## Recipient encryption keys -Wallets are also expected to manage the public encryption keys of any recipients of local transactions. When creating an encrypted note for a recipient given their address, the wallet needs to provide their [complete address](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys). Recipients broadcast their complete addresses when deploying their account contracts, and wallets collect this information and save it in a local registry for easy access when needed. +Wallets are also expected to manage the public encryption keys of any recipients of local transactions. When creating an encrypted note for a recipient given their address, the wallet needs to provide their [complete address](../../learn/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys). Recipients broadcast their complete addresses when deploying their account contracts, and wallets collect this information and save it in a local registry for easy access when needed. Note that, in order to interact with a recipient who has not yet deployed their account contract (and thus not broadcasted their complete address), it must also be possible to manually add an entry to a wallet's local registry of complete addresses. diff --git a/docs/docs/dev_docs/wallets/writing_an_account_contract.md b/docs/docs/developers/wallets/writing_an_account_contract.md similarity index 88% rename from docs/docs/dev_docs/wallets/writing_an_account_contract.md rename to docs/docs/developers/wallets/writing_an_account_contract.md index 058a02fb349..fdc46499755 100644 --- a/docs/docs/dev_docs/wallets/writing_an_account_contract.md +++ b/docs/docs/developers/wallets/writing_an_account_contract.md @@ -11,15 +11,15 @@ You will learn: - Typescript glue code to format and authenticate transactions - Deploying and testing the account contract -Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of [account abstraction](../../concepts/foundation/accounts/main.md#what-is-account-abstraction) in the Aztec network. +Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of [account abstraction](../../learn/concepts/accounts/main.md#what-is-account-abstraction) in the Aztec network. -It is highly recommended that you understand how an [account](../../concepts/foundation/accounts/main.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../concepts/foundation/accounts/keys.md). You will also need to know how to write a [contract in Noir](../contracts/main.md), as well as some basic [Typescript](https://www.typescriptlang.org/). +It is highly recommended that you understand how an [account](../../learn/concepts/accounts/main.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../learn/concepts/accounts/keys.md). You will also need to know how to write a [contract in Noir](../contracts/main.md), as well as some basic [Typescript](https://www.typescriptlang.org/). For this tutorial, we will write an account contract that uses Schnorr signatures for authenticating transaction requests. > That is, every time a transaction payload is passed to this account contract's 'entrypoint' function, the account contract will demand a valid Schnorr signature, whose signed message matches the transaction payload, and whose signer matches the account contract owner's public key. If the signature fails, the transaction will fail. -For the sake of simplicity, we will hardcode the signing public key into the contract, but you could store it [in a private note](../../concepts/foundation/accounts/keys.md#using-a-private-note), [in an immutable note](../../concepts/foundation/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](../../concepts/foundation/accounts/keys.md#using-a-separate-keystore), to mention a few examples. +For the sake of simplicity, we will hardcode the signing public key into the contract, but you could store it [in a private note](../../learn/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](../../learn/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](../../learn/concepts/accounts/keys.md#using-a-separate-keystore), to mention a few examples. ## The account contract @@ -83,7 +83,7 @@ More signing schemes are available in case you want to experiment with other typ Let's try creating a new account backed by our account contract, and interact with a simple token contract to test it works. -To create and deploy the account, we will use the `AccountManager` class, which takes an instance of an Private Execution Environment (PXE), a [privacy private key](../../concepts/foundation/accounts/keys.md#privacy-keys), and an instance of our `AccountContract` class: +To create and deploy the account, we will use the `AccountManager` class, which takes an instance of an Private Execution Environment (PXE), a [privacy private key](../../learn/concepts/accounts/keys.md#privacy-keys), and an instance of our `AccountContract` class: #include_code account-contract-deploy yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript diff --git a/docs/docs/concepts/foundation/main.md b/docs/docs/learn/about_aztec/technical_overview.md similarity index 74% rename from docs/docs/concepts/foundation/main.md rename to docs/docs/learn/about_aztec/technical_overview.md index 6c861dfe12d..7192e34d316 100644 --- a/docs/docs/concepts/foundation/main.md +++ b/docs/docs/learn/about_aztec/technical_overview.md @@ -1,5 +1,5 @@ --- -title: Foundational Concepts +title: Core Components --- Aztec Labs is building a layer 2 rollup on Ethereum focused on 3 things: @@ -36,13 +36,13 @@ An overview of the Aztec network architecture will help contextualize the concep ### Aztec.js -A user of the Aztec network will interact with the network through Aztec.js. Aztec.js is a library that provides APIs for managing accounts and interacting with smart contracts (including account contracts) on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](../../apis/pxe/interfaces/PXE) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. +A user of the Aztec network will interact with the network through Aztec.js. Aztec.js is a library that provides APIs for managing accounts and interacting with smart contracts (including account contracts) on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](../../apis/pxe/index.md) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. ### Private Execution Environment -The PXE provides a secure environment for the execution of sensitive operations, ensuring private information and decrypted data are not accessible to unauthorized applications. It hides the details of the [state model](./state_model/main.md) from end users, but the state model is important for Aztec developers to understand as it has implications for [private/public execution](./communication/public_private_calls/main.md) and [L1/L2 communication](./communication/cross_chain_calls.md). The PXE also includes the [ACIR Simulator](../advanced/acir_simulator.md) for private executions and the KeyStore for secure key management. +The PXE provides a secure environment for the execution of sensitive operations, ensuring private information and decrypted data are not accessible to unauthorized applications. It hides the details of the [state model](../concepts/hybrid_state/main.md) from end users, but the state model is important for Aztec developers to understand as it has implications for [private/public execution](../concepts/communication/public_private_calls/main.md) and [L1/L2 communication](../concepts/communication/cross_chain_calls.md). The PXE also includes the [ACIR Simulator](../concepts/pxe/acir_simulator.md) for private executions and the KeyStore for secure key management. -Procedurally, the PXE sends results of private function execution and requests for public function executions to the [sequencer](./nodes_clients/sequencer.md), which will update the state of the rollup. +Procedurally, the PXE sends results of private function execution and requests for public function executions to the [sequencer](../concepts/nodes_clients/sequencer/main.md), which will update the state of the rollup. ### Sequencer @@ -50,8 +50,8 @@ The sequencer aggregates transactions into a block, generates proofs of the stat ## Further Reading -- [The state model](./state_model/main.md) -- [Accounts](./accounts/main.md) -- [Aztec Smart Contracts](./contracts.md) -- [Transactions](./transactions.md) -- [Communication between network components](./communication/main.md) +- [The state model](../concepts/hybrid_state/main.md) +- [Accounts](../concepts/accounts/main.md) +- [Aztec Smart Contracts](../concepts/smart_contracts/main.md) +- [Transactions](../concepts/transactions.md) +- [Communication between network components](../concepts/communication/main.md) diff --git a/docs/docs/about_aztec/vision.md b/docs/docs/learn/about_aztec/vision.md similarity index 96% rename from docs/docs/about_aztec/vision.md rename to docs/docs/learn/about_aztec/vision.md index 505c29794f5..f29b308f8d3 100644 --- a/docs/docs/about_aztec/vision.md +++ b/docs/docs/learn/about_aztec/vision.md @@ -22,5 +22,5 @@ We are building the [Aztec Network](https://aztec.network/), a fully programmabl To achieve these goals, we are pioneering the cryptography and research needed to bring our next generation, privacy-preserving zk-roll-up to mainnet. -import Disclaimer from "../misc/common/\_disclaimer.mdx"; +import Disclaimer from "../../misc/common/\_disclaimer.mdx"; diff --git a/docs/docs/about_aztec/overview.mdx b/docs/docs/learn/about_aztec/what_is_aztec.mdx similarity index 95% rename from docs/docs/about_aztec/overview.mdx rename to docs/docs/learn/about_aztec/what_is_aztec.mdx index c2e3d1b97a3..76080a98c4a 100644 --- a/docs/docs/about_aztec/overview.mdx +++ b/docs/docs/learn/about_aztec/what_is_aztec.mdx @@ -1,5 +1,5 @@ --- -title: Overview +title: What is Aztec? --- import ReactPlayer from "react-player/youtube"; @@ -50,7 +50,7 @@ Contributors to Aztec uphold many of the values of the Ethereum community -- bui Noir is a domain specific programming language for writing zero-knowledge circuits. On Aztec a smart contract is a collection of circuits that developers write using Noir. -You can find more information and resources for learning about Noir smart contracts on [this page](../dev_docs/contracts/main.md). +You can find more information and resources for learning about Noir smart contracts on [this page](../../developers/contracts/main.md). ## Cryptography @@ -60,5 +60,5 @@ To support Aztec's rollup, our cryptography team is building [Honk](https://gith Keep up with the latest discussion and join the conversation in the [Aztec forum](https://discourse.aztec.network) or [Discord server](https://discord.gg/DgWG2DBMyB). -import Disclaimer from "../misc/common/_disclaimer.mdx"; +import Disclaimer from "../../misc/common/_disclaimer.mdx"; ; diff --git a/docs/docs/concepts/foundation/accounts/authwit.md b/docs/docs/learn/concepts/accounts/authwit.md similarity index 95% rename from docs/docs/concepts/foundation/accounts/authwit.md rename to docs/docs/learn/concepts/accounts/authwit.md index ac26bf13ba1..31fa51e1efa 100644 --- a/docs/docs/concepts/foundation/accounts/authwit.md +++ b/docs/docs/learn/concepts/accounts/authwit.md @@ -54,7 +54,7 @@ All of these issues have been discussed in the community for a while, and there Adopting ERC20 for Aztec is not as simple as it might seem because of private state. -If you recall from [State model](./../state_model/main.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going. +If you recall from the [Hybrid State model](../hybrid_state/main.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going. If we were to implement the `approve` with an allowance in private, you might know the allowance, but unless you also know about the individual notes that make up the user's balances, it would be of no use to you! It is private after all. To spend the user's funds you would need to know the decryption key, see [keys for more](../accounts/keys.md). @@ -182,7 +182,7 @@ For the transfer, this could be done simply by appending a nonce to the argument action = H(defi, token, transfer_selector, H(alice_account, defi, 1000, nonce)); ``` -Beware that the account contract will be unable to emit the nullifier since it is checked with a static call, so the calling contract must do it. This is similar to nonces in ERC20 tokens today. We provide a small library that handles this which we will see in the [developer documentation](./../../../dev_docs/contracts/resources/common_patterns/authwit.md). +Beware that the account contract will be unable to emit the nullifier since it is checked with a static call, so the calling contract must do it. This is similar to nonces in ERC20 tokens today. We provide a small library that handles this which we will see in the [developer documentation](./../../../developers/contracts/resources/common_patterns/authwit.md). ### Differences to approval @@ -196,4 +196,4 @@ We don't need to limit ourselves to the `transfer` function, we can use the same ### Next Steps -Check out the [developer documentation](./../../../dev_docs/contracts/resources/common_patterns/authwit.md) to see how to implement this in your own contracts. +Check out the [developer documentation](./../../../developers/contracts/resources/common_patterns/authwit.md) to see how to implement this in your own contracts. diff --git a/docs/docs/concepts/foundation/accounts/keys.md b/docs/docs/learn/concepts/accounts/keys.md similarity index 98% rename from docs/docs/concepts/foundation/accounts/keys.md rename to docs/docs/learn/concepts/accounts/keys.md index e5d897d0ffc..5802996cf5e 100644 --- a/docs/docs/concepts/foundation/accounts/keys.md +++ b/docs/docs/learn/concepts/accounts/keys.md @@ -14,7 +14,7 @@ This is a snippet of our Schnorr Account contract implementation, which uses Sch #include_code entrypoint /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust -Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](../../../dev_docs/wallets/writing_an_account_contract.md) for a full example of how to manage authentication. +Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](../../../developers/wallets/writing_an_account_contract.md) for a full example of how to manage authentication. Furthermore, and since signatures are fully abstracted, how the key is stored in the contract is abstracted as well and left to the developer of the account contract. Here are a few ideas on how to store them, each with their pros and cons. diff --git a/docs/docs/concepts/foundation/accounts/main.md b/docs/docs/learn/concepts/accounts/main.md similarity index 99% rename from docs/docs/concepts/foundation/accounts/main.md rename to docs/docs/learn/concepts/accounts/main.md index c96238632be..3ad58265637 100644 --- a/docs/docs/concepts/foundation/accounts/main.md +++ b/docs/docs/learn/concepts/accounts/main.md @@ -68,7 +68,7 @@ def entryPoint(payload): enqueueCall(to, data, value, gasLimit); ``` -Read more about how to write an account contract [here](../../../dev_docs/wallets/writing_an_account_contract.md). +Read more about how to write an account contract [here](../../../developers/wallets/writing_an_account_contract.md). ### Account contracts and wallets diff --git a/docs/docs/concepts/foundation/block_production.md b/docs/docs/learn/concepts/block_production.md similarity index 100% rename from docs/docs/concepts/foundation/block_production.md rename to docs/docs/learn/concepts/block_production.md diff --git a/docs/docs/concepts/foundation/blocks.md b/docs/docs/learn/concepts/blocks.md similarity index 100% rename from docs/docs/concepts/foundation/blocks.md rename to docs/docs/learn/concepts/blocks.md diff --git a/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md b/docs/docs/learn/concepts/circuits/kernels/private_kernel.md similarity index 93% rename from docs/docs/concepts/advanced/circuits/kernels/private_kernel.md rename to docs/docs/learn/concepts/circuits/kernels/private_kernel.md index cc0632c986f..1fccebbfa83 100644 --- a/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md +++ b/docs/docs/learn/concepts/circuits/kernels/private_kernel.md @@ -16,10 +16,10 @@ This circuit is executed by the user, on their own device. This is to ensure pri - public call stacks: hashes representing calls to other public functions; - events; - all data accumulated by all previous private kernel circuit recursions of this tx; -- Hides which private function has been executed, by performing a zero-knowledge proof of membership against the [contract tree](../../data_structures/trees). +- Hides which private function has been executed, by performing a zero-knowledge proof of membership against the [contract tree](../../storage/trees/main.md#contract-tree). - Ensures the entire stack trace of private functions (for a particular tx) adheres to function execution rules. - Verifies a previous 'Private Kernel Proof', recursively, when verifying transactions which are composed of many private function calls. -- Optionally can [deploy](../../contract_creation) a new private contract. +- Optionally can [deploy](../../smart_contracts/contract_creation.md) a new private contract. > Note: **This is the only core protocol circuit which actually needs to be "zk" (zero-knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function). > This is a really interesting point. Most so-called "zk-Rollups" do not make use of this "zero-knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero-knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup". diff --git a/docs/docs/concepts/advanced/circuits/kernels/public_kernel.md b/docs/docs/learn/concepts/circuits/kernels/public_kernel.md similarity index 82% rename from docs/docs/concepts/advanced/circuits/kernels/public_kernel.md rename to docs/docs/learn/concepts/circuits/kernels/public_kernel.md index 0bd2c0b7870..e9454ceb545 100644 --- a/docs/docs/concepts/advanced/circuits/kernels/public_kernel.md +++ b/docs/docs/learn/concepts/circuits/kernels/public_kernel.md @@ -2,7 +2,7 @@ title: Public Kernel Circuit --- -This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](../../data_structures/trees) at any time. A Sequencer might choose to delegate proof generation to the Prover pool. +This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](../../storage/trees/main.md#public-state-tree) at any time. A Sequencer might choose to delegate proof generation to the Prover pool. - Exposes (forwards) the following data to the next recursive circuit: - all data accumulated by all previous private kernel circuit recursions of this tx; diff --git a/docs/docs/concepts/advanced/circuits/main.md b/docs/docs/learn/concepts/circuits/main.md similarity index 98% rename from docs/docs/concepts/advanced/circuits/main.md rename to docs/docs/learn/concepts/circuits/main.md index 9a84f9cf60b..8db42f4e153 100644 --- a/docs/docs/concepts/advanced/circuits/main.md +++ b/docs/docs/learn/concepts/circuits/main.md @@ -51,7 +51,7 @@ In other words, since neither the EVM nor other rollups have rules for how to pr What kind of extra rules / checks does a rollup need, to enforce notions of private states and private functions? Stuff like: -- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [trees](../data_structures/trees)). +- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [trees](../storage/trees/main.md)). - "Hide which function was just executed, by wrapping it in a zk-snark" - "Hide all functions which were executed as part of this tx's stack trace, by wrapping the whole tx in a zk-snark" diff --git a/docs/docs/concepts/advanced/circuits/rollup_circuits/main.md b/docs/docs/learn/concepts/circuits/rollup_circuits/main.md similarity index 96% rename from docs/docs/concepts/advanced/circuits/rollup_circuits/main.md rename to docs/docs/learn/concepts/circuits/rollup_circuits/main.md index 6fee1408755..d5ac8be56c8 100644 --- a/docs/docs/concepts/advanced/circuits/rollup_circuits/main.md +++ b/docs/docs/learn/concepts/circuits/rollup_circuits/main.md @@ -23,7 +23,7 @@ For both transactions, it: - Performs public state read membership checks. - Updates the public data tree in line with the requested state transitions. -- Checks that the nullifiers haven't previously been inserted into the [indexed nullifier tree](../../data_structures/indexed_merkle_tree). +- Checks that the nullifiers haven't previously been inserted into the [indexed nullifier tree](../../storage/trees/indexed_merkle_tree.md#primer-on-nullifier-trees). - Batch-inserts new nullifiers into the nullifier tree. - Batch-inserts new commitments into the note hash tree - Batch-inserts any new contract deployments into the contract tree. diff --git a/docs/docs/concepts/foundation/communication/cross_chain_calls.md b/docs/docs/learn/concepts/communication/cross_chain_calls.md similarity index 100% rename from docs/docs/concepts/foundation/communication/cross_chain_calls.md rename to docs/docs/learn/concepts/communication/cross_chain_calls.md diff --git a/docs/docs/concepts/foundation/communication/main.md b/docs/docs/learn/concepts/communication/main.md similarity index 100% rename from docs/docs/concepts/foundation/communication/main.md rename to docs/docs/learn/concepts/communication/main.md diff --git a/docs/docs/concepts/foundation/communication/public_private_calls/main.md b/docs/docs/learn/concepts/communication/public_private_calls/main.md similarity index 99% rename from docs/docs/concepts/foundation/communication/public_private_calls/main.md rename to docs/docs/learn/concepts/communication/public_private_calls/main.md index 34a98047f4f..15ae6df1c8b 100644 --- a/docs/docs/concepts/foundation/communication/public_private_calls/main.md +++ b/docs/docs/learn/concepts/communication/public_private_calls/main.md @@ -1,5 +1,5 @@ --- -title: Private <--> Public execution +title: Private - Public execution --- import Image from "@theme/IdealImage"; diff --git a/docs/docs/concepts/foundation/communication/public_private_calls/slow_updates_tree.md b/docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md similarity index 97% rename from docs/docs/concepts/foundation/communication/public_private_calls/slow_updates_tree.md rename to docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md index c6ceb070e26..a7459932f07 100644 --- a/docs/docs/concepts/foundation/communication/public_private_calls/slow_updates_tree.md +++ b/docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md @@ -70,4 +70,4 @@ Developers are used to instant state updates, so the Slow Updates Tree might tak ## Dive into the code -For a code walkthrough of how a token blacklist contract can use a slow updates tree, read [this](../../../../dev_docs/contracts/syntax/slow_updates_tree.md). \ No newline at end of file +For a code walkthrough of how a token blacklist contract can use a slow updates tree, read [this](../../../../developers/contracts/syntax/slow_updates_tree.md). \ No newline at end of file diff --git a/docs/docs/concepts/foundation/globals.md b/docs/docs/learn/concepts/globals.md similarity index 100% rename from docs/docs/concepts/foundation/globals.md rename to docs/docs/learn/concepts/globals.md diff --git a/docs/docs/concepts/foundation/state_model/main.md b/docs/docs/learn/concepts/hybrid_state/main.md similarity index 97% rename from docs/docs/concepts/foundation/state_model/main.md rename to docs/docs/learn/concepts/hybrid_state/main.md index 36ca4515c3f..ac2565ee39f 100644 --- a/docs/docs/concepts/foundation/state_model/main.md +++ b/docs/docs/learn/concepts/hybrid_state/main.md @@ -55,4 +55,4 @@ This is achieved with two main features: ## Further reading -Read more about how to leverage the Aztec state model in Aztec contracts [here](../../../dev_docs/contracts/syntax/storage/main.md). +Read more about how to leverage the Aztec state model in Aztec contracts [here](../../../developers/contracts/syntax/storage/main.md). diff --git a/docs/docs/concepts/advanced/public_vm.md b/docs/docs/learn/concepts/hybrid_state/public_vm.md similarity index 100% rename from docs/docs/concepts/advanced/public_vm.md rename to docs/docs/learn/concepts/hybrid_state/public_vm.md diff --git a/docs/docs/learn/concepts/main.md b/docs/docs/learn/concepts/main.md new file mode 100644 index 00000000000..0a8c74b2bc0 --- /dev/null +++ b/docs/docs/learn/concepts/main.md @@ -0,0 +1,75 @@ +--- +title: Concepts +--- + +import Image from '@theme/IdealImage'; +import DocCardList from '@theme/DocCardList'; + +This page outlines Aztec's fundamental technical concepts. + +## Aztec Overview + + + +1. A user interacts with Aztec through Aztec.js (like web3js or ethersjs) or Aztec CLI +2. Private functions are executed in the PXE, which is client-side +3. They are rolled up and sent to the Public VM (running on an Aztec node) +4. Public functions are executed in the Public VM +5. The Public VM rolls up the private & public transaction rollups +6. These rollups are submitted to Ethereum + +The PXE is unaware of the Public VM. And the Public VM is unaware of the PXE. They are completely separate execution environments. This means: + +- The PXE and the Public VM cannot directly communicate with each other +- Private transactions in the PXE are executed first, followed by public transactions + +### Private and public state + +Private state works with UTXOs, or what we call notes. To keep things private, everything is stored in an [append-only UTXO tree](../../learn/concepts/storage/trees/main.md#note-hash-tree), and a nullifier is created when notes are invalidated. Nullifiers are then stored in their own [nullifier tree](./storage/trees/indexed_merkle_tree.md#primer-on-nullifier-trees). + +Public state works similarly to other chains like Ethereum, behaving like a public ledger. Public data is stored in a [public data tree](./storage/trees/main.md#public-state-tree). + +Aztec [smart contract](../concepts/smart_contracts/main.md) developers should keep in mind that different types are used when manipulating private or public state. Working with private state is creating commitments and nullifiers to state, whereas working with public state is directly updating state. + +## Accounts + +Every account in Aztec is a smart contract (account abstraction). This allows implementing different schemes for transaction signing, nonce management, and fee payments. + +Developers can write their own account contract to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed. + +Learn more about account contracts [here](../../learn/concepts/accounts/main.md). + +## Smart contracts + +Developers can write [smart contracts](./smart_contracts/main.md) that manipulate both public and private state. They are written in a framework on top of Noir, the zero-knowledge domain-specific language developed specifically for Aztec. Outside of Aztec, Noir is used for writing circuits that can be verified on EVM chains. + +Noir has its own doc site that you can find [here](https://noir-lang.org). + +## Communication with Ethereum + +Aztec allows private communications with Ethereum - ie no-one knows where the transaction is coming from, just that it is coming from somewhere on Aztec. + +This is achieved through portals - these are smart contracts deployed on an EVM that are related to the Ethereum smart contract you want to interact with. + +Learn more about portals [here](./communication/cross_chain_calls.md). + +## Circuits + +Aztec operates on three types of circuits: + +- [Private kernel circuits](./circuits/kernels/private_kernel.md), which are executed by the user on their own device and prove correct execution of a function +- [Public kernel circuits](./circuits/kernels/public_kernel.md), which are executed by the [sequencer](./nodes_clients/sequencer/main.md) and ensure the stack trace of transactions adheres to function execution rules +- [Rollup circuits](./circuits/rollup_circuits/main.md), which bundle all of the Aztec transactions into a proof that can be efficiently verified on Ethereum + +## What's next? + +### Dive deeper into how Aztec works + +Explore the Concepts for a deeper understanding into the components that make up Aztec: + + + +### Start coding + +Follow the [developer getting started guide](../../developers/getting_started/main.md). + diff --git a/docs/docs/concepts/foundation/nodes_clients/execution_client.md b/docs/docs/learn/concepts/nodes_clients/execution_client.md similarity index 100% rename from docs/docs/concepts/foundation/nodes_clients/execution_client.md rename to docs/docs/learn/concepts/nodes_clients/execution_client.md diff --git a/docs/docs/concepts/foundation/nodes_clients/prover_client.md b/docs/docs/learn/concepts/nodes_clients/prover_client.md similarity index 100% rename from docs/docs/concepts/foundation/nodes_clients/prover_client.md rename to docs/docs/learn/concepts/nodes_clients/prover_client.md diff --git a/docs/docs/concepts/foundation/nodes_clients/sequencer.md b/docs/docs/learn/concepts/nodes_clients/sequencer/main.md similarity index 97% rename from docs/docs/concepts/foundation/nodes_clients/sequencer.md rename to docs/docs/learn/concepts/nodes_clients/sequencer/main.md index e9a20081223..4173dd87e2f 100644 --- a/docs/docs/concepts/foundation/nodes_clients/sequencer.md +++ b/docs/docs/learn/concepts/nodes_clients/sequencer/main.md @@ -40,4 +40,4 @@ You can view the current implementation on Github [here](https://github.com/Azte ## Further Reading -- [Sequencer Selection](../../advanced/sequencer_selection.md) +- [Sequencer Selection](../../../concepts/nodes_clients/sequencer/sequencer_selection.md) diff --git a/docs/docs/concepts/advanced/sequencer_selection.md b/docs/docs/learn/concepts/nodes_clients/sequencer/sequencer_selection.md similarity index 100% rename from docs/docs/concepts/advanced/sequencer_selection.md rename to docs/docs/learn/concepts/nodes_clients/sequencer/sequencer_selection.md diff --git a/docs/docs/concepts/advanced/acir_simulator.md b/docs/docs/learn/concepts/pxe/acir_simulator.md similarity index 88% rename from docs/docs/concepts/advanced/acir_simulator.md rename to docs/docs/learn/concepts/pxe/acir_simulator.md index bae95f54ff1..1df355c9bb7 100644 --- a/docs/docs/concepts/advanced/acir_simulator.md +++ b/docs/docs/learn/concepts/pxe/acir_simulator.md @@ -14,13 +14,13 @@ It simulates three types of functions: Private functions are simulated and proved client-side, and verified client-side in the private kernel circuit. -They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](../../dev_docs/contracts/syntax/functions.md#oracle-functions). +They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](../../../developers/contracts/syntax/functions.md#oracle-functions). Private functions can call other private functions and can request to call a public function. The public function execution will be performed by the sequencer asynchronously, so private functions don't have direct access to the return values of public functions. ### Public Functions -Public functions are simulated and proved on the [sequencer](../foundation/nodes_clients/sequencer.md) side, and verified by the [public kernel circuit](./circuits/kernels/public_kernel.md). +Public functions are simulated and proved on the [sequencer](../nodes_clients/sequencer/main.md) side, and verified by the [public kernel circuit](../circuits/kernels/public_kernel.md). They are run with the assistance of an oracle that provides any value read from the public state tree. diff --git a/docs/docs/concepts/advanced/private_execution_environment.md b/docs/docs/learn/concepts/pxe/main.md similarity index 91% rename from docs/docs/concepts/advanced/private_execution_environment.md rename to docs/docs/learn/concepts/pxe/main.md index 50eadfa4820..e8182ab218b 100644 --- a/docs/docs/concepts/advanced/private_execution_environment.md +++ b/docs/docs/learn/concepts/pxe/main.md @@ -31,7 +31,7 @@ graph TD; ## PXE Service -The PXE is a client-side interface of the PXE Service, which is a set of server-side APIs for interacting with the network. It provides functions for account management, contract and transaction interactions, note management, and more. For a more extensive list of operations, refer to the [PXE reference](../../apis/pxe/interfaces/PXE.md). +The PXE is a client-side interface of the PXE Service, which is a set of server-side APIs for interacting with the network. It provides functions for account management, contract and transaction interactions, note management, and more. For a more extensive list of operations, refer to the [PXE reference](../../../apis/pxe/index.md). ## Components @@ -62,9 +62,9 @@ The keystore is a secure storage for private and public keys. ## Oracles -Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [functions section](../../dev_docs/contracts/syntax/functions.md). +Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [functions section](../../../developers/contracts/syntax/functions.md#oracle-functions). ## For developers To learn how to develop on top of the PXE, refer to these guides: -* [Run more than one PXE on your local machine](../../dev_docs/cli/run_more_than_one_pxe_sandbox.md) -* [Use in-built oracles including oracles for arbitrary data](../../dev_docs/contracts/syntax/oracles.md) +* [Run more than one PXE on your local machine](../../../developers/cli/run_more_than_one_pxe_sandbox.md) +* [Use in-built oracles including oracles for arbitrary data](../../../developers/contracts/syntax/oracles.md) \ No newline at end of file diff --git a/docs/docs/concepts/advanced/contract_creation.md b/docs/docs/learn/concepts/smart_contracts/contract_creation.md similarity index 99% rename from docs/docs/concepts/advanced/contract_creation.md rename to docs/docs/learn/concepts/smart_contracts/contract_creation.md index 3eb3380b6c9..b93f5a7d54e 100644 --- a/docs/docs/concepts/advanced/contract_creation.md +++ b/docs/docs/learn/concepts/smart_contracts/contract_creation.md @@ -4,7 +4,7 @@ title: Contract Creation -import Disclaimer from '../../misc/common/\_disclaimer.mdx'; +import Disclaimer from '../../../misc/common/\_disclaimer.mdx'; @@ -327,4 +327,4 @@ Adds initial public state variables to the public data tree. ## Further reading -To see how to deploy a contract in practice, check out the [dapp development tutorial](../../dev_docs/tutorials/writing_dapp/main.md). +To see how to deploy a contract in practice, check out the [dapp development tutorial](../../../developers/tutorials/writing_dapp/main.md). diff --git a/docs/docs/concepts/foundation/contracts.md b/docs/docs/learn/concepts/smart_contracts/main.md similarity index 95% rename from docs/docs/concepts/foundation/contracts.md rename to docs/docs/learn/concepts/smart_contracts/main.md index 98cbd438992..822c7811ac3 100644 --- a/docs/docs/concepts/foundation/contracts.md +++ b/docs/docs/learn/concepts/smart_contracts/main.md @@ -23,4 +23,4 @@ There are no plans for EVM compatibility or to support Solidity in Aztec. The pr ## Further reading -Read more about writing Aztec contracts [here](../../dev_docs/contracts/main.md). +Read more about writing Aztec contracts [here](../../../developers/contracts/main.md). diff --git a/docs/docs/concepts/foundation/state_model/storage_slots.md b/docs/docs/learn/concepts/storage/storage_slots.md similarity index 77% rename from docs/docs/concepts/foundation/state_model/storage_slots.md rename to docs/docs/learn/concepts/storage/storage_slots.md index 0f67af9ec11..80013ecd156 100644 --- a/docs/docs/concepts/foundation/state_model/storage_slots.md +++ b/docs/docs/learn/concepts/storage/storage_slots.md @@ -11,7 +11,7 @@ It also means that we need to be careful about how we allocate storage to ensure ## Public State Slots -As mentioned in [State Model](./main.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address. +As mentioned in [State Model](./../hybrid_state/main.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address. The mental model is that we have a key-value store, where the siloed slot is the key, and the value is the data stored in that slot. You can think of the `real_storage_slot` identifying its position in the tree, and the `logical_storage_slot` identifying the position in the contract storage. @@ -19,14 +19,14 @@ The mental model is that we have a key-value store, where the siloed slot is the real_storage_slot = H(contract_address, logical_storage_slot) ``` -The siloing is performed by the [Kernel circuits](../../advanced/circuits/kernels/main.md). +The siloing is performed by the [Kernel circuits](../../concepts/circuits/main.md). For structs and arrays, we are logically using a similar storage slot computation to ethereum, e.g., as a struct with 3 fields would be stored in 3 consecutive slots. However, because the "actual" storage slot is computed as a hash of the contract address and the logical storage slot, the actual storage slot is not consecutive. ## Private State Slots - Slots aren't real -Private storage is a different beast. As you might remember from [State Model](./main.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree where each leaf is a commitment. Being append-only, means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that lookups at a specific storage slot would leak information in the context of private state. If you could look up a specific address balance just by looking at the storage slot, even if encrypted you would be able to see it changing! That is not good privacy. +Private storage is a different beast. As you might remember from [Hybrid State Model](../hybrid_state/main.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree where each leaf is a commitment. Being append-only, means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that lookups at a specific storage slot would leak information in the context of private state. If you could look up a specific address balance just by looking at the storage slot, even if encrypted you would be able to see it changing! That is not good privacy. Following this, the storage slot as we know it doesn't really exist. The leaves of the note hashes tree are just commitments to content (think of it as a hash of its content). @@ -62,4 +62,4 @@ By doing this address-siloing at the kernel circuit we *force* the inserted comm To ensure that nullifiers don't collide across contracts we also force this contract siloing at the kernel level. ::: -For an example of this see [developer documentation storage slots](./../../../dev_docs/contracts/syntax/storage/storage_slots.md). +For an example of this see [developer documentation storage slots](./../../../developers/contracts/syntax/storage/storage_slots.md). diff --git a/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md b/docs/docs/learn/concepts/storage/trees/indexed_merkle_tree.md similarity index 100% rename from docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md rename to docs/docs/learn/concepts/storage/trees/indexed_merkle_tree.md diff --git a/docs/docs/concepts/advanced/data_structures/trees.md b/docs/docs/learn/concepts/storage/trees/main.md similarity index 96% rename from docs/docs/concepts/advanced/data_structures/trees.md rename to docs/docs/learn/concepts/storage/trees/main.md index d29f9c04669..af58086e10f 100644 --- a/docs/docs/concepts/advanced/data_structures/trees.md +++ b/docs/docs/learn/concepts/storage/trees/main.md @@ -132,7 +132,7 @@ nullifier = hash(note_hash, owner_secret_key); This has the property that it's inextricably linked to the Note it is nullifying, and it can only be derived by the owner of the `owner_public_key` contained within the Note. Ensuring that the secret key corresponds to the public key would be implemented in the Aztec contract. -A smart contract that generates this nullifier and submits it to the network will only be allowed to submit it once; a second submission will be rejected by the base [Rollup Circuit](../circuits/rollup_circuits/main.md#base-rollup-circuit) (which performs Merkle non-membership checks against the Nullifier Tree). This prevents a Note from being 'deleted' twice. +A smart contract that generates this nullifier and submits it to the network will only be allowed to submit it once; a second submission will be rejected by the base [Rollup Circuit](../../circuits/rollup_circuits/main.md) (which performs Merkle non-membership checks against the Nullifier Tree). This prevents a Note from being 'deleted' twice. :::note @@ -171,7 +171,7 @@ This tree's data can only be read/written by the Sequencer, since only they can ## Contract Tree -The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the [Kernel Circuits](../circuits/kernels/main.md) to validate that a function belongs to a specific contract. +The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the [Kernel Circuits](../../circuits/main.md) to validate that a function belongs to a specific contract. @@ -211,7 +211,7 @@ HistoricalAccessTree --- Header ``` -It can also be used to find information about notes, public state, and contracts that were included in a certain block using [inclusion and non-inclusion proofs](../../../dev_docs/contracts/syntax/historical_access/how_to_prove_history.md). +It can also be used to find information about notes, public state, and contracts that were included in a certain block using [inclusion and non-inclusion proofs](../../../../developers/contracts/syntax/historical_access/how_to_prove_history.md). ## Trees of valid Kernel/Rollup circuit Verification Keys diff --git a/docs/docs/concepts/foundation/transactions.md b/docs/docs/learn/concepts/transactions.md similarity index 93% rename from docs/docs/concepts/foundation/transactions.md rename to docs/docs/learn/concepts/transactions.md index ff1dce31933..5cad5bda8e8 100644 --- a/docs/docs/concepts/foundation/transactions.md +++ b/docs/docs/learn/concepts/transactions.md @@ -29,9 +29,9 @@ _The transaction has not been broadcasted to the sequencer network yet._ _The transaction has still not been broadcasted to the sequencer network yet._ -3. **The PXE proves correct execution** – the PXE proves correct execution (via zero-knowledge proofs) of the authorization and the private transfer method. Once the proofs have been generated, the PXE sends the proofs and required inputs (inputs are new note commitments, stored in the [note hash tree](../advanced/data_structures/trees.md#note-hash-tree) and nullifiers stored in the [nullifiers tree](../advanced/data_structures/trees.md#nullifier-tree)) to the sequencer. Nullifiers are data that invalidate old commitments, ensuring that commitments can only be used once. +3. **The PXE proves correct execution** – the PXE proves correct execution (via zero-knowledge proofs) of the authorization and the private transfer method. Once the proofs have been generated, the PXE sends the proofs and required inputs (inputs are new note commitments, stored in the [note hash tree](../concepts/storage/trees/main.md#note-hash-tree) and nullifiers stored in the [nullifiers tree](../concepts/storage/trees/main.md#nullifier-tree)) to the sequencer. Nullifiers are data that invalidate old commitments, ensuring that commitments can only be used once. -The sequencer has received transaction proof and can begin to process the transaction (verify proofs and apply updates to the relevant [data trees](../advanced/data_structures/trees.md)) alongside other public and private transactions. +The sequencer has received transaction proof and can begin to process the transaction (verify proofs and apply updates to the relevant [data trees](../concepts/storage/trees/main.md)) alongside other public and private transactions. 4. **The sequencer has the necessary information to act** – the randomly-selected sequencer (based on the Fernet sequencer selection protocol) validates the transaction proofs along with required inputs (e.g. the note commitments and nullifiers) for this private transfer. The sequencer also executes public functions and requests proofs of public execution from a prover network. The sequencer updates the corresponding data trees and does the same for other private transactions. The sequencer requests proofs from a prover network that will be bundled into a final rollup proof. diff --git a/docs/docs/concepts/foundation/upgrade_mechanism.md b/docs/docs/learn/concepts/upgrade_mechanism.md similarity index 100% rename from docs/docs/concepts/foundation/upgrade_mechanism.md rename to docs/docs/learn/concepts/upgrade_mechanism.md diff --git a/docs/docs/misc/common/_disclaimer.mdx b/docs/docs/misc/common/_disclaimer.mdx index 2bd4a3a0cfc..b6d393fef45 100644 --- a/docs/docs/misc/common/_disclaimer.mdx +++ b/docs/docs/misc/common/_disclaimer.mdx @@ -3,7 +3,7 @@ :::caution Disclaimer We are building Aztec as transparently as we can. The documents published here are living documents. The protocol, sandbox, language, and tools are all subject to change over time. -Please see [here](../../dev_docs/limitations/main.md) for details of known Aztec protocol and Aztec Sandbox limitations. +Please see [here](../../developers/limitations/main.md) for details of known Aztec protocol and Aztec Sandbox limitations. If you would like to help us build Aztec: - Contribute code on [GitHub](https://github.com/AztecProtocol); or diff --git a/docs/docs/about_aztec/how_to_contribute.md b/docs/docs/misc/how_to_contribute.md similarity index 100% rename from docs/docs/about_aztec/how_to_contribute.md rename to docs/docs/misc/how_to_contribute.md diff --git a/docs/docs/about_aztec/roadmap/cryptography_roadmap.md b/docs/docs/misc/roadmap/cryptography_roadmap.md similarity index 100% rename from docs/docs/about_aztec/roadmap/cryptography_roadmap.md rename to docs/docs/misc/roadmap/cryptography_roadmap.md diff --git a/docs/docs/about_aztec/roadmap/engineering_roadmap.md b/docs/docs/misc/roadmap/engineering_roadmap.md similarity index 98% rename from docs/docs/about_aztec/roadmap/engineering_roadmap.md rename to docs/docs/misc/roadmap/engineering_roadmap.md index 890d0f1e14a..4b5163f90ad 100644 --- a/docs/docs/about_aztec/roadmap/engineering_roadmap.md +++ b/docs/docs/misc/roadmap/engineering_roadmap.md @@ -121,7 +121,7 @@ CI takes up a significant amount of time. It gets its own section here, so we re We _need_ a way to read mutable public data from a private function. -Note: we just published the [Slow Updates Tree](../../concepts/foundation/communication/public_private_calls/slow_updates_tree.md). +Note: we just published the [Slow Updates Tree](../../learn/concepts/communication/public_private_calls/slow_updates_tree.md). ## Contract classes and instances? diff --git a/docs/docs/about_aztec/roadmap/features_initial_ldt.md b/docs/docs/misc/roadmap/features_initial_ldt.md similarity index 100% rename from docs/docs/about_aztec/roadmap/features_initial_ldt.md rename to docs/docs/misc/roadmap/features_initial_ldt.md diff --git a/docs/docs/about_aztec/roadmap/main.md b/docs/docs/misc/roadmap/main.md similarity index 100% rename from docs/docs/about_aztec/roadmap/main.md rename to docs/docs/misc/roadmap/main.md diff --git a/docs/docs/intro.md b/docs/docs/welcome.md similarity index 62% rename from docs/docs/intro.md rename to docs/docs/welcome.md index ca9ff902fe9..6be66998211 100644 --- a/docs/docs/intro.md +++ b/docs/docs/welcome.md @@ -1,11 +1,11 @@ --- slug: "/" -id: "intro" -title: What is Aztec? +id: "welcome" +title: Welcome description: "Aztec introduces a privacy-centric zkRollup solution for Ethereum, enhancing confidentiality and scalability within the Ethereum ecosystem." --- -# Aztec: Ethereum, encrypted +# Aztec: A Privacy-First L2 on Ethereum On Ethereum today, everything is publicly visible, by everyone. In the real world, people enjoy privacy. Aztec brings privacy to Ethereum. @@ -13,11 +13,11 @@ On Ethereum today, everything is publicly visible, by everyone. In the real worl ### Learn :book: -Start on the [Foundational Concepts page](./concepts/foundation/main.md) to read about how Aztec works. +Start on the [Technical Overview page](./learn/about_aztec/technical_overview.md) to read about how Aztec works. ### Build :technologist: -Go to the [Getting Started section](./dev_docs/getting_started/main.md) of the developer docs to get your hands dirty and start developing on Aztec. +Go to the [Getting Started section](./developers/getting_started/main.md) of the developer docs to get your hands dirty and start developing on Aztec. #### Go deeper 🔬 @@ -25,4 +25,4 @@ Check out the [Awesome Aztec repo](https://github.com/AztecProtocol/awesome-azte Clone the [Aztec Starter repo](https://github.com/AztecProtocol/aztec-starter) to get a minimal project set up with Sandbox (local developer network), a simple contract and a test suite. -Jump into one of the [tutorials](./dev_docs/tutorials/main.md) to learn how to build more complex applications on Aztec. +Jump into one of the [tutorials](./developers/tutorials/main.md) to learn how to build more complex applications on Aztec. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index efe1271187e..d2ffd760db2 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -195,7 +195,7 @@ const config = { items: [ { type: "doc", - docId: "intro", + docId: "welcome", position: "left", label: "Aztec Protocol", }, @@ -213,7 +213,7 @@ const config = { }, { label: "Developer Quickstart", - to: "/dev_docs/getting_started/quickstart", + to: "/developers/getting_started/quickstart", }, { label: "Aztec.nr", diff --git a/docs/internal_notes/building_dapps.md b/docs/internal_notes/building_dapps.md index b6d4f3a1be1..4cc8792a3bd 100644 --- a/docs/internal_notes/building_dapps.md +++ b/docs/internal_notes/building_dapps.md @@ -36,7 +36,7 @@ FOR INSTRUCTIONS FOR BUILDING A WALLET, WE SHOULD WRITE DOCS HERE ERRORS: -- Add any error explanations to [errors.md](../docs/dev_docs/contracts/common_errors.md) (and break that file into multiple files if it's too unwieldy). +- Add any error explanations to [errors.md](../docs/developers/contracts/common_errors.md) (and break that file into multiple files if it's too unwieldy). ## Testing a dapp diff --git a/docs/netlify.toml b/docs/netlify.toml index a26ea50351b..029b6ad77e3 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -20,87 +20,87 @@ [[redirects]] from = "/dev_docs/aztec3/*" - to = "/dev_docs/aztec/overview" + to = "/learn/about_aztec/what_is_aztec" [[redirects]] from = "/dev_docs/contracts/types" - to = "/dev_docs/contracts/syntax/types" + to = "/developers/contracts/syntax/types" [[redirects]] from = "/dev_docs/contracts/storage" - to = "/dev_docs/contracts/syntax/storage" + to = "/developers/contracts/syntax/storage" [[redirects]] from = "/dev_docs/contracts/state_variables" - to = "/dev_docs/contracts/syntax/storage" + to = "/developers/contracts/syntax/storage" [[redirects]] from = "/dev_docs/contracts/functions" - to = "/dev_docs/contracts/syntax/functions" + to = "/developers/contracts/syntax/functions" [[redirects]] from = "/dev_docs/contracts/visibility" - to = "/dev_docs/contracts/syntax/visibility" + to = "/developers/contracts/syntax/visibility" [[redirects]] from = "/dev_docs/contracts/globals" - to = "/dev_docs/contracts/syntax/globals" + to = "/developers/contracts/syntax/globals" [[redirects]] from = "/dev_docs/contracts/syntax" - to = "/dev_docs/contracts/syntax/main" + to = "/developers/contracts/syntax/main" [[redirects]] from = "/dev_docs/contracts/contract" - to = "/dev_docs/contracts/syntax/contract" + to = "/developers/contracts/syntax/contract" [[redirects]] from = "/dev_docs/getting_started/cli" - to = "/dev_docs/cli/main" + to = "/developers/cli/main" [[redirects]] from = "/dev_docs/getting_started/noir_contracts" - to = "/dev_docs/contracts/main" + to = "/developers/contracts/main" [[redirects]] from = "/dev_docs/getting_started/token_contract_tutorial" - to = "/dev_docs/tutorials/writing_token_contract" + to = "/developers/tutorials/writing_token_contract" [[redirects]] from = "/dev_docs/getting_started/updating" - to = "/dev_docs/updating" + to = "/developers/updating" [[redirects]] from = "/dev_docs/sandbox/main" - to = "/dev_docs/getting_started/sandbox" + to = "/developers/getting_started/sandbox" [[redirects]] from = "/dev_docs/cli/updating" - to = "/dev_docs/updating" + to = "/developers/updating" [[redirects]] from = "/dev_docs/dapps/tutorials/main" - to = "/dev_docs/tutorials/writing_dapp/main" + to = "/developers/tutorials/writing_dapp/main" [[redirects]] from = "/dev_docs/dapps/tutorials/project_setup" - to = "/dev_docs/tutorials/writing_dapp/project_setup" + to = "/developers/tutorials/writing_dapp/project_setup" [[redirects]] from = "/dev_docs/dapps/tutorials/contract_deployment" - to = "/dev_docs/tutorials/writing_dapp/contract_deployment" + to = "/developers/tutorials/writing_dapp/contract_deployment" [[redirects]] from = "/dev_docs/dapps/tutorials/contract_interaction" - to = "/dev_docs/tutorials/writing_dapp/contract_interaction" + to = "/developers/tutorials/writing_dapp/contract_interaction" [[redirects]] from = "/dev_docs/dapps/tutorials/rpc_server" - to = "/dev_docs/tutorials/writing_dapp/rpc_server" + to = "/developers/tutorials/writing_dapp/rpc_server" [[redirects]] from = "/dev_docs/dapps/tutorials/testing" - to = "/dev_docs/tutorials/writing_dapp/testing" + to = "/developers/tutorials/writing_dapp/testing" [[redirects]] from = "/aztec/cryptography/cryptography-roadmap" @@ -112,55 +112,55 @@ [[redirects]] from = "/aztec/protocol/trees" - to = "/concepts/advanced/data_structures/trees" + to = "/learn/concepts/storage/trees/main" [[redirects]] from = "/aztec/protocol/trees/indexed-merkle-tree" - to = "/concepts/advanced/data_structures/indexed_merkle_tree" + to = "/learn/concepts/storage/trees/indexed_merkle_tree" [[redirects]] from = "/aztec/protocol/circuits/private-kernel" - to = "/concepts/advanced/circuits/kernels/private_kernel" + to = "/learn/concepts/circuits/kernels/private_kernel" [[redirects]] from = "/aztec/protocol/circuits/public-kernel" - to = "/concepts/advanced/circuits/kernels/public_kernel" + to = "/learn/concepts/circuits/kernels/public_kernel" [[redirects]] from = "/aztec/protocol/circuits/rollup" - to = "/concepts/advanced/circuits/rollup_circuits/main" + to = "/learn/concepts/circuits/rollup_circuits/main" [[redirects]] from = "/aztec/protocol/public-functions-vm-architectures" - to = "/concepts/advanced/public_vm" + to = "/learn/concepts/hybrid_state/public_vm" [[redirects]] from = "/aztec/how-it-works/private-smart-contracts" - to = "/concepts/foundation/contracts" + to = "/learn/concepts/contracts/main" [[redirects]] from = "/aztec/how-it-works/private-state" - to = "/concepts/foundation/state_model/main" + to = "/learn/concepts/hybrid_state/main" [[redirects]] from = "/concepts/foundation/state_model" - to = "/concepts/foundation/state_model/main" + to = "/learn/concepts/hybrid_state/main" [[redirects]] from = "/aztec/how-it-works/private-public-execution" - to = "/concepts/foundation/communication/public_private_calls/main" + to = "/learn/concepts/communication/public_private_calls/main" [[redirects]] from="/concepts/foundation/communication/public_private_calls" - to="/concepts/foundation/communication/public_private_calls/main" + to="/learn/concepts/communication/public_private_calls/main" [[redirects]] from = "/aztec/how-it-works/l1-l2-messaging" - to = "/concepts/foundation/communication/cross_chain_calls" + to = "/learn/concepts/communication/cross_chain_calls" [[redirects]] from = "/aztec/protocol/contract-creation" - to = "/concepts/advanced/contract_creation" + to = "/learn/concepts/contracts/contract_creation" [[redirects]] from = "/noir" @@ -180,27 +180,27 @@ [[redirects]] from = "/dev_docs/contracts/syntax/state_variables" - to = "/dev_docs/contracts/syntax/storage" + to = "/developers/contracts/syntax/storage" [[redirects]] from = "/dev_docs/getting_started/sandbox" - to = "/dev_docs/getting_started/quickstart" + to = "/developers/getting_started/quickstart" [[redirects]] from = "/dev_docs/getting_started/blank_box" - to = "/dev_docs/cli/blank_box" + to = "/developers/cli/blank_box" [[redirects]] from = "/dev_docs/getting_started/updating" - to = "/dev_docs/cli/updating" + to = "/developers/cli/updating" [[redirects]] from = "/dev_docs/sandbox_errors/main" - to = "dev_docs/debugging/sandbox-errors" + to = "developers/debugging/sandbox-errors" [[redirects]] from = "/dev_docs/contracts/common_errors" - to = "dev_docs/debugging/aztecnr-errors" + to = "developers/debugging/aztecnr-errors" [[redirects]] from = "/misc/aztec-connect-sunset" diff --git a/docs/sidebars.js b/docs/sidebars.js index 9f1a456b865..28f41753eaf 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -24,34 +24,15 @@ const sidebars = { { type: "html", className: "sidebar-title", - value: "About Aztec", + value: "LEARN", defaultStyle: true, }, - { - label: "What is Aztec?", - type: "category", - link: { type: "doc", id: "intro" }, - items: ["about_aztec/overview"], - }, - - "about_aztec/vision", - - { - label: "Roadmap", - type: "category", - link: { - type: "doc", - id: "about_aztec/roadmap/main", - }, - items: [ - "about_aztec/roadmap/features_initial_ldt", - "about_aztec/roadmap/cryptography_roadmap", - ], - }, - - "about_aztec/how_to_contribute", - + "welcome", + "learn/about_aztec/what_is_aztec", + "learn/about_aztec/vision", + "learn/about_aztec/technical_overview", + { type: "html", value: '', @@ -60,99 +41,93 @@ const sidebars = { // SPECIFICATION { - type: "html", - className: "sidebar-title", - value: "Specification", - defaultStyle: true, - }, - - { - label: "Foundational Concepts", + label: "Concepts", type: "category", link: { type: "doc", - id: "concepts/foundation/main", + id: "learn/concepts/main", }, items: [ { - label: "State Model", + label: "Hybrid State Model", type: "category", link: { type: "doc", - id: "concepts/foundation/state_model/main", + id: "learn/concepts/hybrid_state/main", }, - items: ["concepts/foundation/state_model/storage_slots"], + items: [ + "learn/concepts/hybrid_state/public_vm", + ], + }, + { + label: "Storage", + type: "category", + items: [ + { + label: "Trees", + type: "category", + link: { + type: "doc", + id: "learn/concepts/storage/trees/main", + }, + items: [ + "learn/concepts/storage/trees/indexed_merkle_tree", + ], + }, + "learn/concepts/storage/storage_slots", + ], }, { label: "Accounts", type: "category", - link: { type: "doc", id: "concepts/foundation/accounts/main" }, + link: { + type: "doc", + id: "learn/concepts/accounts/main", + }, items: [ - "concepts/foundation/accounts/keys", - "concepts/foundation/accounts/authwit", + "learn/concepts/accounts/keys", + "learn/concepts/accounts/authwit", ], }, - "concepts/foundation/contracts", - "concepts/foundation/transactions", - // "concepts/foundation/globals", + "learn/concepts/transactions", { - label: "Communication", + label: "Smart Contracts", type: "category", link: { type: "doc", - id: "concepts/foundation/communication/main", + id: "learn/concepts/smart_contracts/main", }, + items: [ + "learn/concepts/smart_contracts/contract_creation", + ], + }, + { + label: "Communication", + type: "category", items: [ { label: "Public <> Private Communication", type: "category", link: { type: "doc", - id: "concepts/foundation/communication/public_private_calls/main", + id: "learn/concepts/communication/public_private_calls/main", }, items: [ - "concepts/foundation/communication/public_private_calls/slow_updates_tree", + "learn/concepts/communication/public_private_calls/slow_updates_tree", ], }, - "concepts/foundation/communication/cross_chain_calls", + "learn/concepts/communication/cross_chain_calls", ], }, { - label: "Nodes and Clients", - type: "category", - // link: { - // type: "doc", - // id: "concepts/foundation/nodes_clients/main", - // }, - items: [ - // "concepts/foundation/nodes_clients/execution_client", - // "concepts/foundation/nodes_clients/prover_client", - "concepts/foundation/nodes_clients/sequencer", - ], - }, - // "concepts/foundation/block_production", - // "concepts/foundation/upgrade_mechanism", - ], - }, - - { - label: "Advanced Concepts", - type: "category", - link: { - type: "doc", - id: "concepts/advanced/main", - }, - items: [ - { - label: "Data Structures", + label: "Private Execution Environment (PXE)", type: "category", link: { type: "doc", - id: "concepts/advanced/data_structures/main", + id: "learn/concepts/pxe/main", }, items: [ - "concepts/advanced/data_structures/trees", - "concepts/advanced/data_structures/indexed_merkle_tree", + "learn/concepts/pxe/acir_simulator", ], }, { @@ -160,51 +135,46 @@ const sidebars = { type: "category", link: { type: "doc", - id: "concepts/advanced/circuits/main", + id: "learn/concepts/circuits/main", }, items: [ { - label: "Kernels", + label: "Kernel Circuits", type: "category", - link: { - type: "doc", - id: "concepts/advanced/circuits/kernels/main", - }, items: [ - "concepts/advanced/circuits/kernels/private_kernel", - "concepts/advanced/circuits/kernels/public_kernel", + "learn/concepts/circuits/kernels/private_kernel", + "learn/concepts/circuits/kernels/public_kernel", ], }, + "learn/concepts/circuits/rollup_circuits/main", + ], + }, + { + label: "Nodes and Clients", + type: "category", + items: [ { - label: "Rollup Circuits", - type: "category", + label: "Sequencer", link: { type: "doc", - id: "concepts/advanced/circuits/rollup_circuits/main", + id: "learn/concepts/nodes_clients/sequencer/main", }, - items: [], + type: "category", + items: [ + "learn/concepts/nodes_clients/sequencer/sequencer_selection", + ], }, ], }, - "concepts/advanced/public_vm", - "concepts/advanced/contract_creation", - "concepts/advanced/private_execution_environment", - "concepts/advanced/sequencer_selection", - "concepts/advanced/acir_simulator", ], }, - { - type: "html", - value: '', - }, - // DEVELOPER DOCUMENTATION { type: "html", className: "sidebar-title", - value: "Developer Documentation", + value: "BUILD", defaultStyle: true, }, @@ -213,13 +183,12 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/getting_started/main", + id: "developers/getting_started/main", }, items: [ - "dev_docs/getting_started/quickstart", - "dev_docs/getting_started/core-concepts", - "dev_docs/getting_started/aztecnr-getting-started", - "dev_docs/getting_started/aztecjs-getting-started", + "developers/getting_started/quickstart", + "developers/getting_started/aztecnr-getting-started", + "developers/getting_started/aztecjs-getting-started", ], }, @@ -228,25 +197,25 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/tutorials/main", + id: "developers/tutorials/main", }, items: [ - "dev_docs/tutorials/writing_token_contract", - "dev_docs/tutorials/writing_private_voting_contract", + "developers/tutorials/writing_token_contract", + "developers/tutorials/writing_private_voting_contract", { label: "Writing a DApp", type: "category", link: { type: "doc", - id: "dev_docs/tutorials/writing_dapp/main", + id: "developers/tutorials/writing_dapp/main", }, items: [ - "dev_docs/tutorials/writing_dapp/project_setup", - "dev_docs/tutorials/writing_dapp/pxe_service", - "dev_docs/tutorials/writing_dapp/contract_deployment", - "dev_docs/tutorials/writing_dapp/contract_interaction", - "dev_docs/tutorials/writing_dapp/testing", + "developers/tutorials/writing_dapp/project_setup", + "developers/tutorials/writing_dapp/pxe_service", + "developers/tutorials/writing_dapp/contract_deployment", + "developers/tutorials/writing_dapp/contract_interaction", + "developers/tutorials/writing_dapp/testing", ], }, { @@ -254,15 +223,15 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/tutorials/token_portal/main", + id: "developers/tutorials/token_portal/main", }, items: [ - "dev_docs/tutorials/token_portal/setup", - "dev_docs/tutorials/token_portal/depositing_to_aztec", - "dev_docs/tutorials/token_portal/minting_on_aztec", - "dev_docs/tutorials/token_portal/cancelling_deposits", - "dev_docs/tutorials/token_portal/withdrawing_to_l1", - "dev_docs/tutorials/token_portal/typescript_glue_code", + "developers/tutorials/token_portal/setup", + "developers/tutorials/token_portal/depositing_to_aztec", + "developers/tutorials/token_portal/minting_on_aztec", + "developers/tutorials/token_portal/cancelling_deposits", + "developers/tutorials/token_portal/withdrawing_to_l1", + "developers/tutorials/token_portal/typescript_glue_code", ], }, { @@ -270,21 +239,21 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/tutorials/uniswap/main", + id: "developers/tutorials/uniswap/main", }, items: [ - "dev_docs/tutorials/uniswap/setup", - "dev_docs/tutorials/uniswap/l1_portal", - "dev_docs/tutorials/uniswap/l2_contract_setup", - "dev_docs/tutorials/uniswap/swap_publicly", - "dev_docs/tutorials/uniswap/execute_public_swap_on_l1", - "dev_docs/tutorials/uniswap/swap_privately", - "dev_docs/tutorials/uniswap/execute_private_swap_on_l1", - "dev_docs/tutorials/uniswap/redeeming_swapped_assets_on_l2", - "dev_docs/tutorials/uniswap/typescript_glue_code", + "developers/tutorials/uniswap/setup", + "developers/tutorials/uniswap/l1_portal", + "developers/tutorials/uniswap/l2_contract_setup", + "developers/tutorials/uniswap/swap_publicly", + "developers/tutorials/uniswap/execute_public_swap_on_l1", + "developers/tutorials/uniswap/swap_privately", + "developers/tutorials/uniswap/execute_private_swap_on_l1", + "developers/tutorials/uniswap/redeeming_swapped_assets_on_l2", + "developers/tutorials/uniswap/typescript_glue_code", ], }, - "dev_docs/tutorials/testing", + "developers/tutorials/testing", ], }, @@ -293,12 +262,12 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/cli/main", + id: "developers/cli/main", }, items: [ - "dev_docs/cli/cli-commands", - "dev_docs/cli/sandbox-reference", - "dev_docs/cli/run_more_than_one_pxe_sandbox" + "developers/cli/cli-commands", + "developers/cli/sandbox-reference", + "developers/cli/run_more_than_one_pxe_sandbox" ], }, { @@ -306,18 +275,18 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/contracts/main", + id: "developers/contracts/main", }, items: [ - "dev_docs/contracts/workflow", - "dev_docs/contracts/setup", - "dev_docs/contracts/layout", + "developers/contracts/workflow", + "developers/contracts/setup", + "developers/contracts/layout", { label: "Syntax", type: "category", link: { type: "doc", - id: "dev_docs/contracts/syntax/main", + id: "developers/contracts/syntax/main", }, items: [ { @@ -325,63 +294,67 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/contracts/syntax/storage/main", + id: "developers/contracts/syntax/storage/main", }, - items: ["dev_docs/contracts/syntax/storage/storage_slots"], + items: [ + "developers/contracts/syntax/storage/private_state", + "developers/contracts/syntax/storage/public_state", + "developers/contracts/syntax/storage/storage_slots", + ], }, - "dev_docs/contracts/syntax/events", - "dev_docs/contracts/syntax/functions", - "dev_docs/contracts/syntax/oracles", + "developers/contracts/syntax/events", + "developers/contracts/syntax/functions", + "developers/contracts/syntax/oracles", { label: "Proving Historical Blockchain Data", type: "category", items: [ - "dev_docs/contracts/syntax/historical_access/how_to_prove_history", - "dev_docs/contracts/syntax/historical_access/history_lib_reference", + "developers/contracts/syntax/historical_access/how_to_prove_history", + "developers/contracts/syntax/historical_access/history_lib_reference", ], }, - "dev_docs/contracts/syntax/slow_updates_tree", + "developers/contracts/syntax/slow_updates_tree", - "dev_docs/contracts/syntax/context", - "dev_docs/contracts/syntax/globals", + "developers/contracts/syntax/context", + "developers/contracts/syntax/globals", ], }, - "dev_docs/contracts/compiling", - "dev_docs/contracts/deploying", - "dev_docs/contracts/artifacts", + "developers/contracts/compiling", + "developers/contracts/deploying", + "developers/contracts/artifacts", { label: "Portals", type: "category", link: { type: "doc", - id: "dev_docs/contracts/portals/main", + id: "developers/contracts/portals/main", }, items: [ - "dev_docs/contracts/portals/data_structures", - "dev_docs/contracts/portals/registry", - "dev_docs/contracts/portals/inbox", - "dev_docs/contracts/portals/outbox", + "developers/contracts/portals/data_structures", + "developers/contracts/portals/registry", + "developers/contracts/portals/inbox", + "developers/contracts/portals/outbox", ], }, { label: "Resources", type: "category", items: [ - "dev_docs/contracts/resources/dependencies", - //"dev_docs/contracts/resources/style_guide", + "developers/contracts/resources/dependencies", + //"developers/contracts/resources/style_guide", { label: "Common Patterns", type: "category", link: { type: "doc", - id: "dev_docs/contracts/resources/common_patterns/main", + id: "developers/contracts/resources/common_patterns/main", }, items: [ - "dev_docs/contracts/resources/common_patterns/authwit", - // "dev_docs/contracts/resources/common_patterns/sending_tokens_to_user", - // "dev_docs/contracts/resources/common_patterns/sending_tokens_to_contract", - // "dev_docs/contracts/resources/common_patterns/access_control", - // "dev_docs/contracts/resources/common_patterns/interacting_with_l1", + "developers/contracts/resources/common_patterns/authwit", + // "developers/contracts/resources/common_patterns/sending_tokens_to_user", + // "developers/contracts/resources/common_patterns/sending_tokens_to_contract", + // "developers/contracts/resources/common_patterns/access_control", + // "developers/contracts/resources/common_patterns/interacting_with_l1", ], }, ], @@ -395,9 +368,9 @@ const sidebars = { // type: "category", // link: { // type: "doc", - // id: "dev_docs/contracts/security/breaking_changes/main", + // id: "developers/contracts/security/breaking_changes/main", // }, - // items: ["dev_docs/contracts/security/breaking_changes/v0"], + // items: ["developers/contracts/security/breaking_changes/v0"], // }, // ], // }, @@ -407,24 +380,24 @@ const sidebars = { { label: "Aztec.js", type: "doc", - id: "dev_docs/aztecjs/main", + id: "developers/aztecjs/main", }, { label: "Debugging", type: "category", link: { type: "doc", - id: "dev_docs/debugging/main", + id: "developers/debugging/main", }, items: [ - "dev_docs/debugging/aztecnr-errors", - "dev_docs/debugging/sandbox-errors", + "developers/debugging/aztecnr-errors", + "developers/debugging/sandbox-errors", ], }, { label: "Updating", type: "doc", - id: "dev_docs/updating", + id: "developers/updating", }, { @@ -432,21 +405,21 @@ const sidebars = { type: "category", link: { type: "doc", - id: "dev_docs/testing/main", + id: "developers/testing/main", }, - items: ["dev_docs/testing/cheat_codes"], + items: ["developers/testing/cheat_codes"], }, { label: "Wallets", type: "category", link: { type: "doc", - id: "dev_docs/wallets/main", + id: "developers/wallets/main", }, items: [ - "dev_docs/wallets/architecture", - "dev_docs/wallets/writing_an_account_contract", - "dev_docs/wallets/creating_schnorr_accounts", + "developers/wallets/architecture", + "developers/wallets/writing_an_account_contract", + "developers/wallets/creating_schnorr_accounts", ], }, @@ -455,8 +428,8 @@ const sidebars = { type: "category", items: [], },*/ - "dev_docs/privacy/main", - "dev_docs/limitations/main", + "developers/privacy/main", + "developers/limitations/main", { label: "API Reference", @@ -490,11 +463,24 @@ const sidebars = { { type: "html", className: "sidebar-title", - value: "Miscellaneous", + value: "MISCELLANEOUS", defaultStyle: true, }, "misc/migration_notes", "misc/glossary", + { + label: "Roadmap", + type: "category", + link: { + type: "doc", + id: "misc/roadmap/main", + }, + items: [ + "misc/roadmap/features_initial_ldt", + "misc/roadmap/cryptography_roadmap", + ], + }, + "misc/how_to_contribute", { type: "html", @@ -505,4 +491,4 @@ const sidebars = { ], }; -module.exports = sidebars; +module.exports = sidebars; \ No newline at end of file diff --git a/l1-contracts/Dockerfile b/l1-contracts/Dockerfile index 5544b0eaa7b..f6ccb1dc6b8 100644 --- a/l1-contracts/Dockerfile +++ b/l1-contracts/Dockerfile @@ -1,14 +1,6 @@ -# Linting requires node. -FROM node:18.19.0-alpine -RUN apk update && apk add --no-cache build-base git python3 curl bash jq -WORKDIR /usr/src/l1-contracts -COPY . . -RUN yarn && yarn lint - # Building requires foundry. -FROM ghcr.io/foundry-rs/foundry:nightly-c331b5eeee1b4151ef7354a081667e2d770b37f5 -# Required for foundry -RUN apk update && apk add git jq bash +FROM ghcr.io/foundry-rs/foundry:nightly-4a643801d0b3855934cdec778e33e79c79971783 +RUN apk update && apk add git jq bash nodejs npm yarn python3 py3-pip && pip3 install slither-analyzer WORKDIR /usr/src/l1-contracts COPY . . RUN git init @@ -17,4 +9,7 @@ RUN forge install --no-commit \ https://github.com/foundry-rs/forge-std \ https://github.com/openzeppelin/openzeppelin-contracts # Run build and tests -RUN forge clean && forge fmt --check && forge build && forge test \ No newline at end of file +RUN forge clean && forge fmt --check && forge build && forge test +RUN yarn && yarn lint +RUN git add . && yarn slither && yarn slither-has-diff +RUN forge build \ No newline at end of file diff --git a/l1-contracts/README.md b/l1-contracts/README.md index cacd6087454..e3b27c55388 100644 --- a/l1-contracts/README.md +++ b/l1-contracts/README.md @@ -66,10 +66,25 @@ For now, this include bytecode for contract deployment, but over time this will We use an extended version of solhint (https://github.com/LHerskind/solhint) to include custom rules. These custom rules relate to how errors should be named, using custom errors instead of reverts etc, see `.solhint.json` for more specifics about the rules. -The linter is the only node module we need which is the reason behind not going full yarn-project on it. It is not part of the docker image, but can be run once in a while to make sure we are on track. +The linter is the only node module we need which is the reason behind not going full yarn-project on it. To run the linter, simply run: ```bash yarn lint ``` + +--- + +# Slither + +We use slither as an automatic way to find blunders and common vulnerabilities in our contracts. It is not part of the docker image due to its slowness, but it can be run using the following command to generate a markdown file with the results: +```bash +yarn slither +``` + +When this command is run in CI, it will fail if the markdown file generated in docker don't match the one in the repository. + +We assume that you already have slither installed. You can install it with `pip3 install slither-analyzer`. It is kept out of the bootstrap script as it is not a requirement for people who just want to run tests or are uninterested in the contracts. + +> We are not running the `naming-convention` detector because we have our own rules for naming which is enforced by the linter. \ No newline at end of file diff --git a/l1-contracts/package.json b/l1-contracts/package.json index 1969ca98520..006ddcd0228 100644 --- a/l1-contracts/package.json +++ b/l1-contracts/package.json @@ -7,6 +7,8 @@ "solhint": "https://github.com/LHerskind/solhint#master" }, "scripts": { - "lint": "solhint --config ./.solhint.json --fix \"src/**/*.sol\"" + "lint": "solhint --config ./.solhint.json --fix \"src/**/*.sol\"", + "slither": "forge clean && forge build --build-info --skip '*/test/**' --force && slither . --checklist --ignore-compile --show-ignored-findings --config-file ./slither.config.json | tee slither_output.md", + "slither-has-diff": "./slither_has_diff.sh" } } diff --git a/l1-contracts/slither.config.json b/l1-contracts/slither.config.json new file mode 100644 index 00000000000..c77991cc91c --- /dev/null +++ b/l1-contracts/slither.config.json @@ -0,0 +1,3 @@ +{ + "detectors_to_exclude": "naming-convention" +} diff --git a/l1-contracts/slither_has_diff.sh b/l1-contracts/slither_has_diff.sh new file mode 100755 index 00000000000..2489723a946 --- /dev/null +++ b/l1-contracts/slither_has_diff.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +FILE="slither_output.md" + +DIFF_OUTPUT=$(git diff -- "$FILE") + +if [ -z "$DIFF_OUTPUT" ]; then + echo "No difference found." +else + echo "Difference found!" + exit 1 +fi diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md new file mode 100644 index 00000000000..7b45948006d --- /dev/null +++ b/l1-contracts/slither_output.md @@ -0,0 +1,249 @@ +Summary + - [uninitialized-local](#uninitialized-local) (1 results) (Medium) + - [unused-return](#unused-return) (1 results) (Medium) + - [reentrancy-events](#reentrancy-events) (1 results) (Low) + - [timestamp](#timestamp) (4 results) (Low) + - [assembly](#assembly) (5 results) (Informational) + - [dead-code](#dead-code) (13 results) (Informational) + - [solc-version](#solc-version) (1 results) (Informational) + - [low-level-calls](#low-level-calls) (1 results) (Informational) + - [similar-names](#similar-names) (1 results) (Informational) + - [unused-state](#unused-state) (2 results) (Informational) + - [constable-states](#constable-states) (1 results) (Optimization) +## uninitialized-local +Impact: Medium +Confidence: Medium + - [ ] ID-0 +[HeaderLib.decode(bytes).header](src/core/libraries/HeaderLib.sol#L133) is a local variable never initialized + +src/core/libraries/HeaderLib.sol#L133 + + +## unused-return +Impact: Medium +Confidence: Medium + - [ ] ID-1 +[Rollup.process(bytes,bytes32,bytes32,bytes,bytes)](src/core/Rollup.sol#L54-L94) ignores return value by [(inHash,l1ToL2Msgs,l2ToL1Msgs) = MessagesDecoder.decode(_body)](src/core/Rollup.sol#L71-L72) + +src/core/Rollup.sol#L54-L94 + + +## reentrancy-events +Impact: Low +Confidence: Medium + - [ ] ID-2 +Reentrancy in [Rollup.process(bytes,bytes32,bytes32,bytes,bytes)](src/core/Rollup.sol#L54-L94): + External calls: + - [inbox.batchConsume(l1ToL2Msgs,msg.sender)](src/core/Rollup.sol#L88) + - [outbox.sendL1Messages(l2ToL1Msgs)](src/core/Rollup.sol#L91) + Event emitted after the call(s): + - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L93) + +src/core/Rollup.sol#L54-L94 + + +## timestamp +Impact: Low +Confidence: Medium + - [ ] ID-3 +[Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143) uses timestamp for comparisons + Dangerous comparisons: + - [block.timestamp > entry.deadline](src/core/messagebridge/Inbox.sol#L136) + +src/core/messagebridge/Inbox.sol#L122-L143 + + + - [ ] ID-4 +[Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91) uses timestamp for comparisons + Dangerous comparisons: + - [_deadline <= block.timestamp](src/core/messagebridge/Inbox.sol#L54) + +src/core/messagebridge/Inbox.sol#L45-L91 + + + - [ ] ID-5 +[HeaderLib.validate(HeaderLib.Header,uint256,uint256,bytes32)](src/core/libraries/HeaderLib.sol#L91-L121) uses timestamp for comparisons + Dangerous comparisons: + - [_header.globalVariables.timestamp > block.timestamp](src/core/libraries/HeaderLib.sol#L105) + +src/core/libraries/HeaderLib.sol#L91-L121 + + + - [ ] ID-6 +[Inbox.cancelL2Message(DataStructures.L1ToL2Msg,address)](src/core/messagebridge/Inbox.sol#L102-L113) uses timestamp for comparisons + Dangerous comparisons: + - [block.timestamp <= _message.deadline](src/core/messagebridge/Inbox.sol#L108) + +src/core/messagebridge/Inbox.sol#L102-L113 + + +## assembly +Impact: Informational +Confidence: High + - [ ] ID-7 +[Decoder.computeRoot(bytes32[])](src/core/libraries/decoders/Decoder.sol#L373-L392) uses assembly + - [INLINE ASM](src/core/libraries/decoders/Decoder.sol#L380-L382) + +src/core/libraries/decoders/Decoder.sol#L373-L392 + + + - [ ] ID-8 +[TxsDecoder.decode(bytes)](src/core/libraries/decoders/TxsDecoder.sol#L71-L184) uses assembly + - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L98-L104) + +src/core/libraries/decoders/TxsDecoder.sol#L71-L184 + + + - [ ] ID-9 +[Decoder.computeConsumables(bytes)](src/core/libraries/decoders/Decoder.sol#L164-L301) uses assembly + - [INLINE ASM](src/core/libraries/decoders/Decoder.sol#L196-L202) + - [INLINE ASM](src/core/libraries/decoders/Decoder.sol#L289-L295) + +src/core/libraries/decoders/Decoder.sol#L164-L301 + + + - [ ] ID-10 +[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L256-L275) uses assembly + - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L263-L265) + +src/core/libraries/decoders/TxsDecoder.sol#L256-L275 + + + - [ ] ID-11 +[MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L52-L102) uses assembly + - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L81-L83) + - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L94-L96) + +src/core/libraries/decoders/MessagesDecoder.sol#L52-L102 + + +## dead-code +Impact: Informational +Confidence: Medium + - [ ] ID-12 +[Decoder.computeConsumables(bytes)](src/core/libraries/decoders/Decoder.sol#L164-L301) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L164-L301 + + + - [ ] ID-13 +[Inbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Inbox.sol#L212-L230) is never used and should be removed + +src/core/messagebridge/Inbox.sol#L212-L230 + + + - [ ] ID-14 +[Decoder.slice(bytes,uint256,uint256)](src/core/libraries/decoders/Decoder.sol#L401-L407) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L401-L407 + + + - [ ] ID-15 +[Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L115-L117) is never used and should be removed + +src/core/messagebridge/Outbox.sol#L115-L117 + + + - [ ] ID-16 +[Decoder.computeRoot(bytes32[])](src/core/libraries/decoders/Decoder.sol#L373-L392) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L373-L392 + + + - [ ] ID-17 +[Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L59-L61) is never used and should be removed + +src/core/libraries/Hash.sol#L59-L61 + + + - [ ] ID-18 +[Decoder.computeKernelLogsHash(uint256,bytes)](src/core/libraries/decoders/Decoder.sol#L335-L365) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L335-L365 + + + - [ ] ID-19 +[Decoder.read4(bytes,uint256)](src/core/libraries/decoders/Decoder.sol#L415-L417) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L415-L417 + + + - [ ] ID-20 +[Decoder.computeStateHash(uint256,uint256,bytes)](src/core/libraries/decoders/Decoder.sol#L146-L154) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L146-L154 + + + - [ ] ID-21 +[Decoder.computePublicInputHash(bytes,bytes32,bytes32)](src/core/libraries/decoders/Decoder.sol#L118-L125) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L118-L125 + + + - [ ] ID-22 +[Inbox._errNothingToConsume(bytes32)](src/core/messagebridge/Inbox.sol#L197-L199) is never used and should be removed + +src/core/messagebridge/Inbox.sol#L197-L199 + + + - [ ] ID-23 +[Decoder.getL2BlockNumber(bytes)](src/core/libraries/decoders/Decoder.sol#L132-L134) is never used and should be removed + +src/core/libraries/decoders/Decoder.sol#L132-L134 + + + - [ ] ID-24 +[Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L130-L148) is never used and should be removed + +src/core/messagebridge/Outbox.sol#L130-L148 + + +## solc-version +Impact: Informational +Confidence: High + - [ ] ID-25 +solc-0.8.21 is not recommended for deployment + +## low-level-calls +Impact: Informational +Confidence: High + - [ ] ID-26 +Low level call in [Inbox.withdrawFees()](src/core/messagebridge/Inbox.sol#L148-L153): + - [(success) = msg.sender.call{value: balance}()](src/core/messagebridge/Inbox.sol#L151) + +src/core/messagebridge/Inbox.sol#L148-L153 + + +## similar-names +Impact: Informational +Confidence: Medium + - [ ] ID-27 +Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L30) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L39) + +src/core/Rollup.sol#L30 + + +## unused-state +Impact: Informational +Confidence: High + - [ ] ID-28 +[Decoder.END_TREES_BLOCK_HEADER_OFFSET](src/core/libraries/decoders/Decoder.sol#L103-L104) is never used in [Decoder](src/core/libraries/decoders/Decoder.sol#L72-L418) + +src/core/libraries/decoders/Decoder.sol#L103-L104 + + + - [ ] ID-29 +[Decoder.BLOCK_HEADER_OFFSET](src/core/libraries/decoders/Decoder.sol#L107-L108) is never used in [Decoder](src/core/libraries/decoders/Decoder.sol#L72-L418) + +src/core/libraries/decoders/Decoder.sol#L107-L108 + + +## constable-states +Impact: Optimization +Confidence: High + - [ ] ID-30 +[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L37) should be constant + +src/core/Rollup.sol#L37 + + diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index e8eb5f3c5c0..5acfe14e2f3 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -24,6 +24,7 @@ library Constants { uint256 internal constant MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; uint256 internal constant MAX_PUBLIC_DATA_READS_PER_CALL = 16; uint256 internal constant MAX_READ_REQUESTS_PER_CALL = 32; + uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1; uint256 internal constant MAX_NEW_COMMITMENTS_PER_TX = 64; uint256 internal constant MAX_NEW_NULLIFIERS_PER_TX = 64; uint256 internal constant MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX = 8; @@ -34,6 +35,7 @@ library Constants { uint256 internal constant MAX_NEW_CONTRACTS_PER_TX = 1; uint256 internal constant MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX = 4; uint256 internal constant MAX_READ_REQUESTS_PER_TX = 128; + uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; uint256 internal constant NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; uint256 internal constant NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; uint256 internal constant NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; @@ -76,7 +78,7 @@ library Constants { uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 190; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; - uint256 internal constant CALL_PRIVATE_FUNCTION_RETURN_SIZE = 195; + uint256 internal constant CALL_PRIVATE_FUNCTION_RETURN_SIZE = 199; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 87; uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 177; uint256 internal constant COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 39ec6a692bc..568bbda37c6 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -59,4 +59,7 @@ library Errors { // Registry error Registry__RollupNotRegistered(address rollup); // 0xa1fee4cf error Registry__RollupAlreadyRegistered(address rollup); // 0x3c34eabf + + // HeaderLib + error HeaderLib__InvalidHeaderSize(uint256 expected, uint256 actual); // 0xf3ccb247 } diff --git a/l1-contracts/src/core/libraries/HeaderLib.sol b/l1-contracts/src/core/libraries/HeaderLib.sol index 894cd91ac6a..5ea03ee283c 100644 --- a/l1-contracts/src/core/libraries/HeaderLib.sol +++ b/l1-contracts/src/core/libraries/HeaderLib.sol @@ -22,29 +22,29 @@ import {Hash} from "./Hash.sol"; * | byte start | num bytes | name * | --- | --- | --- * | | | Header { - * | | | GlobalVariables { - * | 0x0000 | 0x20 | chainId - * | 0x0020 | 0x20 | version - * | 0x0040 | 0x20 | blockNumber - * | 0x0060 | 0x20 | timestamp - * | | | } + * | 0x0000 | 0x20 | lastArchive.root + * | 0x0020 | 0x04 | lastArchive.nextAvailableLeafIndex + * | 0x0024 | 0x20 | bodyHash * | | | StateReference { - * | 0x0080 | 0x20 | l1ToL2MessageTree.root - * | 0x00a0 | 0x04 | l1ToL2MessageTree.nextAvailableLeafIndex + * | 0x0044 | 0x20 | l1ToL2MessageTree.root + * | 0x0064 | 0x04 | l1ToL2MessageTree.nextAvailableLeafIndex * | | | PartialStateReference { - * | 0x00a4 | 0x20 | noteHashTree.root - * | 0x00c4 | 0x04 | noteHashTree.nextAvailableLeafIndex - * | 0x00c8 | 0x20 | nullifierTree.root - * | 0x00e8 | 0x04 | nullifierTree.nextAvailableLeafIndex - * | 0x00ec | 0x20 | contractTree.root - * | 0x010c | 0x04 | contractTree.nextAvailableLeafIndex - * | 0x0110 | 0x20 | publicDataTree.root - * | 0x0130 | 0x04 | publicDataTree.nextAvailableLeafIndex + * | 0x0068 | 0x20 | noteHashTree.root + * | 0x0088 | 0x04 | noteHashTree.nextAvailableLeafIndex + * | 0x008c | 0x20 | nullifierTree.root + * | 0x00ac | 0x04 | nullifierTree.nextAvailableLeafIndex + * | 0x00b0 | 0x20 | contractTree.root + * | 0x00d0 | 0x04 | contractTree.nextAvailableLeafIndex + * | 0x00d4 | 0x20 | publicDataTree.root + * | 0x00f4 | 0x04 | publicDataTree.nextAvailableLeafIndex * | | | } * | | | } - * | 0x0134 | 0x20 | lastArchive.root - * | 0x0154 | 0x04 | lastArchive.nextAvailableLeafIndex - * | 0x0158 | 0x20 | bodyHash + * | | | GlobalVariables { + * | 0x00f8 | 0x20 | chainId + * | 0x0118 | 0x20 | version + * | 0x0138 | 0x20 | blockNumber + * | 0x0158 | 0x20 | timestamp + * | | | } * | | | } * | --- | --- | --- */ @@ -54,13 +54,6 @@ library HeaderLib { uint32 nextAvailableLeafIndex; } - struct GlobalVariables { - uint256 chainId; - uint256 version; - uint256 blockNumber; - uint256 timestamp; - } - struct PartialStateReference { AppendOnlyTreeSnapshot noteHashTree; AppendOnlyTreeSnapshot nullifierTree; @@ -74,43 +67,18 @@ library HeaderLib { PartialStateReference partialStateReference; } + struct GlobalVariables { + uint256 chainId; + uint256 version; + uint256 blockNumber; + uint256 timestamp; + } + struct Header { - GlobalVariables globalVariables; - StateReference stateReference; AppendOnlyTreeSnapshot lastArchive; bytes32 bodyHash; - } - - /** - * @notice Decodes the header - * @param _header - The header calldata - * @return The decoded header - */ - function decode(bytes calldata _header) internal pure returns (Header memory) { - require(_header.length == 376, "Invalid header length"); - - Header memory header; - - header.globalVariables.chainId = uint256(bytes32(_header[:0x20])); - header.globalVariables.version = uint256(bytes32(_header[0x20:0x40])); - header.globalVariables.blockNumber = uint256(bytes32(_header[0x40:0x60])); - header.globalVariables.timestamp = uint256(bytes32(_header[0x60:0x80])); - header.stateReference.l1ToL2MessageTree = - AppendOnlyTreeSnapshot(bytes32(_header[0x80:0xa0]), uint32(bytes4(_header[0xa0:0xa4]))); - header.stateReference.partialStateReference.noteHashTree = - AppendOnlyTreeSnapshot(bytes32(_header[0xa4:0xc4]), uint32(bytes4(_header[0xc4:0xc8]))); - header.stateReference.partialStateReference.nullifierTree = - AppendOnlyTreeSnapshot(bytes32(_header[0xc8:0xe8]), uint32(bytes4(_header[0xe8:0xec]))); - header.stateReference.partialStateReference.contractTree = - AppendOnlyTreeSnapshot(bytes32(_header[0xec:0x10c]), uint32(bytes4(_header[0x10c:0x110]))); - header.stateReference.partialStateReference.publicDataTree = - AppendOnlyTreeSnapshot(bytes32(_header[0x110:0x130]), uint32(bytes4(_header[0x130:0x134]))); - header.lastArchive = - AppendOnlyTreeSnapshot(bytes32(_header[0x134:0x154]), uint32(bytes4(_header[0x154:0x158]))); - - header.bodyHash = bytes32(_header[0x158:0x178]); - - return header; + StateReference stateReference; + GlobalVariables globalVariables; } /** @@ -151,4 +119,50 @@ library HeaderLib { revert Errors.Rollup__InvalidArchive(_archive, _header.lastArchive.root); } } + + /** + * @notice Decodes the header + * @param _header - The header calldata + * @return The decoded header + */ + function decode(bytes calldata _header) internal pure returns (Header memory) { + if (_header.length != 376) { + revert Errors.HeaderLib__InvalidHeaderSize(376, _header.length); + } + + Header memory header; + + // Reading lastArchive + header.lastArchive = AppendOnlyTreeSnapshot( + bytes32(_header[0x0000:0x0020]), uint32(bytes4(_header[0x0020:0x0024])) + ); + + // Reading bodyHash + header.bodyHash = bytes32(_header[0x0024:0x0044]); + + // Reading StateReference + header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot( + bytes32(_header[0x0044:0x0064]), uint32(bytes4(_header[0x0064:0x0068])) + ); + header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot( + bytes32(_header[0x0068:0x0088]), uint32(bytes4(_header[0x0088:0x008c])) + ); + header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot( + bytes32(_header[0x008c:0x00ac]), uint32(bytes4(_header[0x00ac:0x00b0])) + ); + header.stateReference.partialStateReference.contractTree = AppendOnlyTreeSnapshot( + bytes32(_header[0x00b0:0x00d0]), uint32(bytes4(_header[0x00d0:0x00d4])) + ); + header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot( + bytes32(_header[0x00d4:0x00f4]), uint32(bytes4(_header[0x00f4:0x00f8])) + ); + + // Reading GlobalVariables + header.globalVariables.chainId = uint256(bytes32(_header[0x00f8:0x0118])); + header.globalVariables.version = uint256(bytes32(_header[0x0118:0x0138])); + header.globalVariables.blockNumber = uint256(bytes32(_header[0x0138:0x0158])); + header.globalVariables.timestamp = uint256(bytes32(_header[0x0158:0x0178])); + + return header; + } } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 387dcbac6a8..d3a7dcb7ad2 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -67,7 +67,7 @@ contract RollupTest is DecoderBase { bytes memory body = data.body; assembly { - mstore(add(header, 0x20), 0x420) + mstore(add(header, add(0x20, 0x00f8)), 0x420) } bytes32 txsHash = availabilityOracle.publish(body); @@ -83,7 +83,7 @@ contract RollupTest is DecoderBase { bytes memory body = data.body; assembly { - mstore(add(header, 0x40), 0x420) + mstore(add(header, add(0x20, 0x0118)), 0x420) } bytes32 txsHash = availabilityOracle.publish(body); @@ -100,7 +100,7 @@ contract RollupTest is DecoderBase { uint256 ts = block.timestamp + 1; assembly { - mstore(add(header, 0x80), ts) + mstore(add(header, add(0x20, 0x0158)), ts) } bytes32 txsHash = availabilityOracle.publish(body); diff --git a/l1-contracts/test/decoders/Decoder.t.sol b/l1-contracts/test/decoders/Decoder.t.sol index e11586d30b4..cde3eee14b3 100644 --- a/l1-contracts/test/decoders/Decoder.t.sol +++ b/l1-contracts/test/decoders/Decoder.t.sol @@ -8,7 +8,7 @@ import {Hash} from "../../src/core/libraries/Hash.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; import {DecoderHelper} from "./helpers/DecoderHelper.sol"; -import {HeaderDecoderHelper} from "./helpers/HeaderDecoderHelper.sol"; +import {HeaderLibHelper} from "./helpers/HeaderLibHelper.sol"; import {MessagesDecoderHelper} from "./helpers/MessagesDecoderHelper.sol"; import {TxsDecoderHelper} from "./helpers/TxsDecoderHelper.sol"; import {HeaderLib} from "../../src/core/libraries/HeaderLib.sol"; @@ -27,13 +27,13 @@ import {AvailabilityOracle} from "../../src/core/availability_oracle/Availabilit */ contract DecoderTest is DecoderBase { DecoderHelper internal helper; - HeaderDecoderHelper internal headerHelper; + HeaderLibHelper internal headerHelper; MessagesDecoderHelper internal messagesHelper; TxsDecoderHelper internal txsHelper; function setUp() public virtual { helper = new DecoderHelper(); - headerHelper = new HeaderDecoderHelper(); + headerHelper = new HeaderLibHelper(); messagesHelper = new MessagesDecoderHelper(); txsHelper = new TxsDecoderHelper(); } diff --git a/l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol b/l1-contracts/test/decoders/helpers/HeaderLibHelper.sol similarity index 92% rename from l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol rename to l1-contracts/test/decoders/helpers/HeaderLibHelper.sol index 5d78b620b2a..7d839535a74 100644 --- a/l1-contracts/test/decoders/helpers/HeaderDecoderHelper.sol +++ b/l1-contracts/test/decoders/helpers/HeaderLibHelper.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.18; import {HeaderLib} from "../../../src/core/libraries/HeaderLib.sol"; -contract HeaderDecoderHelper { +contract HeaderLibHelper { // A wrapper used such that we get "calldata" and not memory function decode(bytes calldata _header) public pure returns (HeaderLib.Header memory) { return HeaderLib.decode(_header); diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 69a1059fe90..bed87d58ed3 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -75,7 +75,7 @@ } } }, - "header": "0x0000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000041ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000601a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02000000015b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a7", + "header": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02000000015b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a71864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000041ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000600000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", "publicInputsHash": "0x1476d6b0483d0d5fc4c9d3b04f50105d97a06bb01054ec7acccac3ff6c85f960" } diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index 006b03407f5..2d4639fc25f 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -35,7 +35,7 @@ ] }, "block": { - "archive": "0x01a7192428c21e1c55be4d35e253b2f30a48c4d7fdb3f4048d208986707b7906", + "archive": "0x2068f1adad2617364389ebe8a1eb54b969af5f5145be43080dce735a0edb0e3e", "body": "0x000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000", "calldataHash": "0x5b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a7", "decodedHeader": { @@ -43,7 +43,7 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1705501940, + "timestamp": 1706272901, "version": 1 }, "lastArchive": { @@ -75,8 +75,8 @@ } } }, - "header": "0x0000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065a7e4f41864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000081ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000a01a11e8b1d440a44deef8aa8e4eec8f476e780ee6eac2d7d64b09c66b8063ee11000000025b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a7", + "header": "0x1a11e8b1d440a44deef8aa8e4eec8f476e780ee6eac2d7d64b09c66b8063ee11000000025b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a71864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000081ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000a00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065b3a885", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x0730fec86325dbb2c6cb108f50628cf32f22f526411f8ef8e48fd8be5f43f536" + "publicInputsHash": "0x2c3372274a0c11108d634c3f133ae26232b662ca28c127f1710d92645d206b72" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index b9e7aea554e..11e14b9d7a4 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -53,10 +53,10 @@ }, "block": { "archive": "0x1f1de772c009f5b1660876343eb57b7a676a84c695b0c526de2f238c41810907", - "body": "0x000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000061900000008000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003410000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401000000041c72e330b60e0052863df88b19ebb482d412b0a7bbb2fabb9347be5e59453d10078d263242fac5a2ad544b5005bcea367ebc04e01ff7ca279650bc63d9488ac304ad4d395e21ea570da47bf574569c6526312c5c7ad63a6d248f694e5c81c2b60e12693b411d9eb8f564aa43f4aa14e3e30f8574425a6d6491416332b77d2709000000000000000000000000000000000000000000000000000000000000104041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000010c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c10000000000000000000000000000000000000000000000000000000000001100010101010101010101010101010101010101010100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc00000090083367367613e6307621401e0b943e65d00d94f7edba399d403da5d93b1a260922e76adec1b929ab590c851320486c68244084a7f9ea21e5ece1e5dfe99ed6069d12051b95f1210b468eb7a029d2b437107a5a246cc1ba5c8f590f4db407e035a353dc7913b80b52296e05af286de4e002586c55a0c4914e946268a214e0caa1f040bd17a9a93471faffd36dc9835a0e00000090ead4b0c12eaa3254338bbcb40631f1f09b696da71b404cbf7415a1ee3b767d9943920b1dc8deeafa855a44f74bc38c4a74537b01cbb09f8612e4256575c2931a98ec9fcc5892ec9da59eb4807ad5fc0613222acb0c141fe55ec8bca4afdef1de719ac262d7ffea40a4d8d5bfe4ca69c10f624cd3f2f922fd8f5a10a7f212bec0c876327251624bfd7d777ac8884b62ee000000908cd0590d2d18f1214ff5b03b6a1d4cfebfd3e463e1b8e98b81fef46a5ba1b0204686f7c57a65f0bc5ce8bbdfc658c1f6bf4e52b5494ea72f193706883d6f1e5949ecd47315b3e2d1e75208e1c1ac3ba2079c257743ca4a9a4fc96389cd96ec0116a35814f15543843d383818637698392b5d5c5e3851162f2f53df7777c1c45c48b8899ac511d2a97c4faa87b25d98c8000001bc000000903ef97e0c57a6f5834dd84e80e8140c989a97a42ceee35be251dbf29ca3b9f1d4ec53f628312fb024fb1fabf2fdae3c222cc6f52957adaf9197fc22aa824e9afd66b58f53765e2edfcaa1e09bea5d09822c7d1ab1c0cdcbc2839c0ddd4eec2435989bf25e9f105380068b77674cd555da0d171b7673337a53fc13bd94d037cb898889a1690494f98997d6ad6f7cc9395000000090a66537d78ef99d64dcbbc8ac804c985b57d0a15f66dc4e0718252c967ba90161684073a50b2de36c358c3b2d7695af8128ae6fa3b5de2ba491f0f33c4b79256ae780a6b2fa2b8985fcaf46f51b0fe08c1f0be001e5faf07671f50d5d3f3cce0a2b14d8e600356c2190c919f7d5e95826223e80c90c4a715ab25286ec0a8d7fa958a0921ea9df290fb3bd39d9bd779abd000000903b40d81778940a1fbf4b631c6ca7f3f36db907262f5b7c9dbf7ed4677be6b459fd5aa18aa47d58a769fbc70cefd0a14d95d33dc980cff26b234154eaa53ba2e3a301af3d81881091d9c478670d47d98e2b6d37e7a5f4c5fe019363217b64d95782a5619e4eb81582b1798faa5764b58405bed270e597925e8e6b29101e97594231cd55747be6725f19e7faa830aa719b000001bc000000903cabd8fd2d8cc1b863fd474708974e9a086456a8c87bb553bc3b2249a6e6d35cea1bd6cefe1469e8d0505d496da0ba43fa23d5f95c1c9ceacee8d86bc37408bf788a77cd803aee3e8e9ca6be0d5c94f228565b5fe9635fdaf5cb935db1c32ba2eb22e34967322d150bbbd7418be5b47d0214392be8237a660118ab42a43436e5ee08e251d72da69b1e79b1682ec7dc110000009073b2ff420af305f8d6e8877c931a27e634e0e02ad27bd07a221ad29898bd955d5110432c2d520e3e608d73f71db60a877a0cdac7023fe16e14894242fc69a6630ad88e96ed3d9d9076850ea7f2da60302a5103978eb03a24aeaa3ea100b61250b98b8430a42fa3b40d9835841dd01a160597bfd46679cb40dc21fe48f5bfd0d457b4d857ffa793eb3931b23b5a5575e000000090cae03a08acbe94f7daa500858bac74ee45668f7d8b8699c05d15b6c8e3a7cb8e68caa3b92fca659e8b2ff5e0a459d10de2d9faf8d23e5e7e52e7bb3ce821a8d1b23eb3e68b93f2792385210f1c7900e910f6892d878b639348529c87faa00be2522c1084fb1f660ade21c84b7193003e0742f05a45a89b327fad6d6d8c8c8d6d77a0721e688149b63867f7930eba8342000001bc000000909a9712eb2ca308f32883b79151fca031a8e418d19df5dd397ca5ea709cefe8a36855686415423dc2afa0115c7987cce0d69612d7b485e7350a63b4d83f9e2f227e0422dcc23e1f2322b8df45ec7a8853147f0a8ea06fea5cdab7b07659ee18c036b4decfcb5be193e05fda85b194f10f1725eb65e156b30c5a39806822af3fe584cf9d541723131a22a23d1400ec9df9000000901cc8c637db22248cb9ed2e7ed8b7818f01b2af67c16ec9d9808bfcdf8b3bd4e8e750f54a84f646cad8f17eabc164de05f97fd66eee2495a419762ce946f40feb5f703bf8a5f1df0c2f4ba03f641b79160b234176a75d19d6e8a48b4ddd7e03c1289b3ec09a79220ee291370d2113bdc504924683165fc5d275305e79c7cd7a99a36537b9cc94befe1a2373b55e3460f600000090b8bd36129be0f622298f580af1ce6cd694052bda2e07761d1260b253b9b58206071b8329586dee5c5acbeeb94eb02a3753ea4c9614f7f9b9a6345451df3e7fae190b6c494514aed8c7fb7af6145072ae192a9f383c5d48e6cdcad12db87adbace3e736819ce046fda81bbad9b08c0946070798e6b179878937fcd611638e83637ee32c0260e48e372d621c3424b0c66f000001bc00000090c1e5c80e7841d56f2fdc2e22252561986ac0bde8583467b7b7cee85533dd4e82db0023a4aa1280e62e82f1208c465d378c09fe6f571a5d6f540ce1575db5a430eea826342e1b3eb17edaeaba692b3b3c1a9b142508381f48759935787a260b1360cbeb6a3d6f84faf868faaabe86f9831cb84a0def9afcae01d13019e2f20fb0d7fd57755bf8cf337ebd61c5d8e2e2d1000000908e7f1fd37c67d43076831de6f05532cff7fdfb2e2f57e1a3a51bcd9192a40bed6bfaa130ce8cc5d174a14e78f3f269baf7afc9a54b07e71f87d9fade5b0b2c8bd1973b0660b2c0ea5c1323fce5b40eba1fffb76ec613395d3a59e1588c5ebd8fb0f6ab9758df61d991c68b94ea2374a120a570858b479f0603c36e2b9d71bf2e85275fb3bdfb8919ad81f34d106fff6500000090110542aebfe9f65c67402024cb573c20c15d4835724350ba9c4389777e540ed6046da159569ee140da387a7628e7bd71359b470625cfd22a2ef99b2bc9e3dbb60f92b901a1bd8cc7dd325010cd83dd2d2704a4a0e660466faac7a416bce77d91c55b9d2ecb1f8d9d9c627832be30f4312bf94f8a074a7f94a363430d73571d5436dd9ea9bb13d907965b62686edbc8c0000001bc00000090b1b087d7329b0e3a4eb671fde2368893708b601576f3229943a86385ce556707b1f3838287448c58240ce1053b0fc102928723780612640d14a06993d3cef135803ca465102ba0ce7b0180c1a2a5f86e167c4a9c29f4a1783f93e36e5da3246f2117272dd6ff9a2388c6e78bc68e79951b3b844bd1c9a08ee529a5d851df7571c8698b37674d4bdbebf416422b5b1b5d00000090adf29bb0ad8c624adc804c04eea5fcb04d0d9e1b1eb3dc13f09adf0af446ee7d63f60f79423311a40926cf93f4652f306ff72b0e1fdfb0fd2f9d40a278eb076fd4dcbdc2455eff29f08388609213113e17e430c2a54f0d542b2ed1e8bb4b3a66d1bd8dec420e19feba9c40a94d2fabec22e9e452ff8e1e062f4f6b3d71a71798edef1aabd9bc34cdfc86d357bfbc03300000009046114b8c401cb7a062546f00d9506462e8c59a34cbadbedee505f9964f0c00f91e76f232fb6d1fd6b23ac668095ffa7cbbe69eec9a1683483d117a18bd478c50d95cf7db543b69b47398a9d882cc043a2ce5032191bcb02027b0e1a588c0a78d89a09b56337027f328a9f37dac01b66d1d4f45d56e66a2d8909cd8907d5f538ea8be3e635885bd5cc5e018bead3c16f4000001bc00000090174d1d04ca93c9ca135a32a723bb8967a20200bbb988465a446ff902b77675377c405ef506bb6a52daa0caa3b92333d2d9ccf16c130455e0499af88f64ffa855fe93d68d285f3aa916a96e92f33dda572b67c99a667585f74f8cbed06a7baf5aa1891caaee8594d5ac241331a4a12db61d59c1418591a4b8e553d37f38ea41dd4f3af725857dd679a9ce2540a608b17600000090d51e3b5514ee11b26f48094e98382d9552ec78b1eb2a9ac3bf24c87050f31350bf027db86146b05b78fa04582e8e0f943cb18005e9bef42f5a26b27ac45ec5c186170367d36d64a1a15ae4ac30f960112934d6f501914dc3f8fe2081ac4a8be04649a8a23b1ce48a2e1e80d58ce1b67114fcc3214860532b0873915328c140ad663ea2a4c69225afe369c736ef6731df000000901a0614eebea2300dcd77bff3171ac89dbf10245ab35b0f66a6fbea6af09024d465895f491da812ce7b116ba1be3590d1b6ebb2650444187876eb87f9acae4344a12c9f26fef7b619512a82cc5e87392627172f181e622b76ad3c6eac337fbdaade012e6ce8ab235e9d7c457503f216961890422725c67cd84b0319edfefd35dd60d9d88a0c52cd76508cc077bf65c425000001bc0000009020daeae685b4a7d525fa9e7322887a1da77d1379c01593d06367e695e044247a30bc981149f091016a4fd7b65016c2d4dfb8d9356cd33cd741c1df7f139acddbdc94573f89a76f4f2884436d22eb69361a5f09304639dcb02feb179b2f1128f7336824922f4639d03a1227a7a60f55512d03ec183fa21321d4fa61963ba2c2e191d37f25e88eed06291961c155656641000000907745a1f472feba9a29b326cb944fe0478c26c54b6423025ebf12a03925bb30d949f46c0c6fa5ee8c58d86ee0d210f0c397bbd41fc5b1cf46147fbed121631e3dee48473eb6ea01ff20cbeac67c5489f10ce126c6c4e735d5c40e16f674941015e0ae8d94f896ae0d4cd703ec8d2a9b0f105422e72324726e8277939f7f59d1b4a77f17de58303017608e60747567da6e0000009019216981b066c88ed0b3b6f2df84132b0d272d72597ef14bb385b81685909118c95d3d92a73f4ba6af2dcec7c94ccd6ab630209146343d808060fed0df2efd837f54cb06c78bf253fa1b8b8a5d4d7a902218c7234feec00a4e7b214b06a598b4caa2649745402606220865f338d0db2408404192c99dcc6a7c2c06a4e10ac8c625e008aac57d9426770dc24a2c1d20cb00000e00000001bc0000009082d76487e6d930f670dd8294a3ff896e675b59871ddad13511d9452de5b45ffb84f14b9b13c30aa0a0e7a2e6c9104db67fabfefeb577d70b31b3c815903784d22857c61d6fdfb68b8ffb698d19b8b2573005f3cc1d8fc31d65e44e50ab9e5215e3afaac2f83077deea42491ceeb354be10fb78ba40256771f5bc72402ac5d4b95714b5cf2648c85e3e10ae89b7b9f90000000090bb455f351a243a89123ce2b0a85fc2b0d711f7cc0f2292d0d2a1244429b2c3a982fb23fcd8deddfca3feb7ff27f394eb53b99309a1c510314edfdc9df4c2fc3db95ea67739c2ebee9989354c7252b6271b6ca0c3f3fd42e89c43684e31a94631dd0c57d049f8447cea033c05ac25cd021cab485baf707fcbcabb7210161ed846e3ba40efa3fb4cbe746a1d5b446cc7be000000904a9c85c97e0d4c935ebc0fda0fd70e4fe7ba903bfe904e6b71be94b512c7d61c05945d369e0a354935013d1840c07e272f4f967e9da05693169c04a01d9c677b30e2c399e57415cd33f4703be42ce44d093d5355d2f3cd6545583eb4b716865564986ec13253b5d93bc537a0d8aef806031481898708631063bfbd047cc701e354bff464bbd7d936bb53e73f234f8a00000001bc0000009014068b8ada80fa69e69589488779f7c44a6996e8ac9b6d6a317eb1693f1d4e094e11b24717028489585be7ab499453c89138fadaf6ab6f0f571dfaff11355fb748cf3d829b36c5b972c698d2bca1d7c02b9acc9c15ff9e5666d7b37e627e590a4d8f1bb24109c7b44936ef647a72b4921b2fa2bfaf9714a3e51999d1e590dfc46ead80c91cebe32784ab654874f9ccb200000090139f1dd54b92b5547d2c96e6018cfc3db4cd7859058e4d041123221c165a25ee3bc757ebc93503777b5d42f01eae0869fca95ee005728e2613bc7c94d734bb49a1c349a8815b3f4161ade33090ac86b12431f06f0dde369efdbda3de50c7ba09a345e652984fe5bc561a96e4a9f53997163bd7f642a409dad474891b58100829aa3663d048dc8cac3598e9525044266c00000090cf0c8c78576cd3295e717b4e5f05a419b3b005ec6731ee5c9d2bf97aac15c9ad3e3d2a56da176bf638374539c02ab70fd4db47cf3d89747cc938490aca465a78421b773c7459e71210c785c9a5811cde2ad310b81aba16885cb3b5e0d976536f92dca42cd55128833f6488e8094141150ba86c4bd92381553af54a040a82e41ea12c9549f51975d49db10fdbed1e6b92000001bc00000090869ad8cac952854ed14124129718d6e67d0aef1434bc70a6f523c781db164fdeaf9ef954b4b994923752445d704b459614eb332b76cb1f4401ad3d9a92773640236b9c96bd671fd81e3ac76cddc49e5727524cc35190286d82784dafa03e4f5690d6ddb5bcd7de9cd0429b924959c327049ff8df11b688432454877b5300f2ccb1d2c4166845b4bfdbb1e8015088985c00000090764b4562eda203759b8b174aebe4238efa1cf2a3ec1768ef3ef7d929a31eda380ae130c452455f036b34ecffab440be6e961241c12d24fcf15ba47756302ae12270ca1cb3c6e2a23d21c280fba5bb5c20a89a3deb175ddc55662a85f0941034841b81e9573af1355bfb08f161c4a886209dde8bfc2be93463163c57f7fbf92d7817304992ec94aedfcd43c744db0f66700000090435820bd150fc3779fccdb6cacac156f434bc441728b17ae0eb9fb9bbadb141cd24f050f1a5311375c82114434ee817c375195e929d4411ac94b0e5f7022e2a09e37b8dade0019025709e19cc035a3100266e6e0900c661e8db4e2e70ab508242eb478fc07f5f0e9983d1c3aedcb5431055c9543450fe8915345472673b7afc4f61e856770030f0a00c3587d3400e4c5000001bc000000905cd2b1954b0b81b07042b62e868d1f803fa824c21c24f9ff64b38a74c6e023aab51893ed2f1919cdfdfef53c741bd7a3d97d4cfaff2bf9a4776a18ecf5c94972aff3b1373ba6fc9ab6855ac00a49584f15c065b44f611fcfe69a1a06e1b2e833e8a8ab6f2f3febde83a3f02e263c266b00062b01f9222887fce55e9c2f5e35f024e566da0f0edeebf252f5a6aa30e28300000090077def0c3f50b0b47c9eb48a6b9708044029c535f4b742f75df046315c8b526751863017e899cad6696ecbe1fb3fefb7490af911029372b3a5dd8e04ecc073264d1ae633b48619177d4b1db17ddb7ebc016982aceb8e234406b2609f32c96088b591224ecd84ac0b49eb013bff1d8d5b291f671a1d584d9a5fc1fc86c27358cc1e63a52bf6e2e3087ba362b90a8a092a000000907b5ad8c10d405a4b6d0dc2bceefc087363be47cc13fe5b70d847ece64c9b8fa6c9d2e2d87f0d3452f6be6e1b5195088a732c38f1c127b18ef1c3888e6dda60fe73d4701f6763e764b0fc9bc984c9ec3a1f30df8ce2d7da272b7a20478311e5cdb3d3e2cf782ccfc8fe24c004decb2a7426e6d5cf19e5721f943de5c6f775c7e3a3257ce201bad3a1e279c18e56a0c23c000001bc00000090758e63051bbb20bfa45a1d6f0cba49e3d77c527acc4c969b17681b95330155439f1461314934ed0a76e838cbe30c38ff040dd1b5c786649b5a517ee3fd2cf0526aaa05c171d6fcdd75625d816836abd50f9d14c4b76b00a4e4ec57f3d934d31ed81ef8796c250614fafef5e5110d4b3210bbd4ca38ef2d2a82d835c158e7b419282a6139393e4bd502799986a28f216600000090f0822b26f5f8593d654f9377df02f4d66fc3109e08c6972cd2d0b9a4502361768fc07cd12c3f7d9e01237a31e7eae18227f1330fbff7f21ab933d81787818fe2bb8c1c79aeed32572534bad3a38aa22e12b85f9e9561af15d644b48f3ba832886868a01ccbc1298bd746adc9f213bd0d29ca03ea706ebd3cd5265fcc4d06491974320235bbc43d71208378f376b4fec400000090ab54fe26c2aea2182626d92a98a27670005516c8043202d1802da90008c2cbd61b9d0196b091be8d8605189bbbc5539dcbc4624f4058cb1404091a0437c1870eb160b02a3e57857e850a1c28e34555e21bd4f7fe7cdecb230dd935647c8c3d446b57e65d7f67b2b208953ef2367734380a15526b29102a6aa922a3525d471403a51ac6eb08e1fdfd8679549128879a69000001bc000000905cc031b130a4e6e45e8ce9d099c29f465014f2bc45a18f4dcf79f0ddcfc715db888f9975780c5a716611e8f25b66fb2f9a7a312a4953b9c1f2d3b63f38c5d5c8353de7033cf40b691310617c130142542f59730adba1d58ba4a553df2a009de247673bbbdbd72182e094ae020b503cac044fca8434a01a10648174a643a28b7105c34b2e7e55115b1c63960cb0a79800000000901de3bfad3720f2c15f008e4a346d27ac6812c0af159d93142eef63722a1451bd0bc02c635ccb07d4fdaa341922ebb11628a53fac21606763dfbb7f42448a042973009752036499cf913554f3e7ff82bb0bc082e28ef31fb2ff685c7a6bfeff67e5863ab2aeaf0a5e62f95e36c42a50b70817798e1089cd140dc0a6c817a9c4294925e8cf6af4977fef8a27bfe3774e74000000909d3eb8dda8a7ca6c61442bb4314d7bdd4be33ff477a9cee2db9373648e3d45a3f19ecf8e875caa25358b24db34795ebbd20481ee4eba712572ee7b88d8b345b0c9b6f7795ebcc246c601aad9eea60ceb131b7cbd50c6abccf73ce8dc958b52230df1916828896785b5f9f2a4b994fc0b20b752bc028fd96f880ff96d0239dca3f27c2790a1efb3748db4beecbe9ecf40000001bc00000090abb3bd5e78230fbbdef5e44ff963d2ee5bb5481807d8ab24468db6c0b34afe6191a513d9fd3ce22327464d7d8f1df5d5f1d28a8c8dea8b121aceb6bb693b4b7c92f626038d83f7c850f8e24ca8f2baa30f728e519ff0afcfe0142b8b6c0a26853fbb3ed9a852b5ab5ba7c5ffc0fe2d210c595d34d74ca38dd455f4264e64c9a5bf10fd8fb6d04ea46f7c0fafa6fb726600000090c6058b3d921006949f8ea3925de7a5272a5d0f8b9623ff4d648896e377da63ce69d0107a9c9d5e6cf286859699e32997120d4365e8cad02ce48de0b7a6e1036bf7488f54a2e7ff4cb1c8f904725f03342891db41bb8bee35200212f942c1e2d891b112c9e356328e68101c24c255ab4a1ddfe14afa6679960eda155b3f4e748fba771b4cd4cfec51b13ab41a01441be800000090407a6f231eebc95b1fb372695287319677ad9c009c273b06c3bf083d312b38a478d64ba7502b00644d1300362d7b102b6361f4e79b42e100ca70226c16da7a3d8651cb4c6a5810b137e439496c6b88d00963eaba8e28200569e81317825b7680479af46afc14cc4835dcfd5f1bd1f1ce095018666da971e6824e9c161135939f8260f4869cfcb42321b5952a97845894000001bc000000902a2093271e5d9e426ca48258777ea1c9d9f4d529e8f66f017ab2f7606fe17873efaab862e6cdfe6bdb06b568546371bd19cc9deda883327fc3bb47b5051c564924b2324633d7d354922fc46b8d88fa9711d7d02d5026e036a46a8e15842b0000cf357fe04e93407514976c6e24fc77381537bb76946a6f83207d426683daf202a0dc88370208c44c039b9223a27ed54d00000090f3af40d79ef111be5c885f6e4ce6a5f39aab3dba6721b387f7c0e7ec51f04e0c52219bafe83d29ef4977936827f17ea5c7db377184f3c07f0964e02bea83b1bd4b5aed48e755b48c46aabb0e802e431f0dd313d1c7f55d62d6996e3865770291774110087ef643ad13ee2b0fc80ee30f29ba6c2563a69f4c62e092346f03b20dac17b845455065432cb0f86f4e8fed4d00000090e2feb74514cbc15cbbd4960c3c31c2c8b89f658742235547af39388a2dd4d1b8383cc3a59bfec0ae7416275726dbc85967b1bd89eb45167b0a983558f057c5b6cd12d793661c9763c4aee5f086523d951413571b25824c9dc659ee1dd0390a717306a72fd4372d07bc9bf00fe6a092fb2175106fb6df9581444b794fd86dcffe7b79b82256bf3ced5f46ed9391431f7b00000e00000001bc00000090d25e818b83b533e096a3defeb73fadfba836517df1b920df53e966d82e384cd71fcba7799a3eb1b3e89eee9d99983b3eee97a525e8ed6722ab1113178d97cbef9b71de73a4db75571bb8a0750d1379ab2b674cd571fa1cffdba43f4c3c087dccf894f758be2877070da819381290f7dc0b3fb34c35fe2dc4ac82a9b758d764bfd171578ff07f263de4bf0668fb99faa000000090c910ad0b7cb33399478c81403d65f247bd70bc2de4cd1a400cb789a080a5814050ca36bcda892be9191fe589893aa3cf769c45d17dc9bb2ae20c6c6e8ad4410be0b47c87a4ae9a4d254d6c9454bd39f80acc01d59dcb13bade04106012e4364de822e00028f194bc9445e678b5051d02001ea661773999576ecf326e520e9490f79cafadd121c7de3486ce095923b21300000090ee0f1163ee24e3082804800407605a7ff98a7e3fff5eb530931ca1c29bb90a2127e46c103ed2ba423f55819d97e3b8b7ae7c98b9246c3fa0edcee4f7f4dc752c7861629d7bfaed003b609edfa779b8c80dffadec2e3a8e1fb967d32760a160bec97c15c640303316887a3f4fc927cdc90129f6f2658826ab3281a930ab23726a41699ef2a9b9ada3616f9a09e330e43f000001bc00000090c162bc6a922d0a9677d94e12ef9d0fe3f23f904c40a302ae96691c70abda3f4bad695623640fee23a35e536ddeca6a424c4a910ab4f06566ab833e65b2a56567b118f2dba34dc1639d242349e1e26ebb008681d4393efc63b2fc03a5c9c349740248057f2e7e2954e143baf97d7fc28d2414463f0ccda16435554fc0b96ddec693f64631f8de020a860e823c03e4a95f000000901a4c06bc51205497c73afc915e848da896ccb3e5ba6d0a01e22ab7e90d7ec9e359b99944e6cef34eb776a36f8bfc89a937c00dda7aa3292e877bd2b0949055f224c995a4e3f36c21da9d5336d43b43d512e2fe707d0597dcb3f61dcbe5ace1856adb5735905df6290a1e97e7b3f56f68160afa94767c419399635df90ac7630be9ca9f2be7a08d47a796433e2fe69d0500000090e971760c54c672a7b46b18e36bb1f53e4458e05f8e8e831775a41da37fdc11b57ffe7a5b1cca585f1af6ee11ae31927aaa30305976134acc7686b180bc94f0669ac4536c2f1bd42e988fe2ab15206e411ab8eaf7bd290eedd0aa07d3a96c31f6f59a43e73a17ec768a58765db5cfb4e21a0b1c6ccbc23701ac6fe4e5bade56d8d185c19055e290f091bb8a83d7a103d0000001bc0000009064d04bc457031d3da99682e91f14951b019cee11f426459c1e0bd3a6cb760ad8f6990029ddc57c255ebf32f0b66a9b4861702c4d62af67177a3ce64185a938d80a000ac15fcf090ac0d353635b3b69700e88eae07b1cf387db29491ea0b26bdfddfe728e5742b16707cb9c3cecd374230ade489c5f5714a04fb6077eb065322cba1029c6cba5d519931cc6869b2a613a00000090607f54712a73cf264d806c1db0440bc36dfcdf33a637efbfa41ce7a184e1837cccb43a5ac09872684f960448c6176eb614f0b9332e71d654edcb400dfd823e026abecdd096e445294510c7ffa77e52b21063632c55f7b907fd2dad33e1008f18c18fea3240507d4438e52a59f873a50e0e6840de615959b9dfe9228457bf09db81b97714d1b9e378e23b16179a7aaffb000000905713c015fab8d31dfb3cce41c788026931fe246f12b4c6c52c039006225596edf9ae9e3f9ecb3ae1462c12b431c7451437de202ceaf85cd58749077fed1d2a1dd41aa4a8072e304084c64dd8f04033f7173882fbcf5dd1ed380f3a0b6cc2ae99c7e1ed3d3bc625e9f881678a77cef7762cf6029df8ac6d0ad629c871e7b2a5cbae474c1e3ec458f61a982a3ed305b4c0000001bc00000090c74e13893e14c051d1c4b0e63d962d6790b8d5b3221254396ce134865a88d2a78ab9462e03635c6f12246dda72a5daffd7e47302b4da183fffb6c6e416edf2d45759e90bea5d320dbf3848a2ddb921c20109c2c82f61d2d57d00d9e6b63d5d6f6191a71492d121ce32fabb01f1892e061403e7c92390f2f321d582fb543b6252fbd6bcd4c81fe99f6970a6bd2219b11e00000090f465624b9784a4a376a2bd668f0654e08538e17bcdd05dfd97f4a1e20541dcb5bcdc377794d0fa79d6a2e1734f1271dd6294473ac6396c21f93be03196931cf71fd9c6e2910465b909c91f14437e9bc92586d6a20aa42e5b0e2bfdb3a9dc831ed60f0901977a7a572bf9719164bf265616a1ef37492fa6624392a171f816c33cf8a6516f966f3efe7cb1b343dd4828f3000000908f18852bed214009ed57daf66d3d85ea2eadb39cb1fb37ce940841774fe966a3ea108b0d39c66bb821186fcb321582e69bdfe18e4a36fb684635060a0992dde083c2b0848a99af0c12421c13bb23a8c401092f5a8571708d7096255112c28c544f33e9dac7234da2cd1e84d6f632134e101487ba4bbfe2556902c61e2a569409e749997aba4b89e8fd7af8285e556bf9000001bc0000009011239b4be51760bd69b2219fb45593d6fc0fcb5559b9fe6ec804297b700a677591419ea725d3f521630ad34909b40eb7774927b6b7a5be63c95cac83c04100f07355ac23aa1dd18add27e82fb9abc8412f8b8117f97f579fd48fe738ffb520ab784e721a28b16acd13d9899f9fe9140c29b379f0b1e8f4f632f3b8ed59adea573af784e12d894cd8343d8a527547d744000000905ad7963a5a5863511f5bc0734bf79941f50f2c71cd0082bd957649599719396cb7ed0f6e63ed1b18f541ddcac71ca4e6d4fd1a802acadea6772e76fadc323f7a74c710bcfbd26fa6ef55f6b17d8a187f034e8b77a4ef4467264ae76ee333bd8d3c2de0de95b7a837dd5efde225c3892e2cfdb16f38a7b6430f047a1a3d14a1b25345dcb3b5470676a8eb6b719b555cb000000090f8e203401a6080ec384e8eda1d3f804aeca07981eba58134ed2cff57729e418586df1fa8efa3096d090a219ae521491c878c4247b0ad36c6c11b3d424b2aede8b97b27bbf497c86b2b93239793aac9d61a9c91fdd02a53fdf50cb8a6352f54fa2cf7024b6cc68d57fee4b95fd8e8d15c276a66b4c0111673dc1bb105ab2ca5813cfc9ead215177cdc3d78731b101a39a000001bc000000907427eefc8c32594e8c7a42ab96bb1fe860ea78fb6146bc1d2a73a1e8ff9c6991acc4d9a463ef73ff781c61368fb7aae00631940143d0d53203189392d82b26a576728336a42fe55bafc656d729212b9d07efaaf20bad1e66200b7b80b29c094c858128ea68f3ab9d3885a207417ac1700a223c722d62b480ad3d1793f05579691edabd5f0d873104b257245ee9083c870000009036f06594a53af8ffd4c69460aa230c8f42cfc808e661b74954492215d41af00a7904d4b103347162c8e73762f27bc659fbcdfb35dafd2ecb3d1adae51091de4f455b086b8239ee229c60fdff690df1620d2aaf0f30c9975c519119112bbefadc8123c10f6b1a9c49c4debb0bd7df203114490acdf70dd8dd6f8583dfd250e869a3035549607fc847b663de3b0aeabd8400000090bd0c1f7e5dab2d0cfa161cc54823cfd5f67bae6dc39ad643a094f7172768f234c760fa9d1610c894d255eb0c773abfc023a46b2a8c8eb1f889bf14303c184e065430426e862b1cc1147d2d12cca898f9100dc0c65470adccc7810f657ee6958c952c9a9df0630d717d0281e7a94d4a4b156fe400fbb4fb617ad65dea278490af66f573cb1f720c1ad6f131dc61db2c03000001bc00000090e668492f7d870f241143adc81620eb1174ea8cce9e28ae6e14f1b26864eb39fc4bb4870a0e53b9d244a0743c8ba9d7c8b7399293c41d3b4b6f5ccf0500b2d328ea2e95147f22c1e2477b547d4fb60951140f90f1987a319217467ab516b7b125b4a8cdcc414527263686e37fda2c2dd92c9eb14fe690ab3846f47f6c5558d4ef7ff71e65a1fca7d93b14868c7ef7decb000000909602d909cb30ba815ad08cedb8e5384092dcdacc76dffd3913f78076539cb24c63bd541d0365c94d523a3b999a8a22719719537dd7b5db9e2f9fc4f0a0eec725be2d0e3fbf03a27c9843eb7d43b376bc03f00892cd118a31db431634c3c88bf2af5d33021a2ae9f4f22350398900bbd30841f4f269178d18bf284f8400da53abffa6ef966954397133b84a7e4c4f60900000009044c029f4795c4eee24224ad795237e3e09e2a8ea64e27f5bdbcdbf32883355a5956a96a7f72bc092991dc90d1edbbeee20aee7a1eafeb032627dfee5cdfd9cd0443bb21ea956927600ee6f7e3451c962013baa93ea18c786700354bec36b38343c9bb35dd239dc06466f515b0470c5811d3616246a801b6f2963b965625d955fc87a3d9fb4ed8e1552b38e1aee41b8db000001bc000000900b3bc15271008bd69ba48695c6e6a808a21cd66b6eb861453158751d9eab45b78a1b8f11ab3c5d989ee68b8f3e1f51e1da4f19e3546341ba88d19665da99d06c618d0ef988f558e281a3c97c6c04bde50479198ec6735b58f738a2cab5f45950b770cb5f9d34ea4099872464ff342fea2865375e7e7bbbe5acd490670b759f74d4c66304543a5d0621bd345dd6b9a09b000000906450d9162ac8175e4061c9266bba9ab6593b92b04b863aa0a08c08be535ddf2993e2d2b541701b62f79954e26e9b832aa246566e55e3ee6b1af856484d659c4ea486f0ccf6cf564260fe2bcd2a6a804d2e49472e9871afe13083a141b541dfd434904556033db3806322f7bd5aa3cc5b1a4dc9311ea57e048418d1c36a8fb231bd9821303d29d30a29cc0389d5474ea60000009022988ca796fc0b91f78b4f4535869997b9017a5d6bb9bab63ec708ec270ec6afae9799c358f478dca2b537239a35e9f78aa260e764beb9d361592a5df720dac67916fd799e37bb36d93e0699df5b07b808dccab7c57bceb538a337bcc68cc8b536f2f8b50566acada0b67ea7eb632d54165bf73805460e1b5bb24200bea8ed8dc15f308b233678f053180ca8bc9996bd00000e00000001bc000000904fc89fc6be0e30f05d6f9f1f86ced7feaf57415a3edd0e487c271d504e0a6d10eaea3c02c5733ba7556e33dc3adc695899a576ae2aa5579d41bfd701f91a479cd72e191d26b55bf6fbb032e3b33bc4842a0aa44cebdefaa8579aff992dc220a3a0a32f84f1ef0f3cbe62b37f413ff8441b4e857d847d8560416e3c8394f9969ae23d8b82e3f86ad33359f5f425f5c7ac00000090a37467afea6c4cc97ee51691ef457d7492c7ed5a24502da13c29ef84ec446b88a3c7bd5e6fc66804208adb01299dbe84a9a1b6cbd17bef87fbd0fe0e1808f7e919dd9703e551951b52ca192d9cffff3317a33dc570b5e04f5aba1d43b2e1997ac5f000e28213956be344a50c4c2990d81197a51d8df67a8c9014672c8efaa8507e8d790953cc222a530daf446fd8c94d00000090ed2da66258960faee567fca3f48339c58fc1849f9ed6084a338ad10c69a03b3d5c8528b56dcb54ad2ff53b9e8de77c73d5278ba02a607d8687b94b439b705f798a8f5af5826be2768623bfbaa53fc330046cd30f364e74e2e1afca74a76e4958172cd3f48806044001939affd2cf387f2d21abaa6b077c4818bfe38178995c90021b3861963ce32c34441ab0c2711d53000001bc000000905778f813c2556620961d546a7fdf739f69a15c0f3d27e12a640b7b8e2450ba0c27bffa2ec747b18a73dec69e8fcdf2847b9536fbf843e13a3f2bc495b3f4e036a1f6e52d7d5de6ed92990db981383d792cd6ec169d75d02d70e427aded56ac741223ff81866f4cc71ff0dbe79189d42c108e7e77f8c6845752e5f92e3dfe9b0142c1bc367b7fc03849e74b4169034bfc000000902053096a3ac009b9625b26d351821fe95f33c92111c691e9f526b5441e63a51a7a56bc43a07d6a8d411968ce7f8cbd7071b4392cb5b8a578172dce794ba5022d0eb31706de647545e373f6ee847c0c1c1c542de88666b01e90f664188ca9aadb0d26958d6071b96488ee11ef7c4756b3223d713a0c0e006f4f7c4c5c90c648666f962e245b7c6bc249193cb6af0bb95f00000090d70e906e51410fa1baa9d2b96e43f8a3b88e3571595cd86413376e1b70eab33d3b6b4a2b37842c653e6a7f40d811eee11ee842a0417f0d1f98e2dfee81d9b0fb9ccd0d94c96c09c419e9485012d8e20c0c6a123eb6e1664a2fe3357bdd09b53bf71102b0014877ec5290018d9b3291ab14fe9217b28dad3f0a5ba42aba7001225de17a38be745d4dfee261d3fd70be02000001bc000000901a8a8b3a10b4ef755a584850b202ae137405e8b021d75f806e660d9f747f2ff22cf6e45472b475d431829838c2b28e59361b4c98efb3180cfb7bb9fe638fbef23531160fa1946aef0d243ddfdf8fd66105e05bc9bdccd6fa6e5abba6fbb161859a073bc4eb89dd1f89b7a9879f1bf60a08a4d3be53e4bab4a27bf94e67ef11eea454177537748f0dc2d0029a09cfce9a00000090458256074deb2432ebccca8774904b3d1f2ee4624ae1eb16b0650324c6e055247a0b7630c353507cd8778c19a74981019d8f07f700aa03cff73ffb9bbe2579ecfaf28a8b457c8ddd0dcb7cb821d2bc6b1f8c99301801c3cca6cce6c27d9b451fef4f66221f6fa7c97e53d41e09e2680228643905b2ef882a09f0b77ce6e15bb898ad015b4f7ca5798b11ecb5be57d81a000000901bd4801913d9124efe31cad632fa74842d90821b2fe9f8fec40586e634d8bfdd3b8bac35675795d5adba61418295439168e7df438eb9ef80cc0f394b49e3297c8b4763fb0e7fc473fbf48a8a58e580021c8857152729f39dcf184443da12567a8ebc9b08030d1b9bf19275d6dec49ad71e75202c608f21a387d18f20c5f97572ac8905d1cb373088ce1175b144fbbff7000001bc00000090cc857f9a85db1c472f109527d0abdf1eff9bcf0e020763f0f6dfcb45dfd089ee1a588e1625c0938210a0947cdf78e983dc0c76f58dbba18245df17d4139802530fbd43cdff064d771c411328ed27f6b314b5f0df2516820e61532d5752fee09a6a46d2dc6d851eebacb495e7522de8b2203583f680d03c44ec9b37ea8ce5f8562466e0d19d222240dd728561f7d5c64e000000903babe76f53fdf6bd620f7ce82713adc6390d32939d113075daf95374cf07964c3a6fb30975853f14cc02fb654326c397e560b3d93c56f286572a9221257030b55369b406d752c06901aa937b8a43ffc90fc03fe346168e874dfb5c5b871bac5b2f6ee285e71c7be70d666e630a5f8fc605f87b550eb6b634d98821aa218263eac28c1aae4bff00bee6fac0ba87b3a5fe0000009044ef97d041bb817cf165c54bdfceafe5b3e375456be5a60a20ebf4c0ebc775d19e3b6a05602fe0702205ac3bdad9fee5733dec31985a830d52d934d80f4c26de543ebbc35ce43f58d7effad1a5e2f1632fbdd7f09de729fbcd9c1e420234edc3e11a9fe07bacd69c9bbfbeb95b2926eb109265132a50e27802b43af6ea5007e60c18f2b9f196982942336596486d7b08000001bc0000009078caf7c571dbed7201223e0edf3a9df03b5a286408591b32aaa538b5183e2811ca60a01da9625a016598952794377029c3577b9c5150612a92fc18c8e278e9c3ff7e831c66027ba31121f404c6cc34680f705e4cc64f09e1b5677d8239852b252d5beb89f9b831ab52164f268f5563de26a79d31cf827cc8d665e00f9136de728218f6c52a27ffafc4230b18dd42ccc30000009000811d22230c9c813d548215837b76afeb757179f8353d6907a6651c52d93a20deb6397944d199ffd1f2fd09002f8ee736c8823b748147db1a3182eebe82b840efb49cd9dcf389883e7adb67130065a209457e1a541ae4169fc17c1da29999e55f62143ccb007e6d34dd718321b61d28280ba790996b51f19e7a9697e6032f0c999e9777f6fb1ece70904f4a5f2b776200000090fe245eda1c2973b1f88513a37daacb8d5f35f35893dd5eb250d1442ffd0ab34d9c41dd3cfe6a7926ff1ce27988b8609ffa0c8de6dc9baebd017b7319fbe9abd7f4227dc04aba4d161f31274bcd20193f20fc7cfe85e4b4bb5a724aef57f265c62d737844a517823404a13148abcbec4f08dbb0bfca4e69efd460fec8558024078cdfbc05a42bcd9bf5e971fdefd08d54000001bc000000900bd4a31bbaf363cf3fa57aca5f04adae8f5213a7694b99c466d3fd41fa6ff4935fd74b4ea26ddaa049ce4361475eb92ada4ea3a828da1e80c29eb7ac684239088ead4a38e2271ab5e719612e80f3a25426580088f7d3501ad3876a82b672f5908cc84d06322e5dc6b244bd5bba1b95fd16dd281ae9e19ea36ce6c401f1575cc588b83e498386a711db916626da44415700000090f0dcb0f94e77f9d78ac41eeb40a50a955b4109bbe410ff70224b742f3fe1254447aa7386f653bc98610a67a95ce8919f78514c4a4bf00097084f0cf3d7c1d2d33122b5722bcca75484ab7952fd55e5ba2a20b78242c1e4d2af3333d8cf40e73151e0946821ce53efa736b9a3c22c6a2e21ae0d781bb4d13cde7018868a29285e9fd659bfdb9149e6296addcb396d407700000090ef341d88ea4e7fd9fe6e4a22e4d5dc505d065110899400bcf7cc54766a7127d2c48e47d156d6cb12d20cd0314d9544be558999261a88f269ab19e5ca7270380658bd36a443c55f097783c769c53c6f4016515b5ab04e4bcdb7f6c4cf920e722ae83ae986a67eb316f3114db6b8af057c28659cdff4c0f7597c43c1a80b453d6dd57ce6970ff28a5277998451724f3f7e000001bc00000090a865c2a5ef808bf3a41075b24637dedb1b5e14a0175b6524bf7e6dea4a73bac95984aad6571e030ade342508e58288746e74ccef9a41db44feb83e74c6bc920a2cef3a46eb8e4699019f6b006b5715bd0fb7711ad7933cbcfea5081657135e6faa64852810ade19b319163c1f7bc5a52120cd34e23191db2caf0e3147e4620adbd9c65bb19f60850cbe2bb27b3226fa00000009040a53797ae7569bde81f43f32b91e826343bc0f14316c46c3a767c9a76f3c6f18a5f43883aab511608ed0def297a253745ebc8efcde6f17aad8b894bb8f2c56bb7a0311b86f7a77acf1d5905f1391aef189601ada92d92ee4831fd2f3f6587ab231751c127d25a790e71caadc150f9fe2da2329b5993f4557c85702e1d3f76350008198b0a53e5659b385013256521bc000000908359cabe7b56b8b199554d07c08ac7780ad87048b1c8517a32fc474dc2d77203ec99a1eba9c192a238479e651e0b5b822f750b92523e7f3cb0265a0ddc5adc0c52839067eae0ee372bd1077bb528a5d81e3728b0d47ecd7e359e89144b1ce2e11da0363cbec6d502ce996791d87876311714c6383edc8595bf0fb0ab115f8265dd47c0f13b2d277237fca8c303c25cd1000001bc0000009014d50b10091b00692c84ca9d89b378281586b784b97e31c635ee2f240f7fbfda52caa18d2ed45b30d8c57b9bdf0e90c17cfbf7cfd766fb6ef05cc6b0e9536010dc1f3c570a1e805fe295077a49074d2629f8e3aa398ad0017f483cb595eac860c94524a59cd99f8d6100eaa2880c37af10d95ecff8e7662fd1675a6b699e368b2becb6381b60245955daaef513eda493000000902fe053e6aebc719b33dc8f0484d6ae3b36da92f490fac91bc44457b10a10f05880ccdd4a02ad43595b08769bfd36d6c8ca6b56ddd3639fee1891606c98ef93aa4174ea438c200f742b7b9cdf0eab75f22086c2b7e9c56a469f8fe4778281ae5dcacfcff7c5e928d12b7286346e50994d1a0f76ef0d2ffd1b281aad6cd3dcbbe8a0ff597104cefc4861e35a8dbabe9ed100000090b9e43908601821a6c6af1e8f68f955a0222223622c949747ca6258e843759a02031bfe8181c7354bb6e4cffc40feb6b0ae8ac4c930727f95c3dd1255f72aecfc7f0145cbda6958e8943722c88cdc172d2ab4e685c0f94fe29a92d8eca001d07945fa654f115d67a6ad1bd9a9d11bc8e02b6764d5427b15702eba437a7379d05a34ba6353af0b3c9eda58949a5d744c75000033a000000ce40000012800000090d1267be4f9d271fef7ef72206cd0e9ea08c2a867ea83347a247a3db18c95a3de4d5d19b44a8847af1994aec028371d91817ea93be421bc88de0f7b9ae628440b5a401cd7fef4bdf68ec9cefdf5a61c43305a51e1aa4cc53cecaefad9c8627ef285ab0a648361206ad649249a976fae7814f39800949bef3ed19e7d9b21eb2c673ea392624f1d670d20f8d9065f201217000000902645822c672907e4d8c0829357baac264aefb6b4308489fe113b1ff1ab965e34ef829446287b3002bab3bafaa32ef13e2eafabcc5801bb482d5bd79d5df0ccb9df3ebd126dcfff9d99499f3b22ce9003016efe2dd628279f15a73a50ca7734617b45328cff2ed111388be15bb328b15a012c4e23c527c16343d5f1aa009ce9ebeed9d4d9953a56a5bed7e5d50e9ecac600000128000000903ec8e194dc39e13100ae37743d4261517845da492d394d40d0cc71520111f86e5a1e2f7c1873ba53a8ad917adcf7bd893d82168c00e6317d2aaffe02edb038e3a91cf667cacc0356411f24eebf401e11148eef7900cd61c234127c9938bd1368f2b794fc12e58707e1882cc3f4d21a0c1df957e9bc5b63c528b707f685dddbfdf84643d155b06eafadf2ac436e5fe997000000902605a31b9297ce4f4e026cd62b1f99e8ebee58d4275eb401f67d9d109b2b8b925a942f34d80a0844c74542fad7d28a0c01483f9a26311961ee99e574f7a03781d749d68e46d2634ee3f2f86cda4b9d5c080a3c309d16833d104081e3186f25e8c36fbff25cea36baec6d85359ba8c5ff282403cb327daf376cd0a757807ef376475b9aa8c5b4afd5ee35af3908066a530000012800000090f01ed56f5ce1b851ea8242e8f2b54b3a470b33bef4a3f98e90e57a1efa1d066af51ed76a646cb0569643f75e371ddde0e4bac9f097f48ebeee3408a9e1524cbdaf08400cb29cf8baf0f1c495c040075526e507f551aa7247610b4374115a9cc36d55d17cc2513f34b294b6b57ebb63f811df0b8c164061b559447fea1bbbee0cde3c15837b4866984ae8e1cf7e91848000000090f48beedcc6a7a73c5dbe0f65a08901e8912e17b53430708ec55f8ebd94ef63cdd8d1ac2ff75c07849e92fa721d62c429769b2f9735c357a275929093d05211c63b36b72c38139554d705aa77ba77153c1810eb74a7055565d2b38898c1c7f68b2b6ff3a892051417bb67677dcb606d80210bcc0e3dcdf034dd98cae6b17708ad15c843e1625300b780d7dec624a6158e0000012800000090e3d8bbf1a03a6ec99d18debe60451df0f74b08613bc7df42072ffc0c63658e3f7a4a4ee218d29f7dee54fb3743b47a9a22a62067a43992ecde88fd0d5a4363d620c54a4f8794f23412e64d8a579d8e2614d2d47afc37c92f2b455c010d741cd477a38f3c53d9fc2a5ef75539347954c30dc480c9350557bd2ccc1d6ec3d93c917d0668cf00efbbd5ac9db2c69a35408e000000903490e166050c8c9a7ced51be3e57b99ae8d4de9e3ae3d7872d7cabfad63305c36e97214768219f502f11e081b6b1ecc4731c9d21e7857a48c39f700f2de1a1e690fdb2640bcd80de3495f5626d2624b81da3a8a2dc731da13a8f75335eb636aae5517433afbf8e02b1bfb63735eafd61122ade87e69376243405e78e1e3730cd0293ee37e4471eda1eed0f0c45c3842800000128000000909fd83cf44626806bbe7824895282b806c8aeda0f138dcd314cb32aefe75c2b692ee9113b1f9236e0789edb9ef55000d8ad3fc9610808e1f8ba10ec5c2066489f8891d029ca88be20c24625c68e66f39918b12237680f30254c3ecd75fbd881791255075b70bd58da59e9994242e2599617011050da58374af5bcb35f4cda80377a8a187dbd733ccf3a97e703dbcc5602000000902dc70eb32d4fb884d0b430b16c7ff97d5b88f35550034ed6841f85aa8dd2bf3b31e316b75c107bbeb05296995c4372b1808268a7e4f2e0f9624de9e95ecb47087753746334c65615578c9e9feebb3a51241fc894f0c95bae803c4f4fac8caf11447f290321247bf7761efa4e84d3453c16e0efd9024dde101546a4a4ef8e473e464a605b56613a3199ad3b629c042e880000012800000090b35df4a8e4fe3d9ba9a45a24b72bc3af314b174a2159cba62864c91c495848f8b11fce0c649922e5c957b88e4357965efe8f95eb96b290509b8dbdac4da7db9eb7f54116c9ab5367335037d89b946c5307f6f9e11fe03737543c46355427cb8c3d0253d78de7d89a97ee51b8a0d125350999bef16260798f2b1eec194a736ecf5c1d58e17ceb37bfb51e0c7396de39ef00000090f6b68d8dad58b1f726721ebfe0ad5547ee026f110e6fd2fdb139116ea2a3a3e808c682b2e43e47718e13d67502a9291b39c3796c3dc6c31b55ff7df469ba1408e1c1db38518a10e9a88235e430d1bcfc01c80d1f0ad3567bc6f3f36ee8242b44ef0b765a5130d8a4131b0759aa1ba3c32d20a24010618542cb216f00fda8b7186bba33dea148e9909b4d4114d273733e0000012800000090eba1cabbf010fc7c52c12227c7cc1bff001f549f020a7181c2b1ea71549f4e8c73c2a3b8a1ac6cfc09ed85ed820a479ec25d2f3e23d0f0807c9052827f4da196122928d3ddbace54cc179a5dc8a29799297e2a199d7074c84cc0696b822b40ccc1a1821fcec621ad646721d0914ec7932fe1b6ac2f70ea89c890f1261e55a09eb95eae781cb719f08c28c1be6e4117f400000090fbbd8ae5ed706962d244022184001121b2bed70fd7c5f24a77747014d9d118a13e8e3e83e5f0f613e51765e55b0cb9e2db954e9d3413b0453fc7166e69288cf6a775c7db07488b1e21fb2b24f1f3cb0023c61ac84d0fcd2b205765fcc3f9fba7bb5486441c07b1cd58ca4176cd410ac80899096c50546c8385b037b01abee2ad4b1fe28353e9713ccf291c29adfa392d0000012800000090f9a33174474e431d81d35dbdb9bffdac406b33d2c6f50ec30f40a501f9019fab188fae220ccc7a12de6ec060712c95add30a769ba5b4679125216799709c7b3fea4ad16b3b2f61beac2140a77bdb27d40cf50eac4c456057fce6aed3886a363443a56a4a4d5ef904d5d037831af022da01cb2f68f559ea4c571058cb175f2a5422f65301b7b24298916e2a7e5d8e8b4e0000009005dd3985388842b02e60a086ad305688dba8c73acaba8804464dd9b3650af21656d86f7dbbacbb344d6380351cf99f5298bef1cf20a917860cf962899c23274f05cde33a985834dd53eaf93aa6043fa72ca9f8ec3d4d394cdae9fffc49896a885c15c4efee1c3823c69f74cad0c19fd517babcc3125db46fc01a444e8725778eb0db0906db46fbd5cb4dbad9439716de00000128000000902bdab506bd3624299973bf33ae4fa16aba0e407b246e8061a437523b59b8bdac5d99d7dc63aa3d15b3c4bc7eaeef86469965d03ad3e9208d349d9f0fa987a789f309f0a847926337207b6f88479438b71c35b3c79aa2eadb871586be85ff3fad85f5c69b1ee4703889c555b242304ee7178997b71733c8f33fa78b9ea722e701ba79f0388c1f76acf7d5d777cde50d2f0000009048b5454d5350c10d5970abd7223e34b714bdbc791b4c65b14b58bae6a87959e9b8d2028cbab36e92b7d96c496613e1a4fffddb3296f28f28218231531aa50db7b5bcd04a24b200191498aa893862559922bd03d09dd727f797a75561ff4bc9ac01c0295aee978cc3487b08de3c5e77e028dc877f80f4baa2c748bf4e6b7fddc9af3c750691e88463670907dc89ae366a0000012800000090839be5d7c52676e753c8a94fc7012fee0c33e0ba824ef37cdf0e4ea1ba7d378161d29e54ea55823565c2fc5b91326b4a99a72ccd98595424e5751381143578bc2ef5f8fc5abfe87eda3951806f9f7ea20d2e867704f0c4f1a7458f33ff54764e2a64ce090b66e306b0f0a9e27f36e6a72828f812d9cbea202ce0ed288be99c5da3b8c032afa35c82906ed622f5a3603b0000009074878a57a2fbf52e6b1096fce33c7f83f2c7425ba6d150f48be26ac01966ca1f5b603a3d3bcca9f1524c4dfed85117c8b8ece60461d5974836189771a9fb700a44c92f648ebdd97770d1526fab8e5dc9301100a2a7804fedabd6d86f2fbbe46e3fe24603a00063db5b42c4848083a3580d1cb7b2386c037a8de0a9c6055ebe5edc17d18440ac6719ed98734f92ae5527000001280000009093e36780cca35dada87cabee15291ba8c3f3b51e28aa2b2f36f9a02f5a19eb21c6ac03f389843056a84b3fb4b2acc9f476266fb480fd7f99bf036d492324f168139db1e31dd27cdfb1b4e8dbf09185411c4de97982b74e636bdf6f7048c4cbf4d1b2149904cff0d5a187b3e3428485692df3c284b29771c96edbed7ac3a915c57377ebbdec271352157053c10369c2b0000000907c664c1d087d8642d85f3394f66f4bed378f77c1d9d7c128b164fec745a018176acb3c666635487d07ef39a9a7443cddfbe690dd2d90f249189a3621281c4d8cee6b8af4c22b18c6ed258b0cd1b5852128eea188949ab62e174d2a5e35ac77b2ecb10424b1d49a956eaae6d453e0843422e843b77ee88004fd697ce4ddfe4e032890c1021ac3d0b33b993d2cc260dadb00000ce400000128000000905998d03244f645698ff7cfc4dd1ba37cbd375b94a94005ad980a9ee1389965347b34b4732bacd868f2d46ba76059f07a9612b8841b00795d1899f4d9e35f14f628361a9d6db9d1cafe334768894eabce246ba1dac13af0fac1bda97683d7cb5789c83c8bca06e4797e2ed46bc518c3ca15d4bf801942721b74175d2034e86b3269d17d92ccf0ae1be0974c478678ccd9000000905d04d09462ee4c6e28988b59218779dc628362c3c8d61b0080506b506232c8dd8f5a8c914e19cc2734646ec283ef984d3a86bc15dbd8de783a4e17308e94db25428c59e05e9012c8b44da233efc49adc0c029e9962b7596fd6466cf39135c96e3aa7ca27556fcd2bb99a520e3468216b2a1294542a597a110476ed26bb8dcbb17162dc138d1b68aa5eb8ef962fc703f900000128000000903c8238f40ee0e3f9e925671432e84c067595931998373096731dd118da4f6acdb427febefa4ead8cc0b2757f651a35607ec45c65669983704f3c1c5696617db0a43dc3f6895691796b92d1586e2d62ac2783413610f60d5d6626eaec0cf5489b56a67fff21145d422bac59bc396dccf3025a8fa94d115c7c3a59681352149f1245f9703ebde50c5ede736cac50e802fb000000905e4e8b0e7d92d0db9288b2b0053965ac7f99b674c782135b7ad9ed8b2f444a70df394aef47fb8058895a0e1095154e2b7ab1783b5a3f0a39d0a497ba8d39bb2d35b812cd7da132646264393f75bb2a050ed19615dca0bfe3e31a947e1cff38a5648ad99b3148841c526abb8ef5130f6a0d1548c4d345bdc0e485e8f001927902345548007d66bc6040ff4d9c5d63b5ef0000012800000090490bd4103feca675238fe7fb4c16fc04b41f260da6ebcece76f632ba3f88c45c041e24553ce95a540d0fd48949d652bc7900b8c7a6eb8b2b687e00349bc9d832e0dd7cd4a4fb6dd73970b40e0156a9112de6af792a7d99bc6dcfd7a322f3ea87f4a5bea253e284ad2c26a523aeca62a32ef78b5c436a4e8dd5e6e12614d04e2cfe468a0ce89df5bb2638156ffbe85c5900000090c152b7aeaaf6f66ba3606d5272e2de83c2ec413ee7adf1c043500c433cf35527fb29f203028e547446779ed475dadb346b8b210c39de239685e9716aefe5d38655d9179c01d89100967ec7936bd59efe0be12e855ab54331d40fb17e7c2c4c4d0d93f3ee108c9cc9e871cf8019878d9517a9cb987489f85c9dbb343ae729094658d51a0c76ecc8f97f711e88aa09f25f0000012800000090ce845ee33b8828c450d0f2cf2e901790e918bf0c8d809e81113f1e829b219df0cee5fd00af7f89613a56b120115c72f98809c06cf525f4926f0c44d2d89916979f11100ea3adceade2c3fdcfd7902c8a203f3f68962dfcfd5d469c0f44b89113b35c8fbb3bd00f35e9c869325c6d56fa1d3a582441db19937f1131d6c57069293c0291c4c5497b62f9e253cd1fa17a3900000090dc2b6f7a95ac2f9b02608236b9d001c25d4bd46c1c299c6d2c5d888d4f6cda24fa0d7eeb717e173ee675f7f1f6a891a65c76d5137d5d8536525ef77268125445bd2a79a87e6dd03ad7fa682ecb6bdb1024cc7ef89dd5d28d3d83a0cfb8d6ac2c84823ce8d2b23da74ab19cb739352166002bb6a64ab8ba6219020940c1868aaf9098599b0536295a152d76376aae54490000012800000090382c4148126f8968b857162ec8fd930d573a41ae07df55b075fa4a90341342a75507d57fb3accd1b145f651562b68172a16d01822fd8fe19b8d74371c935229126d7a3cef7f0ef69c263389096ae3a9221e0676c9bd4d0604f00b6953347bf10af9bf823cad27dbc1f7356dd17fa9c0f12e5e2d085ddc1b4a345e9bffb549e5db1c045c210dbedb30dea67a2ddbb2bec000000905d60495979e9949a319ee7765f6d3f07956e97cb076538f3931c0f4572dfe7c2c9ac2afa11daf65b43b6aa44efd5e3b26672b3d0e3c714f5667fecbed230ef70b0f1c7cf6e739b3f35959a55c46423cf232f6fdd1fc069652903d19451c7870a33ce63d016a2ae702455b5e899f4483f02be42174f5af4eab43fb9c68a1473ed7a51e89c519da6a0073c96bb9cfbd4270000012800000090346bc85326b32dda7ce8f0212fbff1092a4141ae7452adc2c667782ed03aca9b9fefd2d5740b0dfb5919c2ab9a5d4a7ba4118797df233952f68458d346ac573406de9db783d5f3e97d911af1331508312056a292d09b43d071621a945152ad287b75c8a4d790c2e91561e04407be1aea0c81f8af7657704175e1b0aad580ba4564cd3d6ec6f36c55f5e74afeaa2855f800000090b77a26c6b8dd4c4dfe3aa1da8ea966522275687a8f7596662270fc760493b8fbf1e563fa0b307a00bf6e478fcc4eb3666369b67e5273afb4a02bf42374fa193fb0d0813fa243aeaba6d683d4049dd6422166b0ecdba3db4b79df7b0c1fc8a935aa7d48fb5a550fee0541e69d76015e63009ec5223365534bcbb376a2539e42bd129a9c457be332616dc5efaf44bd30aa000001280000009018aea5bc1ca8f0df49da8a42c192a4b8cc0aa96737fcb379804441c19b2a74e9320e84fddc1a23787216e5cf2909c0030145853cb165993dfd87cbc6d422ef21fb6cca7f7825a3f7b6adf36e06e6bb162b4eba544dc40b453b24b4fea13c643a8dbc0bae7729bf40cd78b9bebc4ac7b80495138415b64412bf67b0cdf88d7b4ae8798c4ede2fbf763deec962a29be47500000090142795b3ab49aa436c60b2a711f4c19339e4a3801a70876f143ebff42950fa11687fff7563af84d6f2a2b8c9313cc2f82818a201d4e258d979f61ad4b4ab14a8b8309f17c44bb414b3d74faac4e345cc16bb64c83ec01479fc0c993bf957ecbfb486fd5a4e6c1d3d1274914d5727c22f1917b87c903dd1881df82801e91cc83306bf990f0d55e63891ddb7fc7b8aef4c0000012800000090dcfeef5d43ffa92d2424c452b997f50133e3bb19581f58d007e3129bccb19388e395d25eb5bb852c71700150d709b93871a61b543439e5e0f75f174724f0d7ef9e61c335ff95c337e9929a7219ed1af1263a222029e7a033ff8e7f0ef7ab74af7d85cedad791f2825976d375f17636a80132c3034754ad9ae550bdff011feb1be1c172b2207f98239ae4349019ee465d00000090ac3204228825a74c55b968672f4d63d1e2dc40b9f41659ceb3d5dd63197f826e8d77898eb5e6120313c5ef4ce754d4ba89adc624fe368bb493b5c142b635a2a930339e8da2bca2d4e07b7ae451fe95ae2837128baacb9756033334a5d63609289cbd69f559036c422ce03dc91971424901cf9e1f28c35fda2e46fc7ee1239be8d474913be51cc5a2ca432f6b48684f840000012800000090cd23db296e01fd2dc8da08863075927f5a60a7907f3d265769f8d0f5081cd8fc218766160527828a87715ce58f6d7416114a9c1ef77ec93781a8aca5da4d3aa8aa16fe1a09eee2af3994eedba49718ba28be0537fb39986aa2e1f3ff5bd18f41e9ecd437e6db73e4cada5cd5639935e30756bf0b2d3d0a9ce69a6aa4c2e7d330be077532e4bd5e0a309eb5d3d5e1f94900000090f065bcc6ebb2303fd9c98b22d0e78378302d69307f498fe65e81c146d1001f1fc58423db36003c66425bd288cb7ed234dcf6e6c5cd03f6cf7f3b317b88d2a37767c6e36caa7c0997c0977252397dbad80997a6ec34730acc421489e3b118dac6f17cd6b4d816a0092b3e30477bb51c62219452973b63d9fe92bc2e93b6a0887c8d2a938a00f5cc40ae3d35b71ba74d0b00000128000000901f4117b0387cbd69904faf5afa7e0994ee94179caeaa45f3b3eb2f2aff67481e0da701c4ae66051bf316dfa30304b550add8512230122fccb457af9f61ea3522d0a16255a26d403e080182c27b5ae25e21973829fb3679da8193c631fc7f48bf0d8a789dbf2b42cb39ed2c57dadcf431129cb742a98965cb927e16285bec36e576ad810e799ed4089b1dd1b13ff07d5e00000090fbdf9e199bc0623a1fe2d32c0a4cfc814af0f22450bc538fe3acbd84a8e16e9244e44b25c59dcc3c566b71ec2c5ecce2730680427b55a9fe31c3c2725a347ba742c628693edf2d5644c6a94970588ba916c139b768b3c44cf618f2ce88546aaf413f3803f30bd9e0b66777e5d655f4831cdad9a00f7ca7b8549dbe5d0c579f3f0fb929853a5e836bfd1856efdc4fe20f000001280000009019dd6fed398d5a1ec6d9b90c21f72066191e977de4aaa552a27e8749d1e320081e7fbcba1d65f56c6ce845ba3218213ed8a07c4072dc271d5228b5cc58997ed670d120e96c92d1dac8ce47f856319246167c6d2d5c0c304aeba71d923efd25f9bed2c8112cdad624a3211d9692814fb9029f1f04fa904b76b473fea9e6f83dfabf214caf5ffcf0c5827a34731b31e40000000090e65cb233571c73e4fa6c182120793001a990fa27b961e18ce833933d48bb801382308a6d3c615ead2f098dc4b7631f4101d559a2a2bd2908e41ce82bdb5edb27173450739eb2368b5444822d1ecfcd912c8628008c9433d1c4fc475e73d486032ea9e075da8a2b4f2f9159cc6b68a9e6147432868e71b7093fd7af04a9e50f5188b6d7ed57cb7627ccb31670df5db32d00000ce4000001280000009055715488a08c638d410ac1c3ecd21ae332880fc42105b976c6fb07d698c1b39faa8d9b12934b08bdcc693d3ec0128051cf80c4e9f86c5973eb6d40d03cec36dfb7c971d734262ccffa3dcdae15ea22750efebba45ac81f517d39f8659cfb7734733128e7a96775491393889c73de2e55067fa9a986af3a69d33cae41ca15f2bdca098c58a97d91dab3199c93d04f570e00000090b6dd3736805e84ea003952a85327a4e528da04d3b158b8f9242fd8024ed02a5adc297de3d2ee0ff3f63d4adcfac256d843cbafee96ade152809332a8547682ed599c1c0e91498f3994ba461857d4b8ec037262da4a92fe480505db09fb5bff17bf9eab8daee32e909fdb846a34388c9516fd376daed2955220b85798bc7b740014edc73ffea1a5f7fa15368d582c965600000128000000900a8ce8c6a86aca7ab9f6ea3fd6a2f6535f672840674ab498f9f5ae781b925f2b8e5a0b6ce75cc08e9241452c57590936b61bfdecfef41ce881ec548b0b5a0ecb0abd8405cb28b38d04c8c7f0df097cb424f19bc9257e5fccb7c90a57e15e5d92d6e2eb60ef12956afe176d524faf5fc418725146da3b7c57bb187f7e83046c8898b46713888b536f5ab431d808e4a52900000090891c999fb6f5f2736c46f3d6699cb9869d6e022a61931bbc521008bf3e3d57f048b7bf300a346cf384f2e73260b6796889c7e6416fea936b69dd330e5828ed21b7fee287d1cabd0c1ce21e2676a9ce451bd960aefee87efcf907e8433e3f986ca0d46a4c1c6074b37a1c444c4fd8447d12cc44a788108c3c25de23c9d5a50ee77d1e64d8f5c3c8533abf5df125140d320000012800000090fe755ae0c22e8a61cdada5c298ff8cee16a776607e29d4c7cef27e0de9880dafa71b65c64005522859505870fbef0636ac3066b6b7c7d61941b8a0448b7bf9b2f6f1385ded2e353b329f5bc5a87c2d82088ebe3fbf9907f30caf2c3b649bace27ea96165beeb06bde6c1727b19b6487b2508fa3dca2918a1c35bccd7eaae5e195ee06fdc2953d546542535d3a55c9d0b00000090abe888fd7163369618f463f6d33563db49f7ee9316b35662863a60378ae0312d1f1599d9c2a967ca597d2a6512577dfec7ad1a75364664b29bf2311db1edffb4d059048d653a950c4d7222a53cf069731a7edb0aea3e2d066e760eedc1ace79d8c826e5c2e001790d8c5b99571c174720a03e33f332858a22d1d217591bb4902d161fc4ad5cb987a08c4ed291960400d000001280000009031046819fce63a7102b44aac4c5f8c7a61a3509eb5689cdf977d59cd27c2ae4d1ce799c3c87ac8c8e009f16f8e668574eb7390c74dc034a69f6b3ed1791ae3e8ad9cb378051a96b03e146071515dab32042bc3e5a0144771e4350cf9e97843324a00afce01dbfdaacb9d7973ffc92a92087c71040899508ac6ed22f98cbbc28a326e5450a4d45fe6b3a647b50a41e56400000090094b3b1bba5ee496fc26c68a807f8ded13c145d68ba578d7344525cf8eda77c26cec928f2637327ddbc66ed7a010164adcac03c64a9fa60378d8ebb4d4ef6dc8a0abd085daf104110f5427e737d11dcf0f81eb371c02344fdab811faaa2c3f6848969da8dcff13706be21add66cbeb7a1af501f16c59213bb5ff15fb5622c77b4230bf65f7f99b506dab2da006c5685b0000012800000090ee8c783eec420a1c1645d48a5629cf8ce95d1fa8949367a9da12a9ede842d00b13110aee316cb020d0179e109d17c2bdd9ffdf4a5bc64fc72a5cd07458a7ef79c6724c251fb28c7cc17dce89e99d45d31469f8b4ff96a5cae2822972e78debb1e975944e56522f467d32fcb387c2fcb517125a849697ae7c264e80cf0aebdd9e8fd047d3f48a8ca181ddf60a21a4847800000090c21131eace51e663aa5ddf47fac03e4b8c1b3a386f11d0c4d4a75b8989b6176daedcda7cd3bf8250b611569ba72caaa70aa03db71feea8d09e5a4d8abd3d2094a5137aa8c52af5548d8a8fabb5bbcf0c17b6b9196a1dda2389ee4c780831b684ebb6cb86eaeade5d02c3cb5c9c09b5270e2aac6566015226bfaaa7bb1edb01a88c5583cb0a415ceaa8b0031cbce9c4e10000012800000090618ac49800cfa73d6833d7c6b8382e3409e91435c9901b6b0e6fa5de9c09f065853cb0829b9301e3ade7c1b3c01f0cde7b99086205021fc578bdc51e7aa843849c8ef00fb43a30f9a3c5e3f85ffade7b29e73fd40371222f8d668c62863d9235f3b8adb1ac115b5febddc0e305bc7e1c006902c3cdf60732133e0803abd9fd2d509dfb2fbe7742a9f44d82dba0ffd27900000090a184c9e0eefea15471bab69b8f0a6500c5442f6f042110173c5ad0827e5cd1932d38ea76f0aa40cba967adbb9e97e07db74301806f696d0d177cde9fa0ba61f086b206b98b564157ac24a5dedabd82792bbe9a051cd6b48514c3296d6c54cb8647df72025211ad123ee1cca0291ca03a245dcf0768cab5fa534d148c587ee66f5f36b89fa50df893637f0a2aa8db180000000128000000903b09966390159024f0c642e5d657b0635bc31168923f0a3e0736823d1efa7e48a642a25fb718221062383683fb84e2b64619ea07f026297b445f5bd02451f631087fad7617b2d16bb585866593009db0094d06fdcf120b60e1f4b1b4de7601be84406b9a5373ab0ae7a1793773567d1d20e39cc64e8fcd3e65b33d226a559f87e3029f022c545a449c6fe85bbffa7b0000000090c9f21a34cb2673ab1fec1f94b8b54e3829ad11becca8b51a924f18796eb5d6704d2770518fdb1fdd84c65b40fbc68a5a6c8a535d4ee2e118c851439db8b78ed4c57b8e3d11da1562164de0f87396911525a9e502bbb33d46d38cf863102c2f2e74fbd56811eee530baad35810faddca80326e3d63d9799ca7069f6797d294242373b5a58e6f1ed7330d0060939cb48ee0000012800000090367e9fc1b4a260ea686ac8ad04f2e2ed0761c35a27e3108e16f321d20c8acb40b641a4cd1f1c71d2c5e42b59995ea7d47080e33bef859bff011b38a8ef6b043f236f976c0c39a13f192db7011a5831f807013ac9d1c3a9b88810b0e6ded72f02265be72de608b63c06af3375a1e2daf8168bbf4ad7c401d160b6b36bbaf33cd7542211745a0d0d0abc709d284853ae3a00000090d644726cd54c87ea3ce66c7a5af8ec080a8e8a9cb8db41300b151a2c338e7f9f14ac0e231043934a7ed7bb837be46c7d187e90dd38298e904499932add5d825fd22ba4824609f4c54c3db28fc99507a916a8efbec6336f0b8e8390f5a5106612c428a0adc434d9320f9b9d390a4829e5079a5432b99e97699daf0d728421bf8011cb6bf401f53eb0c1beef6b85d8241f0000012800000090bf4cfcc3fbbd79ba831951aa02d8cf650e7d462d4f1c7cd2a5df1a7ebc6eaa87cd66782af865070338a0a76a66096528ad11288bdb1d9016c1e38e2bf1beadf952896e570071c57f7ac313ad813ac1d90b3d76e851416bd1ccb2dba2d128d6e8203cd39ca8b9d50955970c007b7dad4d104e291a8f5df57bdee6008fe68f0d8163da7984dd6509e2a58655ac2d5e74290000009081d736b83b29f9b0611c05a0dda2490330a97ea2ad65e48c042a3c8b0ad80daa2b6d51f6b19fffe03b50afa87da3262e80378f6248cf5efd1cedd041692aec4573d0e1fd5207c8b281825e76225765dc1f37ae1ba00845d72156077c6533826b991f5f788dd1a10cbcd72ea73f6515812b1ee78954d349355a2a5b9c1232eef4c83d94e20649dec3ab24760cda75e10f0000012800000090a3a61d404a07f45cd49966ed22bf3b4e9c9c5878f58915e0472dc8dd2eb594075d8efa7eb429d7ca61a6c9f79fbea29405f228e03d0bd978971e7f2a42856a89c8aaf4cc565f922b9f832af1c22d365c303bd283c6a1e7b378c5179620165d78bbd8700d4a2900e525236299768dff561ca13cbb25aaf32dd350f51521143a7bd81be6834983052b343e95102f69060300000090304e9b7a5f4670f2fcf132a631b18090cf542bd22bb0a45fbcaa1a2f4ff290e8eaf041592ce1d0e0873e0db3a5943d6ae92ea857d2321859ee87f48324df9198b44e02996ca66db592142f89cf938d6b2e98e9558fcf3af3bfd2ef38ae3506a31f4fe45d907853c60dd998a0ad5bef3f2a620064f2facce42d62d5a2506aea0aea0685b21c7558ff45f122aac0e91c8a00000128000000902640abd81a3da57efeb903fb7ee0e5b7f953a7002ec47e3a9abdf3305a41530e7eeea0371df3533bfaa215b6c987be3a6598e20caffdb7723fda7c5af5fac93d62973c5a86a6411304310f4c0d4da8af14e9d113f7df86b49d60342920cc20dbee12dd8f418d11b0842821684e87feda01fc946ef7c05ce56a9b98f19178f8de758e2af5f786b1fb8b004cc85cb23ec70000009013ec1d98f9636f93ead41ab3140fc2a411f5f2e021bbc9f72d95df91ca55084768d93d2ccebf83fa26cae9e8fa83c2b118fe1cdc46eb9daa30b2d011c40849f0fed65cfadc92fbef62d3630dd676c583125d62403618c5c88c41f689de97c1d75082ddcbc95339e74b677eb2d1318c620d0cc8c82f44736c9bdda24e8b0d706003fba7d4b23237920273970abb93545f00000ce40000012800000090d56eeaf9b6fc69437806e1be871c1ec2a0c23aa64a1d82bac9a7429ef2270bd2765c33c91f82598c1f68ddde7699a285cb64bd409502b8e83b42f1e28207a4e874f8a0b1444f2886da4755d73c7863da004d0689e149f89c368d424e5cd74fdacad44ac7584c9a300a1fc9cba944be581dadbe8d6dd1dc5f96fc4c4cccfa300fd2e787e80e7618e9c5be43003ce3d95f00000090f572e6184890cd783a2c867345f8bf18fe1461a046376de7473fb34c2fc2f1862f6b769d98e88f737eca890f5f5cc48db20571ed6660cec27ce064692abf5cb5a26e5202ff3e0e1fb703499d5fda828800f8b556e4c1224f985a8e2ed75c66b12aed838d942929590121f8983bdc5b7517f746adc73b0c09047e69b64eefbe0340c78aeb25efaf3c0912f93b4f98a0ee000001280000009044b6e3ad790cc71cd6c47f871fb2a86629693ec8472f30df83c8cb4f6001e0e78dbd947a4ada49b87a2dcff150b6735851336062fb4c3ba6a3a74bf35c3aead1860d1cbd5c3507e60a2ddf30ae898cc5018d40e135b8e5c7146e5b2864e91c23da095ef0d6ae535b7d9c6817babacd5313112b1fe26b533d29d413a52391cfa119c12eab0515970954c029ffe1f87b5b00000090870a1f0bae78d421ee6c9ac89c1d95a1b18a31d2b7c86ef2af7e568103d612834985339e8c33c7a5d24f90681edee45a8ece287a949c6f25427b8d26fcd5cf0b774dec6d70cbe0f1688c77266f78e72f1d8418bd3266b95e010d48d53cf30031328f6712893c9eaf368695f43f55f6132a50a634471b990ca9754480d43e87116a1df5bf3b91fdd2a639fb96215472b400000128000000900d2bc0b76f2e7fe9b1143b40fddf59fb274426ef2d5f01d7ed24ac9cd6c3b5ca1279f0216fd765c65be395648debc9082c5826acdd804dc1985826a6d30d9bae86783cd9a9b05a178e8bd613985f0cd71dd6a8dc8dde4fe04fc55f5b391456e02bd685d6a9ea14fd36c38d355d62673e2cfc54c674dce7da0b12c50c093f3ab559b8adbbf2b9cc3b4e3ea52509715b0f0000009012d6e407a368b98961a98fccb0ceb799977f6babcc11d9de75203f9b73dbbc2c141c38bbb43b4d3dff3ac3fba44c348fc35edebf22f3bff9af985e67e2dbdef73c0dcac8c368964f0257a5ce18e5e32a2efed8a3befc81d87c130698efd0a7e6a24a430448b702852988840630cbf639164d104f77092c2e2b5118a6e4be061e6143a9b70ebac3a15ac1a5bf9d5a65c60000012800000090aa1fcd5d082096320617c0e66f2b830a5c7c0548be3cefec89c8d5efc2361c6f0b95119c85d64121f78fcd7317e7c3481c4cc26ca0ff51ce151b8e891b3acd558b0d269645cfd61ec41c6e0a390090882a5e9f8e69af9d41543ab3be93a4a765675fe193213864305b82179cfffd52500039937fc63b2efc64a515492970bbb4a62a476c962bfb03626448e49f478437000000903283ac07cf03f2b74193fd9c1a16ff330ebfba1d6a8d4726cc6f39049af672c17930ab4ce63180b24922c18c43c01b4ac0172b5aafd299476b53e5ba1be50f7e877313fb34ee31354f0378b33b0cb9d4116b9298a40ed296d2b23696b6cd3a50986c0bdfd2bbb5439c58af6b351f9cce0103ab28a09841aebfacf6598c0ec25873088139ce3306e3bbf1a8b84993242f00000128000000903f890ff13d5bb64a96df89deceb505ae3bd968054cb6b354bf39a73e0d3908950a0d9aa8c2d5ee6e2b4fc0188a69c9acc5991f91e4d321b865264765c1de168d83c85ba1ac616ce4801017e5e4c34cf009a7f9f287f676bd11c67d9390ab116e7cb9dd8aa6b468a04dd31f5d78f9666322e6b4b017677a7ce3888a6618558310a0a6ac3fa061782f3c8c77d60f493b03000000900fdef5192501a6583cc3cb04a11f34997f3676a0d31183d87fb7e6255f8bfbd22dc5ca480c264ca60e894727271a00cdbab0b96de88c43e699961e0315f60675fff533af703b944fab3e2900cad022f4207fa960b0d7465156700dbb6587a95ef99dbfb10201d98a4064d1172feacf8430312b5dca5204b1ad73cc3599e01f077a070a39dcda3ea7edd272694debcc49000001280000009015560ec3cb3d4cb1a245fd268fb1c81831d317249ab55981783db915eee39b58771efa13b81e2c90852d5c3e7e74580bc8952a487c10f96b953ca1d86ec62284219910fa213d4a028db2cb3b9883685f209ccd6054af646b530afb5951dc48bc61facf9562420135f161a98d6dc78cb2206f2d4869841f67d3275e541e9f9d66e356d27a06bdaa61448c0afbacc8ad3700000090d445aa4041263de462b276c145ab0bddd25aa0c5f875e429c323e3f58d2d5e84a1aaa46e9297e5313840f3a6fdd600e68453e822744e24500eed099c27de245c542afd148c20548ed106ac2c4286641c0d73fb1acf582d06be8c11439786115b3c634b1be76843622d2b14785d6259e12b8f67d232257b9c837a590b2e69259495c3f9966f5dac6b9a7e7773003aced30000012800000090cec753f8114fcc724810c5123315bfbf96dad76dcab51ba41652b10426b9fd65d7a48cfb2784484e0cf61b8b65b20afc8ad669fa2c879d19028338017df945614e3ffe7c7a5a5f7e7bca84473ac862f403832ca2dbe679bbe6d0e1fb7ea7e21930afe46894c13b48446e6005ab935d841d5494ed8e72009c651dca2ac7eea7d33ec5dd615d818fbda959ef598a230c28000000905a08792b87fedc1a668185e3acee53c5144ac408216f98c9b819a648d5c146ba0499a9af83e36ca91c3f6cda0a225e01cd1e41f3ead0c4f4057c8cb6a7b4ed51911ce4b24ac648c3cd180666b4b74377126825d1ae86b7502e11ea18cd1c8d55156a8b7a1f25c21a92ac80e007c41335182b160006561e7773143e3c9a5dfeacf0e8496c2e2c6ddfd321c04d4673047300000128000000904be201a9ffda34daaf047d5b528835dd61911db450880b1bd3a2b7fc8298600159788b7e47f83dc625b8b9c2636b6ce78c5d2a6fae8c0d1d44009d0610dd2c6f82024a4b23afc49164de7c944b5e4d5f0e20f06069ce3ca7fe2f76c21918796142314525e4546f1e83888970e68dca682f51584adf3fd22f76ad10d759867c52cb7197f1649572c342d970b08729725500000090aeb1109cb748d04bf154bb94546157475bac2113d36e8d584e953a57a7fc212355f8fcd186697882282d6dded2e55b85abf920a5c57e756e7545faa36bce08dca2faa5429086a6976b8c4366e45311d41740d1c95e322047f5b5e96262040c69a166a68d6eff9e5e3ae83b261c0aedd61f830bd4c0a38e1f45c720774e902b7550012b2ba038c9d3710d851830b7c0c50000012800000090a492671e46d035652bae1de1e2d3f409c9391c7ad1315f32d2b686121a75c96756d4dd16f0ac1d666cff578f352b4569fbcba5a153ef82c7611c12421ae9027434bfec9260033fcc0267f44e5a3c4b4f1c2f31f6321a58b8f0ab6b7887cfc7107a2bdb59346fbdae29f343c62e2a5f1102f383e52f679f3d9757f3207cea70f06927d9526edf9b33ff2089f899f2825b00000090148bd8adb33b112b1aec51d508591ff6a3a960056bba4697b89ba23edb1e95b995fa9c1f96b530d117488c56b3351ea5990fcc431ad21c67acadab7ead8ec87ddaafdca660fad163ae6e35d3be395dfc14560cada59209dde10b230d7d4c662e3e7cfcaeb7a9a7a340dcaf6fb8fc15442b58edf35c4c02594f1bf3e5ea3e899f0b26ad62f036718681b829dbb55703670000012800000090e8cfe16147cbfbcede698b9c100dd416212652230a29d79d9716fbd8fa08514837c9644e182460c8eb5bdd694a89195e2365eebcd3996c4af7a1c8d3f887450a0d597a12cef9bda224caaab8a8ecbd982aa923fee4ef4f07e28bd74b4e2c8b0a5ef49674b749513e30b1a039186a3e35269a78b9f7207db380eda629301d79a07b27cf70748aca38a1a0b79dad0aa75200000090655afa7a84fdf37709cc9c7a283cb30c178a5446e7d6f18c54607be8526282f15985a92beaa8ae01cd798f9e4cffc106d86021e65154cfb1a47bbcccf2086f6a89226570e73ec7e47a8c842abfafeace2f3c6fdc480aff2705484a3fc91f494dcf5c427290aba416a052de63ecc50fef164919d1aeed69286f215447f69fca971e4a19421952128bd7bd133ba3a3e8a50000012800000090b00d676b1075c815808ac19b9d44e1b76010750dd21adb26c7a8519eb4c197de00b568d2593c1a4c21779ca05f86f074c7a46fdedd80c67185d13a86ce2d524835b8fa30c9b61dac3596b8717214dab4005681bbbdb96dffbccb423a2bd9178ba7075084be235f11da12d99caf6759a52e106f8e5e7d0f016240f1a9654c4750d34452a01d73afebd928384b0a95c0df00000090b770118ade6cba6553985ccb76698268a91a7e59537762d62cb83b5e2fbd6c78fea043ebb9a51314b8588ff85d7afe03837cccdc4f6518e4e51f28d22374f5814e7c6b5648c0d06563333f8926d162932a7f3a03443f27b002a613ba3efd51e22527ac9fa9fa7dd1234244612ce6b8430a02bd9ea02b7e86c7c9591d9086fdb8a986c8fe164fe57189995af4fb8fe3c9", - "calldataHash": "0xcd9a7ed1324b15c82eb2b86042643cd52b67ef1909cdcdefb26d2073d8664a23", + "body": "0x000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000061900000008000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003410000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401000000041c72e330b60e0052863df88b19ebb482d412b0a7bbb2fabb9347be5e59453d10078d263242fac5a2ad544b5005bcea367ebc04e01ff7ca279650bc63d9488ac304ad4d395e21ea570da47bf574569c6526312c5c7ad63a6d248f694e5c81c2b60e12693b411d9eb8f564aa43f4aa14e3e30f8574425a6d6491416332b77d2709000000000000000000000000000000000000000000000000000000000000104041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000010c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c10000000000000000000000000000000000000000000000000000000000001100010101010101010101010101010101010101010100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc00000090ba31e106be659f28af9e2af50d26e9d288793bd2916d001e72b890141088e28edab510df4a749b7353013aea3159668294ffb417f35ce95cb6fce2f0221d812cc4857d625e1a6de8ef2b35b36213ab4616286de404f3fc6463e0e8b3c8f6f8251f122191b6e9fbb1c2cf167dabda8f39040a8bac6c883f89b0ab3b0c1e42bfe51bc975cc64a95028e12e3973e801f67b00000090cf1a7b1afc016e43b921a58db2db12a3e5898a193f7d50907562b5b85e41cadeecb846519ea542dd1629c46544286079c71deb32cccedd1f1174973b6a67aa3aaf1d2383f3220c9364db3bab5e636a6d08c44b3ed62aff9c6317097a655ca306b03eeeb7a30bc8d67d1fca62afb7519e13d782777f78caaf2a8d5bb2ca25f1bb30c4507bb38b914e1cb6de394c47eaff00000090972270ea28acbcd6a954b5e146cee856dd3ef968cbffea1b2e26fe8aa06971f0e8ed6e16de6c6d16da52a856d163d5d489885cbcc8e5389d1fc374fa7fa2722146b3e3ed216d5458023f295c4760c2ea1ad29613ffd7a06c1c8e789be58df9bffcbc51b33964b639a56bc5dd1a51387812f2a6d70cef7584e1fd429ffeea5282e9e526246a41da20e503971e2aab4ec5000001bc00000090eb7ade43f1e76dbee20da4688d5b051f943bae0e4aa13d6c3df97fc368f76d43550019246b1190e00cb20ad8eed3290d9589d0887c900f7dd563e46a8d1cd032130f47fed6c734a21da566075c469ca9006b482df4c9cc45c3666f721cd8f70701754b25a3f1fb4e350ee5fe39bc3ffa18c8563a2f6f82742f48612ba792506205880c01d57a739598bf190feb8596240000009056db89a8f50db43b830026ae48dd55257eca77acda80258fed70ab6544a1da8dc8a5cbf5cd2a6ce9ca2983cd08679b8acf024ec18107b7bae3477de8aaace0d672c802658736d0654a7fe35b810ed34809f0190f92b4a8a070679832bd2f978d06839aa3c12f7263facc03ded7b515d606ec5141d8fdecb686790d39f0f7f380b056b8d8eec3e12522d779459764092100000090255a139bd500720e3731bb9a6c79d111a39618b2e5f7c530ac9847bf2945c5fd11726efd1664ebd7c5ca43a9f001e6e9048151ec3ae655178efecb510735cda8838001ca728b89c9cff98831485a0ad51b5a9d5ad1566b6ce5872da25282fba1e8fb1ab733ceaa1e4cdd5714b5e0d1ba1a34e60123ff9adef7a9aafa7a70afad2b0150256f6bcb582edcdd802322f455000001bc00000090ad3145489922aa1ce466b9c6c7d72ab3806cbfe1142b29704248fb092ffcae20ce010695fada64864571f02888d1a20a5aa6c85bd719753e5a24b112be2165771eeb9f9734c57044eb2be7e8824c630d14af1b5a23cafb9ffb3449c13ad139c1625cce3cf18a30dba95f89318bc26dca1a788d92b8c8cdba555a3b56f61c2702834346ea4b9c995f2a62832453c95ba200000090efb7e3ad6436cf40a50d456603b484b0790c484345d91ef82df22727bf83359189f64f7647567c4a62d967b7c08d97834b0acbcc233dab3cfd4001f19cc05e406707a1752e03e79919a4a5d58e71b29720aafbc5877bc7c2132627780a3c8028b8e670168e23175d776a0791e9dd0ed1005288a9a0ce98fa9918d9e40308c5022e264ba1f04a36c3e747fa8e039698020000009003294bc41bb24fe5cc42ec61e2c7fe1bd0d0a90a37f04a9860159e21cd2ada613cdb72c0a60eadd711d0a14c1fbb8f60840c4ec94c91a74f2f65e989785b3a28abe0876640a898cfd1cd4cf1702ba78d2e9cff04a1744646744b510798e0c4c1d2a1273fb63a9a8fcdfcfc6511b2e3170d66e31114b708a4c85eec819ce2a81d8b3fb0e14b886cf418f5f904818a9513000001bc00000090fc0e40cf1531f14a598f44838136445b088a2a2f45cbbab5da3cc3dcd3a50d9501b376680602ef03fde8f0efbf5e64bdfcd04d2be10467899db77b87f7082e6bb9606f2b3f6578958f7738aeccc2f998135d91d51804d9bd5af9f9bf0cc082cfb4d914ec78b3717588a607d28866895a26d3dbf67613eb7b88507e96c36f8eb3f6d2f035ff29601a7070db25482ca6480000009097af660dc945d784adf1e74f09c76c0d8070aba3c837dd839e01e1fe905a526b297da15eb220ead6988026a4ccd36544d2a2cde5d68b63179505ac1cf61556c5fcb06155a299e98b76d478dfee7254b10474f23c1f1d780f3525ffcaab169a947e8b42a2b384b2a5733a408d8713510a246fbbedfa20466f9551191746bc8bbc612e2d8605f9d70a1ab9ab78393658ed0000009099c961b18e91d5f06f29cabf320bccb0050d377bdacc0b811a1a5401d046ef2d6fd59c1434c6c7f7f658467a1c5df79c6bae907a28dae0ccd73ca52e7148d36d960bf13af6a158381b2b1d3e3d32085c2953c851420fcfd51c7da4402646bdf8b70fce51677ea205131cc5985b6c36661e93db19cb61526afd04356dbd7ae0b742b27c4dfb3866949e5958ca3e842ba9000001bc0000009002c28f7f35048d85da57163a88bae6c1ce86084bcb10f1f2473b9fcfe3c4d31e696db7c1f176d59a8662fd98179eb6bba3d3fdbd9380987823949f7f6670862992d060df1bb03fc7be8e56ea31d1049e25eab063ba144bd855dafe6615b7e3394519bb08fdbd277645f235e627d8f5c922f064f572ff7e9e5d3793d8f17f7be2eb642ef66ab2c937f234ab302db9c01600000090ced262f3fc9841eacecf4ac79ece1a6f329883551b495dc904f1da4fc7149c19b0af3b589f525b192585ad7cf11d37296750f89b42c2f74c78a4cb7b301b08f4995e5ac277c65466654192ed8b7fad9f02e2c8c9b67aec2e4fe51fd582b065a0b1295023088671f1656ef0c899cfd14e24d3823a3b5bf33025daffbe6667c86a071ab485bdcfe78fd70f4ca591a7744800000090bcc6b58413d5bd230d8ecb4e92873d5d59f603c97f90dc0f13a47cedb485246cef9bb7fb9eeb97588ef15e6a560e7807a3bf30c19222223c73d5495e514f9d94ab925eb2efc5cc009abd85306a1891fc06e743b5b79bf848dcadfede5215546b2475e9ba3c3bd3c90a59b06b298c33b30bd6ca5d1de7b231868378fbe77a66d4d7bd8acdee3b91552036f1786a899f8e000001bc000000907d8152fafb9430eb4212fd07e22ef189b74e1a61840e63bac60ae533b51a4ac663cf6f1eea1b7b005de75030992f3df13520fee65eafcbf284055d95061770dd76993321a449b17b3ba8765d4eb25a5e13f3ccc51ccddee670bf64573ede4d604f38baad0e7b745eaeacd14706d15dfc23e21b0eb00589c0b08468185419290deb27e4dbe077c3348d9ab03babad010d00000090ae769576c6e1adaac865282f54be54d7a32f397c72f6b7cac17b3632dc2b7ea2a991549df2d8cc79a8619bf84dffaf8ba5b8032566047508ff713890d1502f9b6c223c2f417db257ac5cd0eb24770faa230c8a792a315873eb4dd5c089ac5ddb21e7f1be282d2a7474d25b7a76a5eb49094555d3778101e0d87b2fc3634faa9e870274db85687e1fb9985a3bccdec32700000090d6419ea66762388b744d8554f1d12fa61e186e87ef656d9fd43afe120faaf85ca3b919bb9e1159b26c6f9373ed8900ec9b07958a7fa94122767e8fbe83fe25bd25ee9b7bbc215169cd5fcd472d29631a2c85122496dc2a16064f0a4d971d00213573c1be7ab46d9cb1688b7a6b8ad6c715cad16545eccd57cfe4e009769a42f43d35f94afb0ed37f56497a4083b4c1c9000001bc00000090578657302fbb2f8cd1f948c6f7ec702485bbb02d000e49b0bb270e4ba42aaed079b180b57324b619358a65bb30e1e99e005eff7cab46e6ebad6a24bc271dc6bf596cfef2bed50660ee5912c7261f602018fe7c0a8aa0039f79e2d7ae32bb2b3e50a55aaf88f6facebeb285461edd481d0853f2e92bc2962d3abd76ee05c051fd4c616902b3da929fbe7147c9be20b33900000090ff20a189a61ff5160a797d3bbf9fa8fe42a4a718dff147034496e00803e918b5010db5c160bdcc2cd20b453f80f52d555e28addc5b3eb493a14a5eb24bb7d6749e725eddb2d15b7abba4ff1d6f51058b064750b8541970f26baee4f5daa75badc7d27cc7de416972251b974fc47fdd2617e2548554329d272dca1848dd9ca17a8655e9c79ed8d65b9e626bb5f4c195cb00000090da7b1475f1369e5dd95e3974f0a61d381e717cd227a6c907b6f79e25348e2de665ce82a5ef35bc7bc8b7186cf954ec7975e763a76e2b4455c0e8f9f6c95044018b6a6612a3ed58f397c92b4f4a94bcc222ffc4c50503009eaf6898361f5cee52f86d18168916c6d828f762c4e9f1e43201d54a8d7d9e228d202cf6e2d7b7732031cf021496f45cc607e5c772ab64c1ce000001bc0000009082828bd7ea8bd0238eb233d84a6d8eb81473be3048e55f7eaebaad27bef571d806ca99b1583a0ff91d2c2dc5c7165b0f8b5291d069f9041f8c134e58abf0b8a7ed410584e83b3570d224a946973edb9304615a0e468b252dfba310ee65f9daa91e885c7d6f41400876430e7e4283cce8164343d81d0d48a970c57c9b641904f1f43584464f43e42fc3e504dc1aa5b0ac00000090b29129ac91e149c208ee449e9369c39ddea7549359465c1dd7b537c1b768e9afc8ce9aadc7064f10f070eff11d526bc86e5c59efc0b1963dd088c344a0d961214951ba851afc71961109521ed643fabd1bc4146b11f60f52a707ded2c1437eed6621c9298cc689d29573092bd5a5d1ec051ac56823011cb0aca04c910b86eb432ccac18e0713ad65ac0e80fd6461220d00000090f264701ba46324c881a50c29a2cbe56d8ce1d52cb12279b9e666d2c821c641e95e79769ea31329b8d108b5889d12aba3fd22803ced02ea159e5ddd413a810e0147497bfe0595045f5afb828074f87841059e29b9947ee7e131674f694e159fd6fa48816b194a40672220689a3ea39ba51a499df559f617205c47ea0b29ccbe38e77afa2f22901a6ac19ecc44b25e024900000e00000001bc0000009044de4596fcd2174f04e08f5878714d65f924bc121137aca1179967c71b97c9f9880aa849d962e6c2194daa6d78a35dd8d7a0d6267bd4014fbf4618b0f7f3b35a8bce6488b5fd9f771288400410d81946029daab01041cabdff51997bda933b63431573fe8ce751f87b9b6640a6ac76e62b89ff965f5678521288c80e7d924586991cc8bd828803774af1110ad6af2d1400000090955411b3931838621ad246ecad090ea826dd4ddb7bba4f2d692e73d6fbe197f0754db7d8cc340a993078595b2e56c9727cbee8412af57451e251a28716a32c0aab99361800b9c9eedbe58a70207b8dc50cfb4c5670dcf4e3dea0b0d90611be362f0811e4738223810dda308e068502b1275033156d228b2ac72d5c13783764ecaf93fdabb89c3a60dd2511eef546ed47000000901a490364cabc8dcd69b5311f1a3146fd1ce7b2ed487e7770cf9edb318ada757cc7d5a5ab38ff4af623532d17a94d6a0ce99967aae09a722e634691ef15ce8f241bf3b34849564ced406f04e40248751819b7222d607629479e4e0bb7d076d7639c8f6ebb93530fb24bbc03e884507e002530933112acb5c27690c1babfe86191035189c8c17c66fdfcbbdbacd583934f000001bc0000009054be3def72a403f5c2c9e65dfddf409582d462514312202f646d792003166b0f85955514e5e307e9935bbcc9995404afe1eb12bf2ec671eadaf9a846782a983585347a2cf8d5682e9fec25a588fe81eb13ba9a153f0210840b5a343c1223e88a80c467332cb74375602f02a409346000107e5340ac4ccaad5b3281cfdbe0212f640df8b676de03b5f8540623253c6b7700000090a0a2767711576ce8e6cd6b6b1ae5cd8686785990afde849f7029ace4c60f67f07b05231f390f23d2baadd5f0e76b9a5ebde244872dd5757180456cec054c62641187283fe89adb7657866faf7c6141320ab18c2342b86331365ea3f744baeec431a00e8c111f1f8503a7362f60f6eaac268c0ff4448be08b68f919909b6846c9b64e18a4ae9d7e6a640d2d3b45ad9a5c00000090174b52e1c4cc5baa99d81bd062bcedcc8055fdef765174be6dd9306fa931d88888d8d069757b1c6901c95158e8536627f997f10126249fb4bfa15f1a252ebc4a8f75bf5ab07db6c530c9f4887381c5f30cd5ada4fa5f13eac5014e84e16fe8be85fcee722e18675ec59856d364338a150167f37baa8120dff1c3a2422373f34b36cc620d32458375f28073ecd0e89875000001bc000000902a4d89127259186300e7dcefe2b9a3c51c3ce7262745575c1893cb6ec67db59cfd6d97faf4d955b98d3a736ef3c2762b096627ff8d84c7b9a766e5b910377ace261a27c57f67e454fc74b3b65be2310d00d4833db1c3ab4bcb66cc02e8e389148c4c24cf6fd4759afc32e54948a302a5239b055f5e3b16ad3dde597a249742ca3151434363779a42e0900689025ab25000000090a47255e90a224451cddb8819b9c15284c0ab2c79cb98278b3c175dff2e628552793b1e850680507fb33a41f13167445f80dafd01f76d5eed4217c123f7414f2475eff882cd5e6c46216537ceb57a40482e307213037d9a9a09dc1446d1a477b95055de78be0a8b6f39aee6e84b9fb5a8022146920ba50aa9621192b700a6068dfb8e2174d2ac773989feecc6d28261b30000009031dac21a1433f531dd18b1632847fc0dde1c17bb02d5ab354c02f4acc795c5a8cff0b773a547814cd9831bcb9abe8e5acd292deb1df4d6e6dcd1a820e3c17a175c89b40c49f67a7eea27e549af42b416198cc216321d12a56329fc95f648f02fa3224088cb61154ecfe1b9628a5747ef26479590b8bdb8b68b2688ec9b7436a3e0602787ee7c1dc53d6cc2e141c9e27a000001bc0000009042036b440f7bbaa76f6cfdc9b78b13c6ed8954565059bbe1b6f3dfb5bd88c2f28a2f29e0e5c261c25a2e9d7e511d072bde43fd9809796effe69e8aea3be54508d8a9fb29bb6a2a2a9a4851820c90b2611fa5229daf2fda66f0832ba0b177916de6245b6144a4d9fd5a6d84d0b3d09b5f138a8fd41f0245790f51d769418351eba188c24422e29d28b6dcfa5e108a5ab50000009029627be6070f320d9c0094d3745572911c217ee1889a111119f5bfea6769c574a55a30db964362ea4f37cc38d99b125bd96910ad35931dfcc5e1d60460cbcdbcfcadc88b1c3c31541b7bb37f546b4dc91eb9f46857491b80dc5b1a6f3b7d335c2c5eff3fea40db67a556f82ad31b54452f733fcefdc204055851f24bfe942753d120dacedbb004351ae40fbcbc40e44700000090e77c6e4d7f802613a018998785edcbd7f2d0fe43fc87b5297c90f040a86854ddac359d6ae8bea1151e3625d27b5d726a6973ac1a715016b94f596652f1b5c34335c29db6a74dc5f870523c9da04268891c8fb300114e4a14bc53480655c4b2b0ae1b32d51db9e05ab97eb74447c662aa26552991acc5c288822e24649477c17ba04d8173c6a271005b74ba702f19f6e9000001bc0000009033b75699124df3a003208e2f077775a0c0cf6b5f43b10d007ac669f67830f4186c27e63d53e8d10ec7e04a587d330a93303ccdce48e4d883814687d33c3c6863376ed002b2a9a3bb715c93b9a7077575186f9f30356dc5e9bbfbc7448ac599026c258f7cfcecf3b1386812f03e6760b129f10aab131e1fd053fffa9e69f0affaa6005b7788f7176ff1add5b4eb021ba8000000900d5f42e0a54bb5cd368f9c464ec55077b38560a2dd87b7fcc8592304c63f8b713bae6a5f6af20ab8ed03a6b800a12059677496aba92268e1d36f3630ce184a2547b161ba35ad3ec88535cdba733d0ad306a7f349d6ea6ba73641ffe063da5e81170232c57e6814e422518f2ed1d5b40724deff7d2e8c352ee005a3bbc20bee5b8a835ffd076356fcd10cc7ca052fb72600000090485c8561600c40dff828e00dc64d85de0386db3cd95adf13dc343e26c62cbcbd50e4f230a7262fe5faca058dcf76603cd258d997d93d2804bdeca854114dee374b14a94cba4bcf81454a0e5cfdcf7e071b8700e9a230d063828289d9db02e2f79f84dbd59221b39851b0f9c14a326a9509a44efa10eaf2de68501bc0d20799417ae2b08b140581df7fd7809666f48878000001bc00000090793c45f5f8ce488890d12547e0be78376fcffb61c9ba15909bd0d32c4863702f7a4308e7be8214eda46614b17ec59046177137f2fd4191f5214e9035bb1307efa167cb0f9dfcde8ad8add21435e6dd4f23fca789a52337d770bb3239c51752950f463602450dd61e38a292f7467c9bbb0236993135d3c1d9fb5c7210bd33fc7f5068db47cd18a9cc57e585c5e05f526e00000090f849a580d2493d30febe102d84a596007bb41749bcd698232336b52a1e0909ad1ce9c8ba3aad02134ae5b160ebcbabe506d9b7db0a935349e979b8873be837775b6e688777cae831c426aa99a5b95fd42c5a899c819de878d741f833adce678a55148c00e3e9ad526fd8e8824367e48113412b6ebd36bfd1eda1129277085d388afc79c6e0c9c5130d377378ffc8c2b3000000901a77e1fdf2943eb04ad871b97872d58513b87084509e93626d91fb435e5cfa0bb54ff8bc4db8d12df9a027c4f5cd281b5ef6ca8e187d878eb2c3dc3f69df34b7a45828827534373c7857f949f23ab28726f8338613dabee6775bce5af93968516d4b88cde4e1e835f389af54a07f98bb2f583429751b5c5743de521b13e42b23dd3ca73823a09df3cbf95161056e8727000001bc00000090a526b2ab5d1424ace96e20ea34dbf9260b792747a1650ec62bfdc8c733c005d018f5143a029a821c22cb72a30c3d32a9a9293e905463204cec2133071ef13a270a49f163a01a7788a27b017c8d80f84003705bcf1f46491f774b4b66a93884c7e204d37b90712af352cc5369cc5bd64716bb58ad99f05542c64b16267213a12549a9f3dc14a7d0b2c9ed43f170293c31000000904d582dd6d58282e96ed78e85573a6bbee047a622bc85480221f99451687ac7e2bfb2bc7e7d6c1186fd0dd8db4f13021a6163e3300104f0594771afe76561fbccd40cd7ea868e4b3788bd8534c4f301b2006810388a2e469d05393d0c3f308af465af0511a02e0875951b1f90ee40338d1080f959493b6d44e1a4cf65a157e779f21c53efe38c7ef3d907887e354ab90b0000009053547b42020ac7e26e414c1b59a37ae16b2e7fee712797526049fecca537a0ec3e3682a0c6bf499dc5bd1ebd7f002a340e9e1788430993454d5e1d63e8f814e0dc25967f318695e3058c6b31322348ec3041f03ed390bd0f98c27f9515aad0d8ca13ef9b231be19633d8897002c590ae1770f43809e212761fb5b381ac99adb7f0f77b1f8f1cea86b4580e6e7fec82a9000001bc00000090ed283635593ca3f7d15a67e70784417958b09467d558ab99746adb7fb73519adcbb7e3a07bedf202a71f9ea17787b40bcd9e2b3d8c543ca2c5c21841412a0e371b735971eedf6b99bd29037e3fb9fb69132446fcc638762adb7d51818d49bffe2e53baff09e8544b330a1b5303b623fa1735d51c1ac2b6c492c9c84d1a6a55026ad443d5e385d0565e9ab987e8ee4142000000907a3aa2434f8a0cce281947d36d27b0e4e74fcd817192a81b6afd27de57f6e573b0ac854034d4a98443f2f11bdba4657ed7807ad8844c1273300e69b8c97dd2f6357a79cb090a0d3f8a1ea3aaf2eb2fba2feea06a3e822e5467185d783c488c59b7bbc3f2b61b9789e490a4e9f3d07e091ffdd6584cdc4af094e14d135133008ed82f86785bd7e8038889155ae9d98620000000901e128afb71d9690e6a4489d62164e5fcc2ef689bf0d6fc7990b7ea5c9cf012387c6c2c5591f66ef06662b282e37ae620e43eb43cf5827314f05aa8707fd593282b096bd0244d3e6714a396396aa23dd90ea70748e823e25d9abe06b2e098a39ffc83c00ae2facf8007ff3c87b0bd02721655b67ba635dbd904c6a289abb1a67e40e8070e89e550d233f908c47e06c3c100000e00000001bc00000090093f193e90ad5fcc72e550a3f0a76dc9ee968de5270bd8ce9c08172fb4c2f3b5a26da0fef66c84858b74f49798dd226b31c81c4312da9d68caad1b3c8b96dbd259eace348007a70e934974220895d3680522475c527adb8f5a4204e4587d46425b8b51451a66c41718931d544c99763b0ac2a4642ee3bdbd4581c9321d21412810cc7418e358adf228510ede35175ba8000000909f933c55a67a8891db1b2d254dbfdc0c1d9b7728a5cb7a0d9d2332c8f231821c5e89e29bf226603d34b2e080b52f4691c0ef7542efe42a4ccb99d41b69c1dcde57fc713ead365379c54479678690b5b30bc2370bc15d494b92f87312d7e9f490d19473a552601a755dc3ae5c081f0a672616a830f55ccd94db52d6b2d47ddf4aacde4e8d578bc7a6d4b4aa7c8aa37118000000906a096f39f3c3ffe3cb67047edcf09f5b852743fce0f1a5e86fab0d998254a71d45b29ad3cd74ec13b9eb9c9834eda1357737ba05e4910a1972f70155999e0df4dd8e990d05989768e4222e17f1e6ee1c218c9f0b2b93ca885905f55be91c92316bef67aee818862317377a4c834f01e52bd04ccdd32305997766884206a1e66aafe4ce850160c6bf1409e4d7cc2862f2000001bc00000090fb0977cc718446ec0e65edaab214165c8ab241eb044ed8e8e90655276091b2caa5b86cd7a216faf034ae4e3dd1e16bb749da5771dd976d8fef43d9fe00f213731dad21fe720481b4202ee296c80be87f0d451f969f70c2ab0745157ff132bcb72f557f429a71d99f757c33c1a807f39e200398cee44bb61e4bbe4ad8cf534f21d221eda0163937272c18a849011b2bdd000000906ad3b55017ea4cf98784aebdbdbba67c19b26a55d9f145b07b7a2264dd5bcce3fdf59ccd88144076fb3015b8928ad38df1f939577eb411f8e1ad8959b5cb1dfa102b127c75a185c8a7911a39a4950770167f7d4a5c0c4a3e154c7ab738608e8135426db350320a6651f9187e242031d928de5e898cc59d1d9e627ae27276bb6e488dcacc1eef5d3e2068fad43df6f9fd000000905088875ac73652da0184f89480a4e6353e891980f990cdbb3cbc00629baeeee6283b7334870127cb2a1e888816e32f44fc89b53cbeddf76eac4ba0c80080e33cd101ca1a16699149271629b994da0c741d6fb377af7f696feda2d648b7fb702462ed652b61895962fc725591d61aa4d918ee63a514436b5b7ae16ccbc59ceccb19fa98ff49d4dbb3645370682986d774000001bc00000090ddf0918144b46250424d393f02144553c7de44279ca2293101e336963aedf73ea2f3bb7ce6cb414a71f93698d6ff4644767674b827463cff11decac38484077c251d1ec137b40ae382b576c7ee06c2a727cc97d0bab880a919ec3a647ee4f573eefe111af28c4c61f660eb20afd7a92d03ef2108d1a0b8002013c9c85e4bafc39100fbeb3269cd2057e54372c4ea0c0400000090aa319ccef974a6bbb46abdff5121f590f0b037081ab8b5da9e648292d4915fecc40bc691abd959b2e690c40f5484a1079fe2daf181106622a366869bf5d91dd8df73a59ee059f52e6447d7e831c1c31720a425a18c509875a514216d3b85797c8eb73e451153fbfb3dd21b8865989f9e1265c57271318d4d43d0f1b4faf7c32e52f82fb8eeed4b57d7e1194449734c2300000090ac0b574712612f176bef83fd0f812b1a100ab33f0c4ac5b9f509eba019429cc2312468493bb0e8d10603f8a21ef4ce9fba8102dd23dcc4c05cda8435bbe30b2ec877acb49ed250daf1c502572f2faafa032b4de8ab4eec8ea3d4d5f4fc039094331c3406fe8ce09f2d8697134c44581c1963f64648ee9a3b5ce0bb52b9c9983179f18fab2ef9f7e4368e16d72a8ae399000001bc00000090d5cda54efbbeb6d54ed2496af376a262cb98bf36031064f72399c7ac2be9864ee33988b56d96393fb7d2eed6d9691d9d8b52ab6dc8bf1a78d521103869c50434aee072583799f9c483b9dd669092e08e0e0609065426a6af1eccf3c216d575aa8bc1a893ec1600392b4786f9286ba5b31ca5f04127a582cb84ba9e3b70e5e97226a411c4d3eb275bccc5e25b483dff91000000905c9e9fd56e8d560e67b778b23277cfea9bd231347a999326e3a264ccc419577b44ad76169a1c2869e665b340ddcbc7a9487ce6b0495d70da9d771c9fa10b28f24ad3f16dbcac3cb1d014f0180d8cc56e083ea65e5c4580b6fcce0ed318bccceca8ed4138f01a695d6ca8e422199c601c218a1037d1d3ad0ad0571f65a3eb5172fae3e14b9762a594df1e52a041e565ec00000090ee81921fadc592d08ec6dacb28d75464ff4871184e26753752afcd70424a7dcce16bfe5880f59d9c5c627b0c340ed6de8243d196fdd6c175a6b1f574c33facd590e5214f04db6b403026e6c8f5e459d92af77b3d45409a6ce29c570b5e0e255857bcf620ce7bd8fbaffbcefbd2f7cd8e10c45b15a6ecb3ae017bd588f5f0b2077136572a8d1b97acf8368e4d9ef3c4b6000001bc0000009094cea4a845852d5205a71eab1377a763da5fbe70ea95e68602ed9530d706e9734fff6f0f63d1c1badfc518e6c71eeff7341d3839d377e6f2565a28ea7d8a9dc778e96eaf95ea3df8174f47ca08d6d8711dca8e742fafed2e609e73f17f2c1c9ab3cdfbaeecc4051c2e8ee2fc80bcdc622297c7914d843c2111c3a2f36286aa1e92b62b22c98b1702732b18461fcd897b000000902564f7b6e01aeb829a03c67cfe9b90d02bf5d0a3490c841cca0eb13d43385c4c9a6c44e43b6a97d7a6cf823aa6212481eea0d50cdb78394e37ad9c208b6319a06c29ac7a4fb39f6512d2c7aa585d4e112a2fab41500e645f0e48daefea78b5250f0af39036eadd04ac3f8d1ea70d55552071d72c960f1ccab956353278ea0b73197f90fe7991a91617f047f265b6dd7b00000090ffe5b429f4cecba7f308784f79f9171cb8cbf0cf688af5f6f345d43f45f9bdd209f58424886104c6d8ef1c599135d142ef79c26de39088f5a6da5fc21ac20253dfd7f02c28a90b6f4f568f6fbacdcd360248c6500072be21b1a8a952e3f9f6429fb8a509ea76054cadede9d738cc880f037cc0726440fbec580757be0ef5f00860cb5aded77968531e3effe172d52a7e000001bc00000090225391f1f07678b6218786b0fb16dcd6f703fdae693fc8947f64f59f9ecbf8608f2b2fe7673bf7212adc28f930c6c679241913e05e918c1021d1baab8165c492c234d874565789f555f35bd44c057e021345c0508967c6eec0503c73cdf25e17c20d22407bb65dbdb2438c991aadade9034e536ce6c41c310897c7aa76570d36fe4580bc72140a977cc031903282426d000000905a5b8d400eba99dc5f3f2003a81b5c476ff36e092e77f4814fc902c561feec7a616ee7aa66bf9e1e9d63427a0b17654bd61d0515aab1329ab28bd5e1d778ed0cf4b8fb27a666fffb37bffa867c7220ea03da67528e3c0d1591ca330b61894ee9e794c8e5f50b8d6ed366b0ac5d78e7142d0293960d9741725c51cfb2ec7edeebefedb9a769256f0c9154725d3854d57a0000009059afadfe209eba3c172cebb6ca552534b448a6471b27582119547321032be5d3188fea33c8ed8c3d60cb4ed488d572515d463a2d0ddd3ef6d237a7658585408860f2d2390cd44c6e5c27fbd7c3a6c9e6238d70cd02964baef06b1907ec9effe1d7c3be3f6c44b725607e57d503298ba119ca39e81a27a701bcc23319aa7a31b583b2aa5c5fa946f762d40389029d0a8a000001bc0000009019f18b0993ea58cc0e60a6ab12d890658ffbc10abba2deb8ae8da0e5ed86deb44c46257de38fcd3a801f11f69bb609d282b440cc5177f384f131cb5b400e4058f53fbecdafc5235360c2b0a04bf1dfd2186e31047ff1c0dc33298124a02b36528ff0012e161cf63bbfe5e133c713dcdd182181450fdb65bf770a28575b54a147555d352eb9793a2f380441fcaf35cd4600000090eef87e9ca7fc37aa991f73e09b86f3fe5253bcfbbc30b979a631b36bbff441f90f292ad60eb2769cb54e467f63b16db29c06550f96c1430c720f9c2071ee2ac78e48b81ae4cf2afda75505db1ba072b00d7de00e7e8f19f99380e6c3042828a8f7befe8f557fec8deee36203a6cb78372ea43ef82b92e4ca5f36bb118ef05c6f107358a4c9d0bedc1e42b032b7c30f4f00000090a3181d013c7c27c80b6ed6302110e44c89fd98c2fb3ff2bde91a2dac237a0a8c1b9790201524d4add68c0e3fa6bc6f83be980bafca18563addfabc32f4e868736eb61d3ba99b0436838a74aa0f6a27b513c6fe8080533c1c994bc365bd66127e0518029fb0d1e6357fe95e72d82579390ad10e764d612a8176912a688584f119c353e48075e7c78915c043bc6f6b9c68000001bc0000009054565047a9143d945bec3ef338e22ef38e31bcecf35d39a8ad9a53932242e8ddfbe12625d981e24ce51cba092fc1a7098017110d642316f2052b6696ef8b048764b0ec7cc884d4d38afce13c5c3b99c919448e796f40205756f1436e1e5040aa0ced2f7df5f4427286a3b50e2cc8de6609eb562e96c664a796c6e9c6ab269f8fe88b21f8f501ba5b59e56367cf0cd75c000000909410338d8a23b6f386369356c3fa8e16937394e862b9a785af0b426a1bf893341cf6b3a56f5de26e38b57943261a636b4f27f08312cbee701b210e00abd3a1cab483c190251ce200b918cece007f6f9c0f0b5b31f9005a5242a724d86e74f421c852b6672b4d346c999465a443e932190fab16bdc74f7df3b8966d6cfc74c4ae5123dd6046f525d306b76cfd90c725b9000000906ce36d5c10f1ceb7973ea03a9d07348c09843ce95e9b46b9831929db43967c60534999bab1e4d6c548d1e967bb5035eb7750c28dff8944cb6056199beb6b81f4dc42cc9721ffd2a0ae94bfa83ca753b802f53b499f999cfe44cd302b87166848eab643805261ea69b1fa606d5f94bc1f2074659ece90d207636f508a701a85a12efe6a1e9fb074885b453366792a23f200000e00000001bc0000009004d2727c81570802fd60f39187fe8139955c3293e7eb446c15f8c34b4b88800b230e7f1621f1b4105a5830a65b082f4de456ff515b9c4794f474eb33778b47e82b96bd212fe4f3d9f3b7e4dc4bfb83881ac62562528d78dfcb7e23db85f34247a5dd9af7ee24f1df1d855a488b07cd0a231dab09e0487652daafe3f5b38ba18c8b8f6c56f998699f97440ba56ac4a3ca00000090918ab44e96807c203a061120c62e8d898f5975c91cd10a40c33a7b97c57e633ab4b01c7f9e8cdb2e9b2505804360d60e07d686e68a98d59965863cb231c5864cbdeb27867dc6d3d575f6311c890d651508153bfcb90f04d88d7ae3bc27455060bbd9117c98097375f3b910fa2b1a26f51f898b19b7dee695e73f771d2a7efd51f97a1b67fb8cc6d4cc2a4fdf1315dd6400000090b6e162c9185d396449572d19f140bae3832edde96355c06f28792f352c9e0f1d16602a80a9bb4b525b0b9ef68f4eaee1f28700e97120f936f7efcfd722f383f76b22b19e022f0ca46e885d352f1990602e73ac7a250e86c2bfda2766738e5385f50188d896bbfd6d125abdebe893359101d9779b506ca9ba4be0dc69899f0d21c92aca8b85eec4ca8b6e58e8882bbeff000001bc00000090eb3d82eb845cb36112c2f181665371298b76838e12dae58ab41723d1cd3353c26c32ee720ea35760272aabd28c3fbfc75abf24faf78508bf7cf1d731074e263b286fdc2faf1c1529bf47b1184b10a62116e49384fb35a370758682bdacb2dd518fdb3a9c95b472c400be19fb9a510cf11752226b7e1ddf74eba9c1589232ee94e9bbbc4079ac97594a18ab4fa42e8b8900000090e4796a030625a284925999aca258aa4388010e731dadd1396dd25decdabaedc1658c229b604223b888e096e04b35179cc499512920ce0d63359e3b00f2b876bbc1655f4e043e3e034f0c541ca9008dc12246a72afa3aba1fbdb8c78d39bdb12ea33310ccc648575924d780396e3c5670080bffa4e9882535ae82f3ddb54962e6a4ce4bc8dc969a4ed78d286c0712d7d700000090c639050d286dc2032baf8c0feef5a51b17ae5142ad49000b4baf316ba5a6c518bcefffb78de74d207bd52b08e92fe7cc3d53852aef8d6db07b8bf8d7b2ac3efe338882570d238d89b603c10d98efac5d29e4fbe16fcad139750859f360a169cb99767b8ea4a5e4b13e1213d330dbd58d03cb09f349c8746f02da530d5ff250b6ae4dff04e844236f8b2a716e128d8bb8000001bc00000090fbae53f1c4b11b030f6572ca0fc4ecb535cd813d5136a61ab5562695386df70413d4cf697f4d63ac1a59faaeedc8dad4d41a1a457e2abe9e5bbce156c2c812bcccc0963efbdcaf5697607f383f8c778a18a241790d2081fc2ea8f42ce362704be163677c8e6377962a0a571ac8725c6e2185d8e812b2dac85eeeb0f2a2eb5f9efbb8324b504d3c00d2da408a74eac2d200000090f3d302381fc23183fcd2aa4267c5086fcac6dc506b596a91df26e2d521cec254fdfc8981e36f9c1fc4bb0df11860e7761d4e0454d061e704b3f4cefe920f09c847612885592567efa4a762887c6aad14074c4d33f30a2b2f299869ea1dd678f72db17edce419c26f167b56d396d4cc521547b04937acf726763f2ecd3c465ad8330a76a470685d1762f46235619c96f800000090efc8705e36daa95de34bf56295bde86b2ce2296fdbff32476db7e83ca1a8dd0151d7dd1bcbbcb0073d9eace69f8bbcf93df2b6dc105330ddb49f4f8d61d1a55b577b3311c325c19e380a185480d748442e6efc007caaf50c94506d1c234f71eab1c19b2a34161332e426121dcd75f9f20dd18e29f55d57daed1aff739f5ab4b44dececfec9395dc44e620020cc46cf65000001bc00000090aa9507ff4c7399f8eae915959531729413f12bec3fd965b24129b2fb0129d1fba6fe9472084590541bd879f41a404a9edf78251856f242e8a9dfc625966695b6f078127499b10dafbac54db22bf057df0146631f3ee9b6968490012cb08275b03474d5905e26705e6edc3af9ac5cab0d0fe1b514c7d92fdde0724866c047d15c07c1807e58e7484c1f82daba3c39193c0000009079d9aed959c3df77f573a4053287536874b727627dbcd5b654257498f18e325f5ce1ec47dcde04471bc1d951654b07bf09f4754a09165c2a69280622567ceee202b61407411df752ca3890373bef274c0f080bef80811bdb9c04f37947fd762c4a92d492de473bea32ec08893a50992b04eda0bf977e89cb530067ba488842ca83711d0296349d674c1ac56afcec60cf0000009090bec024b80a113256a351d1706a64766b375cfeb06cdd20d7ef75b0b3647622f1cbbfcd0a60fc16d29dda344ce39108b8a98d6a6ad2582363f622e871c611a43ae5f098122fc747e6b7627a31cb6e9d1ee2ee99aac798d2486990af2c866b6b3f8c5b3af208f72ade7b51e1cf4888c81f88e8bb1e1af435ef29b251fe6724a708dcd602b495662e2aba9df00975b1ab000001bc00000090d65e642b9d1d9a03a35426c9e93e1c9321a03b39d51954b9c72d2b6a230e8951c7aff800ad81f7bea03fdff671fd88f666cf5b0e226d8de735cba18bc07538abc29d93f42243250f1e5fe0152a83f06c0cbee8237f842b4b6ce451b40ce597bc3c4a06e3939c5a685da56af2f6a3635a0a3c1fb4ab81de5eb4b0508ecbb43df7f5050657d79092250043db9efcfa6a3500000090a0dcb21a7cd02d72b1d18d9efeb0d1da493b42304a14e012228605e5f2f2a5e044b11ad014e87e114ba74e00ba47c96ecbc5d48f7fa74868bfe0c2e00535dbecbe7e796af28dc37c4bdfb6b1ea149bf71b39f68996b10044ced1872871d90d73a35b723f46064ec7bc591d13760e5edc2786029e6c09f2dd1399697b4513db9394fef770d01cb86c21351e18fd724ced00000090dd806ae7ff708846d36f9ddbb6c8f8f8903a2f6d68a06633e707c7be0e5d584f8f51657c46f027ff5024101798a3692a554ab3b8ad185fa4a321e64de7f6fa26eda8e4768a5b8358fd6cf932a138c3ea0c03a0d6b04a12d7a0984f2ae9711483c43ae205251730357842873083c2e19c1f2d576fa667d9d5384ea6e7b2a2141d46f3770bf6eb8aa659f6d254bcb55a7e000001bc00000090892b14aba0efdd81abbd79b8791e7b14fd1b4fa765bc40491e4fddbfa21054b7ee882f95159eaa89c28821a472d33504f738edfc8c04398a16e15e8a41558349f3683a610b049e72399686c61bfd5a802460fbe9225973495867fa3c43588a6c734391f87824aef78bbf4a201e7490a32ddcca538038bd1403fa260abb9e32d21cfe381ef680f4410cca678119e1c28e000000903bf5b5f5bce33dbe74db673db3f58944f456f5276fba5a7a59e93918380b1e151c1ba18cd746607a4d0cee68e36bd17ce577cdb7d18eb7887c7698c8d9ac52af445bad20b520a4bb1733d953d00156632de35bc8ab480c2dab17a10d2d0faed1e7597a45513bad38907ab546c75ebd3a2d69ddfba64193b6633153a915dde34823f2560c0468c8822db4ec69f8b22817000000900bbab109aea3fa753bd5ffb15326043f7b3a5d20d3ac6df24379ba28804959fb4f37dcdfa8c2b17baffb16ef63b1a29229c00dc6b289ce6ce7868f656a0af73cefb428854c07972026f38e45415f40542a8d166cc63ecf982739a3b0acd7483332373e979d16a04c3eacc610fa4963e50aa445b3c940be97a6ced2b5aa8c57f29eab7e4c8548515ce6c252ed733e0e2e000001bc0000009045da1ecba3eb2713931e0edc750f695b1f1b175c6b5c52b5d3f8963446f21e117e9ecc7904ddee87ef3eaf4274dc9ef5dcb0707042a7bc2052f849af4029c5ceb3e6184066d378d21f6506cd6f44b7720cce17b80c0fb48bc6486ce98f879a87c8d65131e0caa7ceba5b9e7bea2b15a82616f160655f922b53b5f32e7d78fa77f21b6c41be2237a7d5bd5763623ed86f00000090eb156a017208ba060689d4614777b3e026b5407a0e981a11d80b2000cba96a622036f63b58f94d8ddb4f3f51432cfa33b2974823715f1abe0b372dabfad69579aa2407ee91aaa7563593254b00948128216fd3efae361690f87eacd013cffa2e55c50a49895e52ca16991ae7ad631da81892664084cb1c521fc0742dc0732e8a638618e22f0f8b2316a8759377f438c10000009028c973afc8072005b575c14cca6bb159002d2024fc4ffcf6b4a90fc443e84ebd23cb498ec0cd46685f730219181b8ffdfdfac8573904bbe98d17096d347c9c8deaa6f18cb539bc7222d5a59c22e775ce0ae863c19c6388afba27d1a35a36ed79e759572be92591b47a92751a88094b05136517e0b93be6f56e431d32b906963ffb1bc9f4f4e7b140e668690efdaef521000001bc00000090c251c2887e122e6cba8c451fa308cc66262d76f435ba48a8f121daded6f254fc8438a1a542472ca5ddb23ab196d7b27c9c268a72d3fca4421272be7eeb7087c09919cb789fdb12606d2cbdd6327caab62a917b9f8e46bf2c83ef29dcd35885ccc9a1b0d88f6e6f78cc419399175651602d67e05de51d75535fec4c7532bd1c74415ff1b41c539a863578983fad6e0a8400000090082cb812c86e14b312a3e43d8560a673bdbde8673d2a728f99cca2b9e7217344343028a7cec9d079432a06e139bde2933fc59f0d8ce7befe6d5a7dbdedf5da00d8b564af7a9c0f159dfe7b8247d0ad57296828fb7fc593d279b9ce9f48e018d69ccda7cd6d207582896bbd0be7b9a9bd280f371cd9b7eac113d7017a1f48e8cffd8991a9c31fb59bd3d609ba0464774e00000090d13cb195beee914e24b867f316ed0a00e1f93ae1dcb1eea05c989770703db9870b8eb3fcce0a12674a2112511bf7a36efb1db8d7ddce9d2ebaba71ea0c79c26b204853d3e1070283efce7cf37ebd775a2b3f0a080652b55c71d984556754bdc5e74239be9a870bad98c9478a5e1f31760f052197f58a5aaae91b6cb1aa03d8aa3d556dfb16780855c3d67ea74e282bfb000033a000000ce400000128000000906ced29e71559289b41a30bf1c8223f7f5e190c5da0f18e3f2fb36755bc81632a23476279b21af617e3d5816669148c207bcfdabcfb5b37d9b93055722276f28be39fe324bd2300bf8242cad86eeabb7205bd36533c669991697f7ac788acd5c818c25e3dddc85b52244d0f6934006afc1181fccaf9c0671fff329245645cf57661f534799facd0b91395793e958799430000009061165e7ade49c3d555e2d506013851883f97491a11138301a64c23d06d36c60855ccdd2ce6b090b52213ac32f93a3c1915aa511aed6aec6b43d4889b7e8e12e349e3c0ccf01091ed55c8808debd2a49b2e0aa4352517caef9be648a1866a644d5c3232d04955edaae334e4f74a32256d01d668ac51f293586688c588fa1248ebb561579b8f1243f64520d602928193610000012800000090c20307cce2ad40429fd085e166598c6e159e2d2daefc9987319ebc658f37ebdef8478eb6420ac9462237030db7d460732d3ad007badf7923d27ede59fd9b76c82b5af2c60804490219e0143d168ee1032c354276018ec209d3840905d6fe7ab1d80c315c2353388c17a5bb292d30c14e0e8ee38cbebeb040b1b49815a01c50110577349a069232cb50749456b8542ca700000090c21be279d7112c8233f699b86da220130309e45b8f46a5773a71c119a9d39a45eade90aff8ab2a61e72bdb611fc799af18a05b3561d7fea5494538ee01e558afab7aef60b0eb51fcd9394c3385cfb0d423c767e83c2e7a1216f859776cdac28b14efc4ae43d6b6809ef2803b18d9cd7c03842e2e13d817c95cefaa7f8ed91e974b80b3d6917a946f6158a19df15a947500000128000000900845864a50a47d07297348aa259971ce32c2ef15021d561bb24e2aa4647489223667995cfd6dfddea6f658d2b42af8b818f6475e82f5ec38e8ef254363d8eaef5602e1a2d980c9f63b765836b8a436f11368746c397c46f8fbc7f610383947dc5cce8c663bd8443557c0fec48692f8b20a6120da540fa31629ba3ebb25da26a1b03276b5d659e019f8e8180a54009855000000908827ea601e3c88179aa5542ad6ca3e054d75359304fe90253f421e8f8ac5de67ca855d06b2c3cd0aa5b78acd7072184cafb9178adce066c2632234f2cb23cb6a06ebda3643f9869e413a6a216e84a29626b1114ba32561c671d54188e45a8323ac4b1660749caeaf154469fdb0a98e2303f50239d3fb942a166effc3f760d630d56fcce63bc9d3a7970893e6d343800a0000012800000090de481777e2521e956c1a82ca6d0468c95986b1b49915f9dbd3544f74f0d459466e8ce587c90cafd599075436e5e74359cec9887c81eeebdf1bea8672b5d10802d515fd85efa7d37a5c5b674ce00ab3522687ee41199561092b7bcd3a1e2210a882b53b9f59423495d3c793244e74e11817a3f58b2142475971a0802b8e1ff58eaa585326eec00da9cd7a92c0eb41a86c000000903cbb053a398485e98af097d1176385ecbc574895fb7e03c83c3c7044c266ca84d8cf849b1a4156b401159fefea93ff8b773639ed58719f3128bdf37640081d1a824ef9e3ec5d9ab1d45bbf92778325df15121af58b9312e2d8e5d0373245187cd8d6c77e0b4e67fd1c54463b77dd2d750ffaf29df1a8e2e798b6fe44e593097924cd52d7154e5b2626f499d04914fc900000012800000090e16c6579c155574b7fd4636bb4cacdd57fecf1694d69c94e1a72ebaf773209bfeed7cca59b3079e09c927f5161c91e335b6f72fc2e7104a459c5c7487de91b25a3355d2112104d19a1f2d0e9fec930b717bcf5da750f585642b4d43d79b87f5d7d275da2ef7c298b7bf5195b920a35b42c8afed45a38322a802a862b4f9af3142eeb31b23c862c681a691fc4cc907d20000000909b8015cfe88f81f4f5c715774601086214f10d5818f9bd191bd3d2137543fc500944fa5707eaaa85c688c7bb34ae2cd0518c2264d332ee6c577fd4d4e882c5e5bd2f0307fd9ae842c8d1d939b29723a92667f1ec789772e054311d82545b5140107b8c0b986b08eebaed37672902eb6e19719f5332e7a2a8180e2fc99caf06d8513a8401743d728de3be3dc52ce8eedb00000128000000902a08b6f9edadfd9b077990874240766afa3fd95d83866dd22304f569e2d33b657152708e9f227cdaf037a357ab0a4ff600f48a30d64d70eb03599647962dbd00f48a9ca96f99b8f6ac410eef7f2bb19907eb42623e48cde44d97064a5e76ed47e6dab6666ff1ea7956f1373d24f533a922859a39dfd5716a7ab2c860d4a893a1344af599276cf2804a6e3fed4b0e89bf0000009012330421895d95a9c8f0cf59381cbd42f3139a7dcc28c6c4dec85ad38d95e734e1149a9b6389902dbe08dea922ff800d6710ae3abeff66941ab1ed689ea8bd6a0eb788f7831b0097f5571ddc3d0830841e178814ecd91babf64d7c096fe4e985f7b9661753498f3f394df532d7631b431cbf7f35df92487a75c12a15251f6b0e73ad9295364213eae0749cbe2fa3b4d200000128000000909d9e2da1bd1ad0b265e7a11351d74a82f053e95d414e3e3509035aa1adf722b700fa7a68e1329d9906c610febfee397c5ee613b19037795585a65a8cc9a13fada7eeb7e68a533b673c4ab1ebf47bbe791a59536bf864b0dbf29e2186e8aa11a9ae564cdeb8e53f2a18b63bae7ae97c200006110189dfa8b9e94dfff867f314a1fbc03bb9e59bfcc9d496b056ec1dd01f00000090bbb2748be6a328c4adc4069ebeb37c5398c1374effef708cbc40754ccba78d6da618b9d26fe7bd0fb01a4bbe3a7a335019cbca751f8325c8c66f5f2c4609f91544ae2f405881cfc6038402e181470d1c01079698e5f2e36f6bc15b2aa5b4cbf659524ea6bbe04e04588d5398ccd3683a048f7b1489b0de7411cfc7cff87d563ffebf153f08584d55e17e304765eca385000001280000009078c5a1db7aee3e9361e5ca420122cf5eb55ab9697d0b41508b7bb179e6ba4f62a90074034bc48f91bdebeb988ce5c675dd0fc6e0090bd38cbf7371dc3457fe10828ca8ca90c393070ab65c81ce1134a61393ef5dc50be99f0eec64555dd2a12753939ec2650923c39f4856d1a68cbcb11037cf8db800fa237d10e4d54446f81231bfc374e6f84b431a88858e591f6c0300000090a920fad261e56a1e0ec1e816594cb719f899fb224fd1288a995571079a700b9f424b63a4cbfab814c3bc101dcedba4efcc8a4f754b0bae9c2ba78b6ee6baa71a24bd2ef46fa1157c48128c096dc709942f0492106bc6c3291da53820067cac2a9d12e17bc638ffdafe921f98e6df37150f627b37f6a549fec31c2daf649bec9f29a608ef138c28334b901f5146b63dad0000012800000090df55310ecf9a1052b12c8ea6b3f325d7fadcaea956437c6a08f5abc9d119c1335975343301985023f32c95efed3ba647563593f1570040135e91958ec6f1862b8a4db97e9703fd417893f918854646f1054122d0af6dc2ffa13c6acd8555cb07ea2a24b033b8290a6437928ce57b909d2a334328988cccc41d72d176224de78ae29ec28e1f5933ce55e88978dfde555600000090d3cf89eef5bde30788ede8d63de64fa16540e0f32f7a2bbf695c4b625fd9ffe14df603d49a8dbcb2d7ff85079f80235d11597b266a416bb52dae66bf24e644ff82c535a74e465a84f3f4546e0242b23c02bd93a36ba8cc649501f6bf99a12bbe6c5728fccf668fa2bd58ed848085caeb2be3e1dd5887b76898d01a6db4e8e4dadc3b1e61cdc57a41b0053981250116b30000012800000090fc86cea3d4aac5eb7dca669d076b2fd061d00e48d28eedb6873afa7b40366e4ff82e26adacd233c8f001921cd3258045efe30bb813162183402a371b40ddb88c2935b78adc21554bf3f007e4ee7d5e9b18689e7b5332a1e05ab70856d743fdaf0fa9da120870cbf04d918a65f16a885a1c19e721585c80691c65d097b6c8c92a4aebd924434c7b6024de8624ece384810000009053ab5bfc42c215b93e1ff640c24d7d5fd4036074d9c8aba43605458a90708559cab63e463aa20871602124e6e36405ee046fe8e82341ab70e1737325bee25f63215e11fc9d73f2a808c0a9644216617715d11054eaf640cf796b6746cbdd3fea488418f52673b553d35dc294f69144c30779432f41b7f8798bee222abd4aea7d3e148793dc477f1c45f57ae8fb6d42b900000128000000905e6e31986ce58e8d566b22248dbd8e742e36db217b7ec9535411ea2ff3d76aaf3b3c3eec489e754063e34fbf5ead13001a5e6f97635565fcbd8a5783d63011e21a823da8bdf690eabd1f75f76879fbcb0f49e857ec71a4ce840e5b0f17918a3a6a8aecc7ae60c921f29bf9857ddcfe8a0ecaa592c24c54eeb37338d671f16c4d5004ba49988524f6e23ab69c807d36800000009012fd8d0c10354b223aaca3b96c3ce882dd6bcc43ea0e79427324753ec7480cea2da54c03241b79606f1d63c330d26ba0b345727e2ff0ee6f1cfbd88bdeffd09bc05507f80111d163726655a51b8ceb692684a81eeba49a4b4e57157231b8338497c267c6f1c184405e1a7d3b8d1561dd22648a8f46a9cb80d858f834a880028276cb70268d5d9427ceeeb5294f66b8f400000ce4000001280000009030f3472bb2aa4afa7f906870a30601b0b42da3696e13c18ec49a94ee262dc1b536b62055c0e05716ad477dc3389e318fe164622664f37818633970b6cb54761d661e61e5b7f1e64195d4ff430bd0d97f2a9c2680803a8a65763022365b7defb845cbab0db45c28f0cde6fd1647040d8f1d08bf8fdf52723a1aab2ad7dc880c9d5bf5b37ed2e80ad5c8d7f13d822811ab000000906fd356b5b6e84cb93c5e067bb5d1ddf99fbb95c87de4a281ca3fa591a0d04960bdea46a9577d1196df1408adfadf1c5ecb273ac874df29c7adc3eac64d5f9e1494273ff4b0aa9dc996532693a66ee85611430e5b22cfad17091b004a87acd321eca932c9e744d9af1543716240eb6853191cd9485100f14fd22d96dcb3f03b20314399ced282ee408fb7eb8d43db77b5000001280000009098132d107bc7c0a5d87728dd6fb4727647e2f4f2cb20fbdda9b9585498c5c03503050a145de389ac72e59fdaadbd3f3dd2c0d853576cb5840d5b0d3ef300dfc94afcff4026a65b3c0825a72017505e711a8c45008e3b5bced0c77908f91c72e0b35b985c12adacab86cf81f2b20187db0050248a789b024b3bfdbcb94b44bddea4e67f1ebf2130fc97dbd257fed593a9000000906108fbe8ea485aea0c3b9dee478d8a2fc395dce9aaed16e08e53b456b3ab7827d6d5a1973394572f90771bce09d05da2992366a7970ec6930a6616d6aadae93c6e2340452c3e46224d14932fc7ffa1a825e7e6b8cc504243e76fc6b52f05aa4830fe7f1e30befb0c6a7efa1f8327842815268491e75d595d08894a3cba7a8b310672fbf79d627cd13744ba6fe52c33ca0000012800000090a640b92d89fcb69e2c200102a972ef00aef23169986bde7e450fb2d0c9850d641acde236c581cc72761a335fec7b27a0fc2bda3504d8046f2a683745404cc5c880aeba3f16d61377fbb723aec4df3a640fc3d6e318f2ddbefad52e99671434cc4f17845a5e93a51487a0ff6b48c68e3414e70a9c45b26b02e540a93fd00d3be97eeb6af5c4e68d2ab48458d23de52a33000000906bf44acbfd2b3aebc38aab3848c867de4c3b359d01193266e6303df1f0ff84430eeb64a1be407b1601c11743bd6a184dbb78e5f53cdc8f227467db585c8ac477193fbdfffb1b4288cd197687bd1d872910cabf3c02086c10f49c414074b75cd589ec279e7edb1d0a5535668893c7341400c73b5350471521e780daa529234c8c053aae6b2eb8ab29fdc0ba78aa6be33300000128000000903622d289412b4951637f9e55a801d7a6a00bce377d288e36121837032f05b258f6921547a4c5b410f30c2125daa1546b6b8d336d82ec74b388bc719d3d34c72347dd83315b121dd320e3434b70b0de482f71e50f882bb1022f5caaad860fb6e2b3e843837dfe28b59955a7725f9ec9330ab23a886f6883f230aa74854695a30224d60e0b4f4ba5fe30c19ef0751ffc9e00000090b88847e072454264065439ed169f92410d4e4654a0b1f39832dbfc3be28eea464798848393e82534b5485828429af27e5166a794544dad0018a9e5d2c5826cdb5d0334fe9f9ef469bfcebc831769d5872c7916e0a8a87c44815b66dc08519b1886fbb45428d83772e77e5db38d44dec52fcf3be71a84b0bf17c080930c6c0119cbdd6ed061a2225d3f23cbddecd36ecf00000128000000904201e3550d2e1f76ba1068c82ec0a67d690c8e51fc9f68c7f36c81263d5ddb29be32e5e3e3b9664d9bf4c4363436e7a41749cc645c29150275f8501a87a0174371cfee4ae8df103d59b0d0b75d7ac10418654975639bd6b9ba06cbe79acb60ef3868b697ddbfd2ed661451d061c3a25c02cb1bfea7d3bd2ebc0f5f0166c649562e96022c6d14714d4367c4d3763a6f93000000901a4abf13152779f3020b104add938d7117f3efee81c8c129e864e087ead16916fbaf4c2f36beb51e706f185afe150cd005ca9b0ec51ec03757c1e43def29e24dcdcad410a5775310b3253db842b7b00e2f772e81f0d2dd8c3ab5efd0591d8d772994a9ca121fc0e601810d87c38070ba246d2fee20ac6b429c525f1528c4115f357457bb61c3109edc71450019e95b2a0000012800000090af135c5f86076eaf2ff68254357089aad9e5feec3a67139dbdc62da177032337ee03e6eeee03c5e017fa6da3d0bc05709006f68b11c277f52f2cddaf691d4fed83e9c46ba62d8189373724bc8e966e850458df493e3c8762e69154386f1cdf20fd5b1515c18ff7dd5e523aa1c167eed52acae16139da38501a6551c47f0743227600e0643ea83b830acf55497c8f519800000090af3b415745232d4b810cd1371c2662441a7745ee6e6899f0fe89dfc88e5e377f85e95bdac825a1d5a8970ae68393b432ea5c886eb848838701adc656330cc7cedd54270324c524f4f7dc46f8dcf48b0f2039a5325bd816ff3b57871e68f153cef59cd172b3dcbe700d0eb44d3cb5820f264ec501f59a78d4128c39fe2880ecb86bb64c4b093e4495ff680f110743059d000001280000009039fb70ce62c23dcfa825a7bf89053dcdab094f14b3d0974ff76cce08f48ff8f7b63497afef0b281a4f156cf0af29ad59f5d36e95eb80d825ea4697ec7f7f710c2b51790b45462f5f129310013071850d014b07614fc802068f90631cc7e0ea6b383e40e4f19b44bd0d0d7d522a8d121a0e275c1ab5f6f9b274ecdf8d280f9750173f2f434b994c2ece09999cb0501ce5000000906d2141941550893d8333f7a1a0a9af9baf9f6e737b71f07db67cf1283b4c939393986b7f0109dfebedcdc19c59e000febda964ad4ce208ba59ea2ef2182ee787e156a18ced9510e50cd4a177220896c716c20c62e0ee3803d408603fb34d70de2880847f829e5ea6c9e4255f3f53ac091d2ea4960b6a99c63b3d58056c861622cdadd11c0178d13fe271636c5686cde10000012800000090e6e105147c3ab0f1ed9f425fd0d8beab8525d5efe0a43872b36b8fa9154e89adb9437888d7c316d410cd9fef9b5deb1681a254986bd1c2be16e5b465af02349c0f01faa6c7331643c9a1ac714654f0a02a4b6ccd3839295344c5b4ddc939084b0d8ce45b9c922dcea2e7e62156a265f104cbc24622883bbcd114b3103b0e4e7b78c3107b2575eb05317f27eeb59bb35c000000909190ec9fe430c035ea72f17bd3bc0b3a970ab2059e32bc49c0a5ddb1d278738d7cdfe01e920411a977934e18824300c9d2137947fbb594137c70803fe1c9629022c3d6ed77c89f35d541116240a803000cb6f57a124eee37947fd8bf6f66cd67846f0f1f1576f522f5f96b2a920386ee208ecb88b3bb9412e3fac2970ceacdc5cc06cac0cf2089981ae0bacb3a1b7d1700000128000000903a28ec3706d2eef4640070428bd729e97b4abd3dab30b987909e5cca650600079c6b6845f201ac65c5a3949c408c2cde406b2d306ba688b65e3c2717e4edcb8b2940fe6f48fce8788c945fdc283b60c2208770380b05ecd318ab816526d340e1d44f0e4b16a7f561ffa26c28bf7779d4052acb479b576a5bbae956727227887eed77007a37954713abb709ff6531860d000000903b8a5676e83b32e7f978b723f1accf0b6c5f191876e43ae4983db637bb1af8a4c699bd1749580fbebd38cef2d10b258f00166f71b14bf35c1c98336cd133fefa21e3b89fdcba4f34858f60ff61f02fa51b23a65ec2bc0434af82356f00751b054ba478b4872320543f56f082435df8bc28a0fbec0d9f1699cf85fe79240bc01b4fa41934ae52f3dafd57db6b095e49be000001280000009007b21328b8c8bd7d2b7ea9db1c48deb7abd40e7e5987696d90d0bb35f3f4d8c4cf515da524a06390ea4c29a7581dbce23d174380038045d19681479f9bbe4642280605ee3ed024fc475e180e376f5558028d37eb5ce1a75ce746d5e5f5d64ef0f888006ffa49180ed079a8cccc22fc830a2b1571a64b4644671b35c7c9fed049d889622c2ac19cc8c9e666dde8f7487e0000009013ebac517052f806e3e8a43f9a76b3fd8014c2c51bac75c18813d340209a1f8f49cde8903283fa0f6e57f99538d34fe76e2c2ca622464b2adb4105235645ff068510094118d808a86fe0c57f9c0067ca1ea8d11f1d4981a817216886744bb09af6f1f9437d0d737b3bc8ab7a277669f711c767ecda7972525d468db22be9c49e6e82ae4d6b053d753046689f1f6095ea0000012800000090624b9506aa525b6d6889e72f9b026880f244534be16924cb6a1248e5450c770687a29c580c5b9ad284ed9273486a579b703fe1c1bf5634d2762460cdbeedeeffda11364f71b3160fbcb8a734b1ae882a25812144653da5a24934286afd0be45c6f1e0153fe509adc5d741340513a826c111df48f270168fa72ffa3775a9a896a782a7cfdbcec88d91f0f14942c9f0e8a000000908839817e7303ba863689869f4a68b545060e5cc4a2680c20f252d0c5dbdbb3213cca4f412c6f2b935e561b839d319ef7a33fa82bf6106110f3c90f0b79ce5f242526f3b84424dd0cb4921494fd53e50a0bee29198df55dd02a54dac81ebdb9b1cdf9889154ffa5762a27696f1368faea2b84a7dffc567c61f7c6a87e082aa3f80f6acc2f16f2b3d9ea54e26cee5b3dee00000ce4000001280000009025e4179a89f006c7561f2f9db9a7375bd6e014fa0478234b1f56679d353489b6c5f499dfca964211832ed03f51b1262b4580ac1e68a534752b47cf2f7798aa42da358a45a3a6888bdff7f174613675ab0ff2e00e2bb76111c569e761440794eb10ee13f6cf1130fa680adab60995c55c1b11b85387ded9cf8fbd255e97d80040b0de541173f02de16e87195b1293a4490000009069416623e8132febf95d02899baa57788bd46cbd1b46c1db9e3fe4498c32ddd372b59f8c80fd9787b3b7adc70a2e50f4dd3b79f8015eb159bd251eede3013635d72c8a105813457558e33262a7f08df21737ac4eb5b7dffaa8d8e4e2f0a4893a146974112f8c3d6190f2162b6f89928504e99551cad7da3198cdeab46290d4fb2d427dd9975e96b2cc6394c85d399ea00000012800000090fde0a703c4367484e2d7452c7ac078b8e59b36c449f09b170c5eb35e5c7407cb04d17840ff92217b30f280b7b740d265db469c41baa3e9bee4bb8767b552076866c77ae3af797703d42311f7f13557b71ac51641bcffaa56fc7bf4b851f155e0935831bb9e362ad98f1b172b3b0bd67b1f5d8e93e1c95ba553ec9d223ee8f3b20d32d8184115af308218d30128803add00000090eedb114f15d635863740f6f166cf200c9abf5a0ba790aeb48fd25177e2a05cae44be9925926537e7b0cbd199c8f5806bc01ad1a921c8aa22ea6620e7b48f51d462c708c3c1c98d5c6cd5765849ee580d1556612d0017c5824430b58b42b40997353a5200a369497e1182e990524c7c000b1f4445af9513fca8bc679754451e6681828d034f7de583d1f106dbb1576aa800000128000000900f5b0b1a2ded4152608ce8966a39171628dcb23a03f2184956b537f0920fd4d01bb19d06a35f2576b99f9ff31c8fdcb0b16455d4ba4f486ca92cecb091c33389517c98054fc81a7c9d648fcc62025b281215827d96434c2606a4416c11de6ff75a969a67e0548e8e3c36196225be2d8523de79ffd1224e59f5126287ccbf9981da6cf746853166c7b8082d74ed3754fc0000009077f89fb4b68a9f1ab542f23f2c45f77709d8b88b0e83a13abb74c9ee9c9b23e29943a931091498b1cbfbd4b219c407b8400e61ea0c47ca55dd8c55cfe6a0e68bfbb9c5ae4c22cfd85dfe79f0f8d7add12d3b87c82b19851e889f571218ccc80ad9ed5cedd60cd7098459ce34fd231dc01ce4dd7153efcba4432ea9dc48e1acdba76d6a232f720e5b3a0d9ef82c6f84940000012800000090658c2fb8283c73e49963439e6047e80cb73ab3159030a1e8944caef2d028af220e15f949472071a9f815af8ce3d8518e5ab7d1487c7ac1218af2feb9e452f65569bb0a76d493a651bbf2b07764af2396208a908d4c81553fc7b813074daabd0c2bb0dc5c404326939e243048e0e0f6582e75ad5acd36c0bc2d47eb922c4ea97aea0030b346cd362a15823aae70330726000000909106f34f3216567269f250a7aefcc379a5a5f73491308209fa4545c9b12d505f0b6cca6304b55cfd679fe153771d69fdc174e86d5505f7538f455bfab5027a14c1d0f79e4441c49783c3687580d76ceb10603aa326d144b193a05a4dd6abef19cddc19e5c484b508736bc5f6c1f6452e15006b0608d7b76d504041a888e8019e2b2e5d59e825f3bf803ec89863c4e95000000128000000908f2d66f61c398d081d91e0cc37b113dd1cf63f37746219f040f08f81183a96c411bd805993055d94f9a2642affd04150fad1022d51e4748ffc5904fc57d4a85d0d0b1684db8617b55255e327ed08749e1d938d69aef70f4a42d3f4096e8d1fd0c22fb303666bfa66851aa236cbcec42e03b1cbf750519018e1db2ad8e4c7ec8e79d8916c5d21d06efc4e497e89ce2db40000009061138607fc1233949b170ec2c0fda3a92bf355c5da9ee4b7dc854bc3dd4b99ad56250fe95b32d68714880174355a85b7f504d0e00a93b4aa951ead1809bec41c85216f8c1bfa9ee91b5198949c68066f0387d32bfb9df687e882e2434b6d682141ece88a5bb0d529e016f48bc37109301625b044c5fa7200b56dd1b64cf238adf700ff3ee89c32a2edc2a5d2bf483ad200000128000000909930bee5b317d075ba5cbba4c8ab537bd0878e00f1c9c940d39beaa135fcc9208388cde74f44f55bb44d8a6067f7867dc92971e18e71c3ff54868db71f73df74207cb533e3e02dbc669fdd5bf27d8a89042cdffa03ff863617453c97bc9b50acf0f9729a283057555aa40a1f364098a9033f9b3e622b53c73c8a2d6245b32811ba323e37832a36f314e255ed362a46d600000090f9b68a55c28a7b95514f66a48e4b03574ee8e7b633b11645223c6c59cbe5db9592d8bf0eedc05fb9263dd076d7a88da4fbaa717a80920513b9c334e10b650a51b0c1a126e3b258a60457be4b7f165b2a0eb7902766aeae1699361bca6a1b99445a75d424c26ec0a4d21032e554f2e763030154d3a6569b962080a19c54e0ddb70f9d20f42d97079bc47b1f0715d876710000012800000090b05b85d84802f2d9c7e94a96c230de0b96e6aa81841cbc29a6c9a1431956847e8fab1c3fe5ea8c24122ff0bb34f6f51fd13deecdfd683e06919463107b54a092c09d807c7a1e9659000af33fb522e0d72a502e4771e499d8363ce7862d905d871d39b05cc7cb5cd289ae9ef4e2f0b85e0ad7df39f1afa28b668ec85d5ce28bf2c2f471b41c24e817949648705eac1d9700000090865c148a995dbfd76f82090b6e7187e665aa4f003f76dcac21fbfda3f6d3e980de7bcf4e870443e5cb8c44d330fc5a45cc2d3b8f545bb8c3156a7d35a5386ab0f37c3737d5b5e06e2b03dc2b94faefbd19bf102dfbb7ac31e502ce4aa05e0160bdcad6f5825fab8c27edd151420a9e28076ef7c36e1bb3c12b183b9583bd82922437045c95d90b491c2872f9333ee35200000128000000901923f96f8868c7e823671f03dc0ad821aaa7d584a8df286c102ba498b76cddaccfb1be4dba3bf8ef4cc68083de9a2e0ba54d28fd2c1b669f98416d84f35fa3d6629d2931d033f8c95a6223c5a0d32da127b9c0b641a641663e9f18d05a68ce7ed5ee82c661cd76c42e2501188897d26b29651201b725415d5674327977266df140e3ca8cebe0cc52f13da6cb5e76ba4500000090d4c3cd035d1089a3d2d3d70b9995cf63418da271a2830c5dc8e2a6b5ce5beada4f3aa71aa102dfc35cbbbe7554c1cf9c5ac6127b55076f423d56f4622ffae47d40adf14d672cff3fb3a15904437111ed2f04363c8bc4df171323ead3dd793ac098acc8f1c3f1685628cce426731cde6f20cf746c1e75f261c9eeb8c6912e587ed851c5d706707429a0d61d4ae839091f0000012800000090131088d98cd6cf8548a230c77e0cacdd54169209cb2ba9ae8beb9880dbd0484f6e3ab7f05e8271a2c161562f25d0361c6609bd5d846546c1f7300f535a8b244d855d7a2b751d32a1629d343b659336ed2349d52ef499bd19e73f9675d0a934890e702cc522cde8f9decc1306e48dd0560feb00a244a14d299f4270f4c8bed06e32a898a234f0dffdb4316fa7e814726e000000901bd6fa36327143be4d65f1ea02bf932a7d067055279544b2a922251af080bf87b207108d9e717161e41721a8020d13db9e07d93293694e4e4ba5ae88062a0181a329db4e5b087710c88ca915e516f1ea176b4dda8bcc83229442089af7f7acb0202bc1b3d032ac0d9105c8c80e5817912546bbe34f018f11ad09f5b1505a581242fe198fafefca4b8e7eeea30c2d03160000012800000090b736f7b6e2f224b3e7570f3f494619ae872d055f6183642a4933e435823d1962fc427256a0610cd81904592ccd45a9ef4613e7da8d8acd1a321f32fb60bc041f7c4613b51c7ca31128a9c2dc9536bd6027766dc17e67fdbf5afaac90c495b9a3efa7c13e10ab3f2e0589039484dbbf60116225004034c411594e2b111b107e4cfa1992d75fefd31669aa06d5bedda6a2000000905f29189ba16aa5615d50c871ec5fd77b0f2a4611984b53cfc504136e06c719ca4f9f5bf54e77cf861f2b2a0aed8501987e00d38166b0855417c31062c7d093ce4f7d444c53e11af0f554da4a59c82966086900c174d97530fefc2250711d88f733f5b16bd73811077d6715caec15e928252b1a85ed3d33609e1404329196a570f911d28639bb67206497a9ca1ba5a7460000012800000090b9d8da40a7e9373882123dcb553c8ed4926326d914feb1f0e724cef1616990552da304f2bbd5ecacf60e1b4fdf6535c28089378cfd500f22de3d62bdf7b52126de23cbf2ea09d7de12af2b168dc9406c28cc0435297e5a7aaa2113ce7b9b87e4ff3d855349e974f019132f3d0147c029162c39f38f83f18d3871e47a20590bf5e2ce92637924ac32ffc8862f29db695a00000090cc99bb3dbb2008b94591505ced444fa0e0f5994d5bd1544fedc76d1191097cd612bd7bd45c2cde7010bd0ad788c4c78bbd75f91bcbb6cd221df3b22f475c5b26e5f3cdc905e04a95904246a3ef73a8972ac85096f0ef02cbcacc38fa329469080b4080e2a9f34ebecd578ae79c53ae7e2d0ded061af7fb0cb654b6cf6be7bdc4e0d641978f1394451d12ea190d8c5e7000000ce4000001280000009093e2f8635a045c41c8d9257adda690fb5beb3a5d56dfe78b0dfc3e02be2a104df2ae35d92bfacdc93e35a8f166d24a1f97499ce93faa066176bc1f06a73d02311507712cb1ce5f04c63e27bfe3c3e0651e9c2f13d5cebdca4626f083a8f36aaa65aae4c74d704355b727d601d2305bbe0a121bb2ebc79160f5c11a8f9ac2b69915824c413cc1bccebab0f5fb550085ee000000909bd5f2117634bc2eb6ac1558ee63de19c9906d306a91e434cffb75722aa6b2b2604a84e4ffa075d03226dc5045b16f71f501235820340e4da21c8b46c7b2a4e61f1e0b69cb985a34257c38569ccd0f1226b948e0f2ce68b0ab7849e9728b0517fb9890846f446661a335854e91c14e83302f87c6ce77d02db8e81bd3ed3fcd9dfc9a2c00ead57cf0b147b65512681fcd0000012800000090c0ff69960190678d193dddb5d32f220bec1e0a9ec238240925558cf7dade6be9038dd0039f31513a96a05c05cad1d883f492d42109006e18aba86c16cb6e0fb876a28df71d8e89fa02060bac14ef04cf0e1e34520905dfa33602d49a96ca766a2b46eeb514153c0f13e057ca2a0ee0ec24374b23c5fd922cb266dbda4ea04b879baff83583e3eeb12831fca1eecaf0cf0000009014f4354e9f6108f7ed4c06e8b6f4ba9040b9261d6d22b677d848590958d43a5507852f3acfb45831a25f4dcbe431ac979204bd0dea3f6623c04ddac1870014371581b84ef68f307342c25569987ebf9c10c8584ab1d72e995795b38b52ec6a3ad522cc1c9517e05154e8157b1d6f87f02a428d121d52569eee3bd8bdd9b330500e882390d0fad2d419755a17fc27213300000128000000901c0728fdd04973e9906fd1b541bff24461f9403a97802a8129ccfbf0bbc7cff8f81cb9fec321e2186365860d08202bf3f7168a618eb6342fd117c213d9d6428fc1537d3e8a01cd4fe21c0442bca55cbf16f3360c61254e7b2d089f38eefa4b283d540cab1e674c833f6f1d98b39369e92989531b35d6e006557c2916d7cc7bc5df35be0d64c8f497278ef232d58093a900000090be5eb11fcb7229bedafb364856d9502f66506f9328fd44644880c9e8e183ae0c861b7720b70af77271bc72291abab5963445b8be8ec35a402f5b23efc77e49aee0b6c65a99bce778b5627b5fee60a0c42d8c9cbe8e39bf439608cff529602ccd005c151987f7bdee3a2bafef9e0dc3122b46d03f266625d5ca0895cc527b6fee308661e23c20639c9bdba02b3ae71c8f0000012800000090ea504b252805bac5de56d205a6297cf38a90d101aacb4538f26a41adf9e120494e2daa93318788a151777b0e8fb5e0444bb0de040f684b48e113a3bd7d43e280263fb782adbb690053923bb0eaa7c0f11d89cebca94e1077de29e1f13450017f2d39e5da7b738a58158467680b87e8a916c6385cd1249ec51e5e2922f249b107ed353789e24e45208805602f96a432ee0000009009852850c074a233370d7d9704885ebbf57d13ddc416cd3809d7ed1591b05f0716560e8328f1efd042a4d1ade629ee9b693ae5866fa1f3970e2d91f41a03250126330bd6e27fb64bf6312c7600770f542be1632e295fb6d9fe45bf91b1030cd0c3150fe3f65ab4d1d2d017c3839898781a6e1eb8f2f4032f4dfd5f0a600ef72662986176bb14b4b7a9c99f66f429106a0000012800000090b9927e80cdb316ac5a9e7d5aefcf6ac01d489ede79e20af58377baac0bd74a49f19db328daeaa5ec07d4ecf7ba55148032c4989ab1f8c30d32cfb74d7a10dc6b9b3b62dc7a27a8db24688e5683038a541f38971f13f8da2bbb892e010c0ef93df1ed8b7a960fe65e7efaf2f274f3869c1afcdcc299eb2080c41e9c5676d524195e22e79730f662f20b04c5c640b233550000009080bd76f074f19aecc02adb0d7b30514b3878b31726f96fe25b68f1fce3b3b191d72f4139d497900637e2c28643f24f581949d196949acded4c29a8a6e300769e5c58d1cc5ec8ccd76006ef4c20d700c01747378dcb6bae7af6907dfc8ea88a7c23f4eb3d32f33c6da243702b6f1cf7f8155920309ef26019c05564716d2c55381a86bcc98712c7a0295832c9770eda20000001280000009011951b508ec3fc32865cde3f8b14e4314665a92561b35282c4b5f1261ad1e28e881900b80d70dc13e96680a528c997f09ed77899928a287f17a8eff3bee09a839f851153bdde9d1577a89c9d48c74f6a0557849194971f6237e73fa31f725b2a1a878914521b094863164d5f5891b1300c41c7999762752ca2adcc89de07f4e1d9b3ba5a1cfef2204561563c5c73901600000090ed0097c38e390151b701a7ac242f6e73c79fac1e0cf1dc2f66fb29c6002e0f6db13a6d6027cf18c4e6308caa17da58ca8d48acc59805585ea6b006facb44654f6f754f9725b685bb5c4ded4de2c690a72aa7923dacd13f83722f0893ebee4b3ee8ce7b8a643acb94ed2925f282ff0c4818d6a0713c5227e13b9e28e9b58cc913d2e66750c5ac23e16ce76598472d6e9d00000128000000907c0e86120a5a037229ee9c3a6ea20bf194396f08ded24d811339ba90f1ae02744218270e0b2f3115ba455b5409284da7031e56eea2eb96d1204eb02c2e6ebb8a0b4f3e98847607cb6b2279958b0197e52ab0e29034302cf56b533d3157b5a419665e50428cced5f15097cd3ec2ea34951d7113c4a2fcf976adc69ae623c2557c19589c89907106001f1b25d2b7d9537c00000090745e83cd5102da600a92eceb7c2712d2ea6704b8a2cc7105dd788ee043cc0f0b23077b5607903c7053aa17c4986e4e9e8c3c9767070b6a814e6e4a89c904b12308c11a09cdafe6faf48b2630e8ad24552d5ea409a7ad8b4b9b117ddb852d61e70d25b30f70d66e0c7907e5c16c87376209020da80311afdc646841e86b55f89c920bfafc0623fd73585eff854c10ddc20000012800000090a626f21ac7482cd903148ee4fe9fbcb0bb37c2b0c25f78682b40d2c65212b9f2907b0d0ba6b357ad998ac2dacdb23a6d626ea1f240967b92a3aa492b6bc3f09a57242e4d2a8d50636f6761ea8738488b0c19b34b570e8823b97dce37517dc9b24639c7410183ef3261a85fada34c0ca510ff73ada4daacc553482d68d672cbb3f674c8f2f0751a37245edf6d5695557d0000009092b9b1bef2731730812331aadc03fdc1aa7603e10f72def23023535b475b25182ef02e5bee562306197922453c7e28c323463902cc16a0295d2cebd6e1cbc85715e8dfa9c8d9ab7ac810e29350360bce02d3ce1075f6198042f4b657d834594564a00700d5e457e7838a00b590ef55550b5893c4bfe5f65fce253caf7141e83111d74368eb8eee18004964feb64dd8bd000001280000009011c36f8adfbb22c9c3d657f7564ee4eb30d37fbd30907b2a0561bdad676980ca96254999cba01fa8050a433a1d0ec2e49722eeb016279c2a51469725498969edc938823df02655a402418f3a6b8a28c70d5d89a7532bc47ab408e4a634bde7976bb2def28668d34b131909defd9379ef0c3c1d4294e1ff613c7423ef3b6e575ee39591b9be108055714df1789da636080000009004dcb05ab956ff0b68077fc113fd949ac3fcbed71a7605d42c3a09174a6fd573d4f66e407e468a1f51fe670b01928a1b93179fee05fd11b661f14bdd6518f61f5e0bb6aa55060e1b8b3a9985cf9049c41a999e111b4a3c3422fa6a55fa8f0dfbe839a4d5f51213c3915f1f6aeb85c7d00903b9c405878112fe5263e476101e1b53a2d2804929612759e2b5354e09ca4c0000012800000090305141bceee489d00e1951280d90286be9dfde8a0c23e802490da8807d919892fff6dc32c9a66663ac0762043b0eb2376390aa1b282bae4d337ad9e6f41d6720ee0f3d0315c1e19b81fd2fafae61de5504eb79685817659363e38f998e7ec51f77fec0f60474e14b5ba3bbe63bd3874a0dafc5fcae9f9258e277597458fdadcee0e822c56a55248acb3700a463154d69000000905a754dd00b1c72387b2b59bba5fe3ab77cf0a4538ddf9f8f658db80c6ec2a1327637e5c05e9ededd5d4da46f842feb545f8eeef74fd5a5a214eb5bc46966c44040e5fd9d2a87c2b15042f987923722a80e7d3a43fe74774c3681b1c792a34fb0a4f5de14e1c6f5af9fed1dea7694dd6c296d23c677c781280cc6c2970227eaa0ca6d690d1f738e8ae5ca76bad02a291e0000012800000090988af0a1f57a9dee97278df9b1fccd62a21cadfb56160960eed6abefc95d5f0fa96cc2e3bce75894bff947d855309e264c75eb95c4532de49e810e59abc43ff98d08fdb9e3b0f3ae561e033983c7ab391f521efd6af2675bea296cb4f257850de0e3ff28205b935b76b05d3584222e0a067a336c8be6a365c107fa95959563cbc11a1c2f63914d41bd5c4b0c698b0d2f00000090674e68e7621622e4a22d90d7aa2a1651bff1b53bd4b9f74e4da2c3a4bdd05513206950613958362efe44c16cf3d2133419737c395c0ef4f04385ee580a561ae1647db60f3da047b382789331edb670be103fba6587fe6f26b1cea9bc26820dcc65ab1a9023fef37e8e52f0cdf5fc69c5083b8f5855fe15e138af8136188b9b0b2d80aa2a60b895d4bc1b0ebe0e4121e3", + "calldataHash": "0x0ef928e73adbc5f53790a7591f274b0f4179a533e21da23f2ed7defe5af7bf41", "decodedHeader": { - "bodyHash": "0xcd9a7ed1324b15c82eb2b86042643cd52b67ef1909cdcdefb26d2073d8664a23", + "bodyHash": "0x0ef928e73adbc5f53790a7591f274b0f4179a533e21da23f2ed7defe5af7bf41", "globalVariables": { "blockNumber": 1, "chainId": 31337, @@ -92,8 +92,8 @@ } } }, - "header": "0x0000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f51000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a2000001801a3d3e40c90cd24822b9c268154ef14d4639febdb7af81b554cb2d651b88dfb100000004160ba3a7c15d7dd592a24b3f14bfa76a0b45378877d4dedc5f126f47844b99b2000000601a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa0200000001cd9a7ed1324b15c82eb2b86042643cd52b67ef1909cdcdefb26d2073d8664a23", + "header": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02000000010ef928e73adbc5f53790a7591f274b0f4179a533e21da23f2ed7defe5af7bf410a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f51000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a2000001801a3d3e40c90cd24822b9c268154ef14d4639febdb7af81b554cb2d651b88dfb100000004160ba3a7c15d7dd592a24b3f14bfa76a0b45378877d4dedc5f126f47844b99b2000000600000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", "l1ToL2MessagesHash": "0xb213c9c543fce2a66720d26a913fe0d018f72a47ccfe698baafcf4cced343cfd", - "publicInputsHash": "0x124b48fbfadbbd213feab5c7dda66f6908f55c3c899d88d0db822527dcbc34b1" + "publicInputsHash": "0x1256090bf682bee2a1b43969d13bd8921ab74904a46a578d20534b57434fd60d" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index f0147e8c6cc..805a3869c17 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -52,15 +52,15 @@ ] }, "block": { - "archive": "0x2f3fb377fd6181826fcbfda86813263509bceeeb8c606e61a03386a5bb6d0be1", - "body": "0x000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f000001000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d90000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f000000000000000000000000000000000000000000000000000000000000071900000008000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004410000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000048100000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c100000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501000000042ea6fe02855d8c72905f35f08604467117c037962e324c9a793505138558b3700c94efd9afe573212f9bf596ca3a4b42ae57f59e670a7cb5b9440c54bd8ea2961856bc4892b0b3f156ed2aa87463c389bfce0fd675a37cec77ae5d753fcf593c12f9d3f397c2edc9e4a6a5e485641163525ca802e3bd93994af997a9b9a44f98000000000000000000000000000000000000000000000000000000000000114041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001180818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000011c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1000000000000000000000000000000000000000000000000000000000000120001010101010101010101010101010101010101010000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd0000381000000e00000001bc000000907c1b3a08a2cb8683fcf76e45ae9de5c9d696408c53a9939f5064e661500cac4a2964e0e00a2d6c71f958321068266a0ad7706eac1a5183572be5c3d53ba45ff1734d012091c1faa4caf66c00b6a0b4252ba53f2ae331779ec2b332e67f3b10a097f4c74d6bbcc69fabdbfc1a07956b820a762eec034f3519c6615c7ab60a150c811c029efe9b594f2412a29b64105003000000906bab5e23dbfe7a7696c7090aff4201627797929ea89bec9d6a17ec930fbf0f3d42708d82717dd5dbba0e06b724470f6a9ecf06918af478b4d92ba01a3bf5cc97e531181c10128934d4f2a58760f863381de408544e4b35200214e5bfbb7d191f689934289a36948459656b72b025f2590cf71cfd94c6c0b479f85ae74bab0f42384de7051fa4405e3e1663e0cadec48e00000090b9d3e39d91ad008916bef1383e0a7a18314b2b778569b1bc650be76cbaa70defca5db3dba7234ee8c0c1ae77caadbe6e4d44aefc9016a6ebcb43a30ef76e614ef6072bbf1282ac465c0a7d8f1ad081c523aa58f64bb496593f493c5e18084cbc343f9cce765f11cebbb9f08aa524aaa0107fbe4f10f8fc4d5ebd6f34cc5b6a718b93b35c3cb971b033d51dbf3d71a1e0000001bc00000090d65b1026d291257fb639ab3bd2bef618b0b48a8a0011f78b66ef61da931d3e98d7476e5b783cd04fd256c2ee48e50e6609423babd46f0d4128e062251f200f5efebd8874fbe9803428ace9441ad6be73024d04270212a21b1e315671fd50cecf657008784a40e6a945d0c9933b0b751e0e4270bdf3d96f5660bc332deb55c1d69efee98575540775b0bfeb1795ab0b6800000090c428df8558124ebad08202b4e9df93e9aba73daf792c1c5778d7db24eae062d1f96e40068f382c241371fe92222fe65d6079aef71144a6b5200b640fda76576707df17436b91e16e3702b234bc3b5db2148e9b10bde68adae03ec7397db66e9f38d9b6dad770ed9a4cedd10af990193d010d7ee63c3673e7d19a1a86c85b812a77a27960a061d34b6d3603e9be4fd68b000000900dd0a2f23deaec926322cf81653b6af17ba64cf0771512f67cc6254d5b2655c57ff8bb485ea8b7800db96eae65f0a7c88bfc2106b9bf899dad80284afef5030402d374526f89145f851b824fb54289e50964cc0cfa74628f766fc485bd77b2fd8d991243ca4df56a0d2961c62bcfc8b0143b56669c4243ba4b8a1b23eb6d47baa02a5018715df1ba04c901c8c8bd0177000001bc00000090a90243f2ec68e4f6e6b21048876e4a1312cdb3af73a5cfc0dbcc269d26985fa2055897a67459ebb74f3ac45aa0d6ff3f63dcb9e71f0884497c858f0ae15cca019fe6e93e9baafcaf945bd069a3a5c98e0865700131bef16cc4c47e389f5e0f8c5222696be1a1c09029c7e1ddcf643fa617304820537e972a15547cd43dbc826304a85d5a9fdd345f4033f326fd8b317e00000090a6f785621cd1f8bd394ce02ecd3bf72e1652b7dac8434e0f36be19f5067923427af900b9d89d75e0693d121c4ee41ea5c7b3c3768c2aec19c6db0476c0290e50028b11d31ae04ecd702125a29fd857db05a3826a0ce0a9d720f46e24e33f95c1ffc966b90a1d2d83c7ae9f28e538cacf0cec4bf0ef40d262f77360406230b9456a7c14321fac15cd4dbeaac0672954d500000090ced89c13be6d034f1f3ed73c871c41bf79e2b6f9c03652ea3562484101d06c0fe592debbdea9ff08a4a8e242c3e31b3a39b0b503bcc29f1f3da8c90fad9240b701258f7cd3dc750418cdb045d6f89070259677559b050bf6652a4b3c88edfd90a208d80286a3a627432fbe2bca3d07e5196c31f8e14d2443ed9eb8a12ccf2f2d3f90af296c346adf5e874042f50b8e58000001bc0000009036b8114db5d25a74f20c28ec8fa372279d3de9bf48e22a1466a0e02283af96257e863f638359ea3f4d5626af79ffb9c3755f0201f31deeb9082c5d4bf708589e66edf6386bc795ba50d50a23daee25eb1492ce5b5ea7bc5b2692bce3fcc4d75ce59f4ff60a1925b26288230a41a085d7192a0d71649842bfd019e17062a1b606dd09abbaad2ca4f2d8e19c591583814900000090f448cf92adc1a09fe6a43d3532627994990b9eb5aaa76a43d547045d73c4311a476773a0642db295b91823296cc8eebedf1c9fd738e612e2c07b2b5770618e696f6c4f97e6714ace745c013e68ea1a7317b03ca9059b14736059b181ea3d2d4b35b02525ce4127e892259748c01a81912e694361b8f22c0484b545ec4e2bae6b6b9a04727ccfc5976597374e891ff50e00000090a422ede5cb0a1ee27d05be320b90bcadcaf47b31ff2723625145666809a67f3c2757ee3d5e56ec08fcea4ccf9cd345e2281dd362935cc246680a3115f8b9df3301c3b1e9b8c6a8eb2cb869f8e029b8462a2cbd9f5b38a69ceaedb87e7777e8edcc0c6bdeee33ef17b3fc5dd8d74fb097010b54bc3509deef732f49927ca924a212fa97c5ae076dd285e9f5001bb3755b000001bc000000902388e4f77b866464924fb5d3eb9bb1f4cf8aeee2327dbb5ca6c94d7469a8a4cf955d66341ca63cd8b74b1b81c87fe727cc79d4c52dfc33b8336a6ab5e88e5460d3fea2d8af8ef176c91ee898a1ea3b501af82247408797c0e1b3d309a271ad98109038e1fd88da421de1be702af1c94a2868d845580151b770a3af1ab2ba4ffa38e4696d1174792ceb8169c0e3a40d3f00000090eb7def151cd9a4004475ad0ce963e7e34cc75ddc8689fb9466c4e9ced59197dc3fb3c25a43fa9c62bba236f989e38bfcdef819eba5dcf89d17f6c4025beba3f988497c0b9639b765867338d4b096dc811f1f35b19829cea2a0999d2bcb28db6d3204ed4b7acde9785129e72af98439d31035fe030458a481ce33a27dff24a1ae4796b041643c0c80afcccb1b03e9916e000000906968b696d07368fb5400ea065d9602b3043800c1440c79689952ffd7797d5c614568420845cbc63e9d741e1f5fffa1d9851d30c01c29b1927611f795cf88d2237e7d4ec9037aa9d0d2bfcaf4b5a9355c0c8e9cf86b1c2957799bed4517fd6e7678a52789de5e7d7bbc50b1c4819f7d452f2d0fa9ab1862b6e086fdaf8870a4b1a0720cc10f545d8b1a80d2f7bbd4a03f000001bc00000090c66e589493203da5dc904131056f39a754308b74116ab5ff61fbe83ec2eaf2029b6b617bdae1462ac1c00ce5411ec65c0c5234d7def6a7e8ad98a15b73e2a9c02f50fcb32dc91952a1256a7c0cfe7f9821e175d48758ac9aba3cdca31f3c6fcaa0c616c8fd0736a1930ef29ec83d40c800e48f95794a82dc3f8ea3fd2a823bfb297e541d1b88783cbb52046a5c0f562300000090768193236ad2763b5873968cf429dd9904fbd0e566984a93df8d19b31fa6c7d97b685669fa571770d1104e49deae20e878a40c0836bdb779b82935926c6fbdd1d0a5a0313eee67f020ece80df5e81dc42246e9f9a36c8515a4d80eabc793bcbbefcd84bf5d10711f35971580e81c41280037c6d6da5cfa8c3eed023f32d55c48d0d4294ad7c030781aff4f77b94fcfea00000090c912532e7c09e0a8dab5f7a0c0e3f8364025505f36dd512d2ba05909f99b04cfddfeef1175f65eeaec313c4eae48323611d7b40b7f52bcb507d0c4c80563c66bf52949b1496b5fbb65265a62e7b6843f02e21de4e1dda3aead13660ee9e5b2cb5aa9e614f2bc9c086a0eed7cbaa710b42edf80e0159819eaaf21d15dcfd2f94efeb9525fa6a0f99828876e91682585b1000001bc00000090ef1b83a2fe15a224b3cb05418b3497e13856d86ec0def188a4cf0ced86edae1002081453f26b97ac1691c20788d6c4746f19f06e29c5b23b0e887777b6e30208971d0f2cbd0ed8d91521f4a3c7045e34076df337e47e9fa507516ef13f03ada0c285b92fb61d70e9a0db40d3e163c45e2ee3a7b9f4f6ca902e3a7e98f18b0299031970689089bb5f21c08d2fc94603da000000903b62fbc69c73bfbb0c0443bcf4624f807b1ef4acec60db08a8bccef7f0833e1944cd2ee8644678af13f82e7014c4c728d36bc689b93d5856cd21d4c005bae82d726d64da49fb830601b511e9cef791b62e54ec2d95817842163e2f417ff9cada18ffce9e4588208fecc05500ad078f09057b40278ee50de377d0a121b23a928ecf36c42d1e609261fd79c6c853cf304000000090570872564617956e481624ece8f9f8fa7bc63eba53e28fe4c3c06dc594cb0672e9530b3214c8983cafe960bc97fa3536e3ef44132d8721b793efedb3a17578de05a354348a2c25e83357c4682a39df3206d44fc44579a5ca0920f4196fe08e2d00377513e7ed4145e51de3836faaaa4e181002382bf3915f558af58266a43b2801a97c127dbc10b2840c2e0df5949bac000001bc0000009094212cd20c5afb93ea77dc91e6ad2ecd5dd55ea4e8e7de7ce66c2f7d496f9af69d07f2ffa402f093d6bd3c2d5d246c7763de341e81e5b654b1c29714e79b02ed8aabce6892903ec40e05e0bdac20c8c2237a47816a3cdc1fc64fb4052c9192e2493e19c8a6f2c639aec710ef74b5ad2727850860db08e994d6dadc8f773a7487cc99b29f65b78e76874842e18c59cbc100000090d22273ab92a64992204949d374718bce467241f4eaba3dd635a3b03469b2cbec16e5c37e80258e9b1985cb4675450f19dc8c2b3c3576da96c4ce51a08aa4e3bb3c8015777e3300fe7e2eeb1f57b8675f01a998d4256eb12fbacf0157cab4dbb9f4ccc9d15d5786f2c14d5b453cad59a828312c4bde964f8bf3224a34d5da9c65652b754d3e9db14d985923114c3ae8a70000009016e64044ce8bc509083bb3a8bbd4546a349850ac8c4c2a4e3c1f2b6bb12f46a2069c4bc6fcf80e208fded4592feef5da5448609bec68fbf7e1314b3eb76e5cde198af34a03a051e92b586452758582a11ccdf709902a39cc8940dc42e3ef4e0afc2ad07b53337028ac9dca172b7f475421b2eff3b6c4da731453539197b2d016903d4d1ff7361ad5c5c2fc35ecdc6a2000000e00000001bc000000908f5f5305fbf3044e058b0694519238796f9e67dcc6927252965c4792d1642bfd740e05eccc60eeaa8e4a5b6a085385b2947b7e9f0ef5de46869ad4136e88fbf07123f9570b54623787cefc24533b49ac0e01c777811bd9cac13a289698765bcdf90d8e965689cef3e2faee319c3eb9cc1242762410d2041e045715375e0e060dd857fb744e324b653250e850ff35845b000000906ed36c1c9b2d8c7c394f5c0024cb8510f8558c17d6c83111ee0d4077bb0fc10033c45319684f00450424e3d77369f15eec6a65156daf316522cf5795f0d21c326640da47834e04eb9987af73772f864027aea09f7d3a5e79d39ac7e44f7e2a83ddc472d7ad4d6ac4cd2b235e660eef9115773b7394dcd03632821701533dda5be844f897845e7781985fb961279153f5000000901d10a151dd0b0aa3b5b8d6463174260fdcf462d9a53031d828c4a6e2268c05500373e6a19654b0196fad986d4a1a5fb508596b86081143487d11a8914c16c8a3be4b5ff912f227619cbcd5f0fa9bb3472d659391f8ab820070814fdf2008597dc2feb5a180ff856cd705506219e6ae8512684f4a8fbc073f5cd556bdc28b514a728ad6643d63d0b2a73132e333cda1c6000001bc00000090bf18211d1bf13578fd2bf01072f7331e7f1fac3e4082875ae7e7e7b3ff0b4b37164425b976bc4938a6cf59086ceaf55cfad4d17745bbd7667939b438ac95cbf03c6d7363567a153cd37df714ba7e304004128e90f1076177cf7021df6819fd1fa05e4fc477ef5448abbed7425d02d5cd2120ea74f76498b5771de72eaa6062c4739be7bdbcb945bf50f923295bb84110000000909e92a40e2d7c0803a9c1c2acd2fd309d5dc6a664ed8d8a19520fce1cb1c04a70e77b37e5ab8b86d510dc91d20c590f27e8695f14e3e6280fca591b91fad636e6e0017662a77908d614963b89692a5b2509a593a79f44e6195f385ecf367583615e5e57cb0e0a64e94eca0feb06ebfff40a570a8b8ada1ce1ec4ec1d41816ad5a0e0eb5f5ff60424a342b692e3e00003200000090a488ba549f733799ed5bb466cbaeee0cb5f92530d0fba69ed7d64857893c162834bff5636267fced644542d9ce29cd01c422a9bb136580b369a4b807323f3b3358438e5148fb094a70eecd217f515dd12a94a17a4220490b31e7de13113830cca9a36e7be60e304e53f94ea4a4345a7427cff8058fb4b484e0bc5f4c4593ff22c4329d33d5bf96d2bdf9a152dab4f2c1000001bc00000090b2df28904b5b72cfd178670ecc399d16dd3da01f4afe6d735a7ba5de51d5aa826355206ecde69e6dcbe87e4aff2629ecc23fe3c69166ea1171572fb172f2245e063b0e46dc59e49996cedd02283942ca192a166d30c3418197da6c907f2cf2bf423e066f0fd68c1018af6dfcea86c04e2217a1fb08251948cbdf4b26ad27a5a47fb634267f5f1d06715a41ad3031b31e0000009096c5ddba66f37c8e7761c5cf195c140c6edf6235facb9dd07674edd48b646119a11e05e3addaad9949704f7942d246391fd7743bcf17bcd5e6ef5afdbcc60b5ea13a3605d200be3922f68f84c879d56318a1306cdfa7aaa518661fe032ff2d043113e594bb512552705b20024f7b4f070071db291994809f527f91d79aa40b18046c265b12165cac3b5bde0214220683000000905bb6629675b1d01997f6f33a8bf669e30540b49d31e4895c3369cd810ce5645e5a3e585ddb29382ab9209dac3e68f954423c52cd148ed3969d7e7ab819063070a6dfa3c135a45a1d080f47c428bd69d50b6630d5d2bda9730c9fa5f32cf8c81c03b1be6b30b7de3669b050423c7e132925f6b0bbcb1d5bb0af2c29d8ae2574b196e6e8da740293747f5e20d6f51585fc000001bc000000900e9b1b8cf0d0175eaf2276c35dc87b99a330902503b3bf88a756b750f4eaea3609a401968cf175a77454836cbbc5525ca5ed14edb753b54524dce85926933d149322a31e37102aa8fc1ae44103757be91643d3161252446bf073978f1bdfe311bea78257d05fbba0b263c842474b9da812eded30907e614d95d53856099346a65bc21b56324f01dc9e3bcd98f6220f8b0000009039d7912fc0239dcf903b219c27cdf364c33cd37a30a94afbe18f2778cf2d0e3d892976206e2ebcc2e6d55673d978e65b76461e49ad281d58da534a83c2e3a4f99ffc1848da89a8d25f3fc43775ba84f00baecdc0fff6867148dcffbf9db34bbcd6c1365182d56429f775b70633023e761c2dab8f1069db54ee02ad670457b2d5363d0c7f1408f8b7241e9cd9637da5cb00000090bfcb048a04b754ed6499c538a5e7f5171a93009747e879c6107841670f8ba2effd3ee5a443701ab6ec7f7cca7f1b903e647b64c1d23283fc7ac21aa2e0248576e759e58a8092d866d9c6af7932761c6708b38158792e6eec7fe194f4867bbfaf9bce9e7b31736646bd6b75bfdf57caa21ed0cc1a5ed3cf23e49680957e6ccfe145bca1532019a9ba465af64f12b9b1c8000001bc000000902f2439e3ebb2b14781fad9616f31013916786861336cdf02d81ea1a2d0f82fed8e1a0352b7b5f76699e8a0429c874560b857915338d03c98eea3ce383e048a072b4b030fe128f64184d6b11747be25bb1822e95d9487ac8d32b34a772a4504b3e98dbcea2661ae9c4c7209647d10a4481aef78c9e5a2f06dba8b8f1fcd22868b3918ea74d2181d61798f10fc9391fe000000009038ca3a37a4f433486ca51033d317a37be014d1a960b33bb16b54c6418f2df1a55573ca9e052da45402f3b7bc1b1718073c581eaa6de90161f9de1359763046fa9eba5872f0559d3a40df31678b93605d102029a421b8e9c0cdf8b9aeb79a56694ef916396329000996a10af3551edb4a04887cea168a15ea8fcf8b9b3693d34f34744c6cda7ab63c2cf0f74f04a8660200000090d9f3ff5b9412956db9a6a98a8536aa08f13b2cfd675a0d1de26d311a31ee234d25daf3ac9332e20838e735225908efe42dd6391b8671380b73941fc6428e3ea61f24f9b56365ed89320e72c1a7c3dfeb05b0cace2b85c028619e40c413599155a9fd882caec77f4af38fb56e608ff88d02881fef1658f1a55f6dc1c0db724e6b3930ae928311c7da07db238923a7ab3d000001bc00000090e81f94ae53f3cefc91e9e1dd0daf188e8cd3c9ef1c6e78f9216ab5ed80c48b5546fc5e13048f64bbc159b0c621dcc73048f6dc215e09e00242fb5fc5c5adba821bfb38f7e48706be200ac8ed2e045cf608e7001683439e7575ebd3fbe2744886c97e980f3b76890c32221b8e15b4fe1204b5abb50c5c40526fc850e99deac16d0996bce31e412039eb4e5e41409c5eed000000902e07a04fe6a351dd0f4885901e4c964d58d4b90c041ca27768e0fb352ea7a92cef1ce4b7b78a4c3fd04c78df3741b9a393631b7f305b850d3b4684adede74540cc36ebf64be5be1a2b7aaf858a7abdad1cf71dd2625503f41b2aa6cd8bbb02ce8fc975f6073c56a7d5665d57dcf67f2612dfc622493b15fa2ae49735c9d77eed90b069ce10f26dc7a56be0e27b5dc72b00000090b63ec5dced5d374975f1268fb76ebe294fe413110af5861f3d874c4e2159d712b53d44d7bb594e5e06bb20805a0b83a718451784acf8fe7e2a488f77eb0e5fb232059daea041fbe8c260e772b1786a7120792b5d421cf88206fc781a212554ecb4dce9d3d0ce86ae6a0c3370242062cc0f71c72149897b6c3d023351104fc338f0730b8ed899ec4e9478495e50a79165000001bc000000902a45feef1f690573b1adab340aefcc3718aa5f5da6246496e3a27c0ec30cc19a4c296667a0bda271c960cee763d5c50a79cf2db8680f6fd6b153b557642f2561d92e1a983154177fc3dd576dfce6484c3060e2cff23d56b5400e981ab57bb10f086c8ac4c4b16be77f4a8df2b71e125e02949b090f32a9d2325cc0512c3a29fe917d6532287377c1c95c88ef0c992fac00000090a20f6fc346c15e7e890959858476a0f15f2b3fc318de61e12ba8c5c8aaebd6c1cf9702548b6b930b3a32d37ae19ba0274d11434aac08208618ccf457f457a8e986c5922cf5d9499167fb5bd2125387800f2f9a04f1d5310185d5cc420a9485852747a5c8966ef1fc2998a2363f6219812f0beb7e70c8b49f7fc10b88ddf8cd4e9ac9e6e0891b13e645116069560eef3500000090784818f1d8648c12d54a9c59fcd7be95532ab8af2845f6d3ffc9ad6784dfc7c34468905e2f2a58ff4979401d25309aa43ec338c3648e151cc091800ba72dd541e8e57566a59e0c44bb929591834b91202aea218ad2dde451ce9fc17969662765fae79213a63910b819cb298ae208a25301ddcce3170069482b8253e649daed00e6bf05c2dcb2b55b9410a51187a503ec000001bc0000009004690b61c90265eb3a91db5fbdfa7c7eee1f4b4f359b16e803f41e57a10ae17287feea5c17910a75d7408849bbf6480ced31bc122abfc20571586db97b1610ee5d0fcb287e6975b142cf38b0cef96d3c2e1abd49e8bb69f93f3b49930deb05635be1a971c3fcf56d072964531f803d540e97cd9e5ed3a4c6ac2699e8a0e898b67cf78733ca44d1be440818826562b8d90000009012624585c036d5a50bfeca21aa095b1a7912126044130f201e7a9a68af5ccbf48980797ebdbc0e25324ff6a4b30001836a9ac34087da23c0cf54d97ac2303ea36e4641a3085a017748a1b16a2c31ce8b23f4ea5eef22964dede68b25d97993af88af796df8f3ca9d08c237245bc386430114e431f45c18b7d6cd2679d4b0c39d4ea21a422f0d65698f826bfa12828d8300000090efd36a1245df2761f370ac183478511343d07cbf7c3e48c25bf0974f5bcca31957c2f9ba1ec709cb88d86ba8b73c5a7fb159e1fa87f200dfd7d177fe5fb644b230e9d16d2d9fe530b3195333abfca4241f8a1960a844bcc46abd9e916998086bb5b61dff2a49841f390b4124aec67ade1fcbd225e21183957ff1233fa7bc0ab65f5e6b923bae64a17d85d3780295900d00000e00000001bc00000090947684198f65397ba252f9dbc1f8af99c32aeb32284f3de49c547b0b3114f328502977ca818a2b4a264a487456ce29d0f1418a548e71ca58240a97ff5011de799d72cd0ec3a48f3a4ce6403399c37f330e55917691e8414f521d38f3ee63ba5c24e191e871b406a7a112ab11fd79623106d026049fc195d5f6d13db61db27ce7275f50c6db01e2f6e827950602a835760000009091249f549962d71734d4226ca3442ebd1be20ec7a8ebd8ac4127005879d6b5b692feca8335583a4ae0a6a9ca2ef890337f89de3b0d0d9cbabdea11713f3ee8f44843e8bf98a36c958158456ef9bec22314433d304114fccd775dd84f937283a904c9e34cbb00f1b045894ed2690a29f3094814b960bb88ccfd8fa201627dd9e6dbe1113b92f6ad611721075c318a94bb00000090d07c621e6271708621a319478d0795bef45f713b6de2c471196685c0594594a609db8d5db559a1649a8d1758fea1467283fb6c01daf08762858b48bf0615c1e116f73f8bfdee730c72c56af959018e2a02acb10d80458b041ed34e3022e2b3b398ca07a4650e3201f16b7a03e4ed316e2b8c100851e08a74e8a44bef8292271bb70a527e7493107c7f6137a1eace849d000001bc00000090cf7ad5c44a117719a906954ba9babc0edb51738770b4ee763b16786eaf24fb49faa32760f99342e1b5b5bf14985ce6fae0a7de2e3220f6f11fd89dd1191daeb109fe74b046ff913a6256e0368b26c15b0353414edeea5052ccc39ef500f69baee2a4d866ff0687d450a3dfebda4dd16a2488dad669abb84abcb8304e791a0123943c62be536dcd139543693e23b8f92900000090ca8eadddacf1b9634370e2f35e4041b50fdb7bc6509d633274e89c9f20e46cdc7839f39b7bdf1c86eaaad5adeaf2cf4fbce53e28622234e28b0a7c29d925009a5d95a3e552b90504d2cb2ce48599be7623d6957f71a06e48789c3405c17319c231e5d13059c74e2046cfcb01b195d15e15aa436d9b166a7ec1bdc4c5f80e3d9dc70580b20514c9630b65a71fa4c2b2c600000090ab0d42c3fce474d24597ee47c7f10a98c9f68bfebb211d2a352e84ab938d45bd69759f2a76690f029be1aa30730d0284941de3f796dccdfa1f0529c95e4b6679354dab63ab48ecc79a5e91b3d7d3f95d1e07799e9397ea5d2a6776fbeeaa4ff79c65c4b06810e20ecc2686de6c256bfb00531e2689364b7b81f7692432290d757e4caa95775d586da6d24d9f0fd460b1000001bc00000090d2a6f20ae66b3c42770388248911cc2b69569ec915e4ab4fe8a6c7e1d4aa0262bbe1367360a2c8d201e445d361f4311bfee4871f95b4ceeafac0bd20d229c523ebbe060cd13835e5904e0bb4cce865aa283dfe8dafa40181f02a5ca81541b4e170efb21a66ab761cd4943d42947657c927fe1d12ad7c2a5ddee85c8363d3edba175c87e2682bbdfffe993c9fcd2577eb00000090f14f756111656f5896f07909a24f208168a7175dfd7236ee3d50a11d6aaca5f4e02b0ea1348bd834db882a10dea0aa5bdcd78cad15d555f4f7ae29d79e188a9b0e82264b2018c2cdafa2787a29c4b12b2b7af03f94b35cd827d0745732ec211061a26c6b73eff0bc3e492c1910f4c4dc0295ab73daf1af831b407be133c243c12f7faeb13cc54c177cfee8e2ec1d9eaa00000090221009bdc1b35d2c1f8f98e9c88ed6272c09fe0a5050b71b11600da54e262c86892616e7117ae08df212206b1645442a179796d63c3babb16178a0c64a18daa1d09573cb0035bd68971b00de5d5570a000c90626fed9dfa6f56a30c8983abbc55f791cacc21a91eafd0d4d0f26553f8c253f58e1313862b32be1d830116757b4de42fc122e76367b8bca06b524d1a2d7000001bc000000909f812138b9e775dfd5969502abea67268af1cc21c9bbf14c24618f74e8bf66cbc3ffc22659bda2b6f286ebaf0ec4dcad2160910cf444b5ec4162d4e69a6fb8eec2331c41ad0b10177b2e8e4c2ac98a180a72bdca115a8f467ae53bc69b561f37f3415376076097b186e62c24e2977d630b40c1e975642f810d232937964ab2149babecd8c39b9faa9b946b14638a4918000000903fda1fa8f291baec2fba11067cdf4e363a1f0ae6d2e168fe8445b614ca3e8669ff1872d7d774e11fcac97f48cff4b199c047661b22af335c2027539859262c0feb865fea60aeb493c07bd72459caf3820e170c456d91f8fb70f1097807f76a1d3c3552dcea437dde4b4336d117de2fe6084425c996aecf3bece7742325e4ab116a23526edeb91451923b40769ce07b4700000090d49dfc5cecfbef724d97e87b5024a1057ff0b853835ee0931170970b6ef0afe3630fd198020f91a75de23bfe72621fcb1112e1e315d32cdee93656c96b0463240b988f392e210d8d1235dc76e652308420900759e115b20af866c93192f6bb025c35f9ce5f8e9d607a2918d70aa231b32c7211be4ecd9ebb31b223dba5eee9cffb2c14d002bf4e6c8cd2617c52f92209000001bc0000009052cd51b86e05a112185fcee59644c7868239beeadfecbcca4d334a1546904f4cfb3b16391cf17aa1fd543fca15681a8494500c1b341277b96bee5a43feddea9f5b5b968f46374dd616e74b96c20173410d3ffba84290c2230696ff06819e6cddd55a76a44a710c31ca5bd9e95a5f215314d88ec363fcce41e0556b5f5037cb9ba663626ddde3fba5ca49a18397d2861c00000090195a187ee83284094d52b6597b76a9de1950c68a4a20bc0e1a958b84f3dedd893db8d68af7abf948c04cc946fee7dfd3e98df98cd435c7c0616097c2ebd550f7c3e98a7341315f53468c3a4f7516ff8d23c160006fe19e7637c2258444e080e9c54753dfac170b7c991d734659748c4a09328f81b03ce897fbc6dd4bf283093f526a65e24cfcaf5532756a85e3f0980e0000009057f70fedc5778b142232a47726cd35c4623e7f440ee98e92d918491d17e1ef9ac8de9c6c9d2dfe5d0b38181b709172fae1e9970808ecf061d7a8dba520905d2f8dde99cfa9b6a527596aa783c7d21dd5282708cefb592cf2c17cae26eab29728101185f515f6033731b1e0c050b6b0cf0bfef40ce87ef4ee0412bee0503b16995cf7a5bb5c4100d6a502f80596c1f7ac000001bc00000090a87159ed5a28b9d2876ca81908a405c4d4ce69b04f5c585c787cca6e4e444c7389b1d8f9bee61c6cc5d40a65cb1c66235ef5bb36e274cd24b8b8be107759787935eeaebd7e4f7bf42e1d9e4d1b2cff8215e079b4c27c1bdff61b19ee1e7455df02e2b9d44e6d0113cab1018e8ffc2fd00079cf8c0af9a2d431f1ad14ad1d45a7dfef8080515f3506d0d7123fac6957a7000000903ede5c1517d46f450f68002c97d595f5a35fa49189a8346927926a4be396470ab70757159ac64fb5d215ce07384e3bd7af352c7d63b3bec10627f7072345d365bcd313cfe82b1f6b11088492bf9ff62d27b752571d6a5adbb01f290bb70a267ced42ac421070fea792f6963d2faa1f46112903aacd31f3c8239648fd9a308ab493ebcba7813ee3c1fd85b234bd293464000000904dba3f8d5253847e0410880b0e94de490bfd7b274fb8ff1a1d19da50ca4ac756885cee121f54bd05d4098b6139f0429bb44f8e9298125c7ec4936565ab5ee625503acd59ba4fb8384fecb1faa487ff332444b78ee8b1770ca6e7d8d4a5033c5a841e0bd137dfe66fea79921d8be63d3c17046aa6b02de3ea263e784a01331ab59390396006610ef6249ca469b3b256e5000001bc00000090a318178fd7c767175f9a386439bd1753d04b8cd05fc9ee599f2b3b8b6f4d49509e588d27ae0143272f13f60649625c2cf65e7c60b707f155a1f2d7adeb4523541aceaeda83869188a240ae6f96626bba134792fc15db82bd296c98781fa4187cc2235b9a81683c51719cc7089a62e249191486dffd24778d0d42b360f53320d1396a4535a21c67dabfb7ebab6829429600000090ceebb89ab853d54b103f12d65f145dca0b50e079974b3bffda72918d65ffbf2b6f56773816504aac7d18f645c7a810c2ab27755209342bd1a3d3c7bdb4a0a9f3bef70768fbfe0048f19599382100791a2d3ead79c839dca4469a8e1ab7efad9b49c9c921d5d06ec688c38290cfaf41212dfd1fa3f876165e9e2e4501fea39515129b1920d61deaff829d5c8fd632e40800000090dc880c0a8b4345e819c34e4d4cee8f9b655bbe54ab1fc7086dd2dcdbb92c0abe931df0b7259782b8ea3db0cfffa341a43fef48d99532e19947e67d7a99d1964f7dca4b077387ef4dda2556ecd948f5da2b420825296ac7e697f327e031c600826ef2085458e49c20e39d4abc647f5a642ccfcec29b3e8aeda89451df3bee503b9a4185b54516d68b8c393102242e7d82000001bc000000906c7c882a148444a9b4d95ccd067d18b3b7f3976ee606456437dd3503fcfd8e65a3a0b7149716d3178ebb574a3579a56337ae43b55cd8f89e7c1d1cfc076e28fe3628f2f91ccf6092de236aa93432029e00321c0b18fd00222b7218c0c6974321b5dfb7b9a37be815e77d0ea4559a2f60178cdb0a2cae0e4c6ad3b7eba520b09f74cfbc559826e3499f49918e6da231f90000009081ffb2cb3bbdcda534d9c100bf64d41c630244fb248f255da994c977ea3e7a2591398362d4f8a70860460d5d65ba17aa0e312e47a22f6d6e0e96667ba1ab2b02b898bcea8a5f991e25878b70392514950e237cd9ef6b504942ba6ee37e97de35b072e92afc0071f3362e4f6d7667330c1060da0b1b6d98e5c0873c1a0b8725d85017415cd2ffe4b018d77ee46eaad29300000090fde71d5101f8606e5bd8be1402cae1c9f6fb500d1f6eda8144878cb10f44c93171bb2e96ded3a1d1a6320349a6d5ca84677773742dc57459a772dbabbef35a96eab54f7ed1b4353bfb02ca53c68c1e3d144c6a1cf3e56a76c46213c589008be1dea90938d6e2e20f47f4cfc852ca294d0fea1bc5c52eba75821c70d98a6f6dab13de0624bff4f75974ec7d7f4860e3b100000e00000001bc00000090d9f207c2e4ab524fd2e7b51dca4f4fb421bbbdaa372793c766077aa8545d83bbb6fd42dc13cb1faa91900c92b683bb527414a8ee06ca3bab0ce9f935885198a88bc1ab065be3c41dc936685c6cc8fd6f102711ae2888d2391ceb7391d2773f1f22642b3b8bba7b356734ee0cd13a3d5a095bed4c7a18b005c895b25092a1281879a77e5876af1a56965934f1b01ea01100000090f6e66e9ab940c2d660abd12bf1ac581e825989598ec0617bad0c61fb54fd1a23546d7eb7e47c65389a32b86a7636532255b7567d19551b31451ab28c53665e122b88fbcc80ec0b06f26508ae1bbb82082b2690761b9151ded3f00c3534d4966bb79bd49c193757793604d75d837b3393023b9ad219829bff8798bd903a86bac85d4b6ffe1a4a7e68997248a4121df0ca00000090d4b4c16da25ec69b67ad5075f5f4caad48d49d2fe1dc9588f5809e4266176873d373ff68d6aafaa419693dc8a5f8347f25191b6b0e1aea68caed8331ed5f20d4cb46e7f35f714c7d8750ba404abd768e03f3f2394ed30368b968112e6ef4de0f98d860637b91067f9ea3a1ba95ae459b126db09c405009c60e1ef968e4d359d801d672b8450bcc13e5e58130412995cb000001bc00000090996af5176d961e74e0317c4d426c39f03f1155e8a4ea71df264f7e2765cff15853370c2d324c5cda0ed4fec33210036ef8c6afc30d98bc2fd62a4b42c20babccf769231bd8014508a1417d05bb1110fa21e542a26c0c88d844b9dd00f65989f74c02230087c7941dfd80e33aeb099d522b144046133c21ae3abd46b750220083a524cc0b83791c496beea3433564241700000090bc0474d57f12eb0063ef2c63b1d9e2c29b1927305b109cdda2e344633db5ac45d6642a9f9cb07bd4ea10c7864b9063e886cfda45f4951a8716bdc3d9287d3e524ea82281d2e1463a473d3bbc9a22810617003f5fc24cd8c7b3fb385dccae36562c8495e1daee1241ba6795e6ac98658d23c5fc5aadb784c29bf11e6e3d16801ec2f73bdc6c3e502de4fd1d51243a03990000009013675fab13dacd1fd805c4666d09775c253a761a9279d9d7831289bd7ffefd5ff6f1d6717efe15829aa86cf17451755f48ae5f68bc5f04800d65348993d20e2af9a173b4d67836f70b8f99e9072669b608373b2fd442a610ed78abe40f31b2e835984fe9bc1229293f202f0571a8d9831d43f087d6bfab4471697a8fd1a7df7dfd7beff70b02d5eb70f6f447fc5f0a49000001bc000000903956dcadee164f892e2ce17f5c3350cae9856d708aa761bc58732afab746b49f220021fc0c58a0a4ba9e8d9969b084b9082bb1c8fe2e65fd36620145e208cdbe7a8e1ef4409c40a810934f8508744eef2f838d08c309b3f07a8af4401388000b6e69ea45b326abb2573202de67e5cf4c064e4b9ca1a8514e0dffc98b69c493a195b918f70f79461f692eb8831a6dfb900000009070d9aefb3da2dfe00a7d2af651e2acb69df180cf66eed166bed5d1faf3e3b656517e22142737d2ac36e9ab812f04df082873328d44b77390f183f326f0cc8d2b3b15c6e4f2c29ecff7ca4a43b155e48828e284e51f6521becfa95f55252575b19111b30ab145fb1c7a6502bc59e829c706782348094f0c0c7b163839133d319f784e2d3303aeaed7ddd331faf711f951000000909743d75d6ec72d4297dd828d0f52dfe07f0091facbce0228271033dde57511a839a22ae30cd7c4f6609a2de0e871a581b2e528b0a90db8ff871af2475b8985d3a04afd894c356187f386219610b7fb180670a3a20f5b04af6c5a765462a6844cbbf7d0c72eb5da66321f3311fa95d99d045f2bbed604cf948545266c1f296b4bddfa1d487c780c58d8e71953e645cfc9000001bc000000901eea6f04d80babe64b4795ad61a35c08d32f67378d2380b7bfa04f46d06e6208c1f28d2303ea2c4e8171f3bc2d2c1a9910508baddf162dd9af42c8f7604f886fb7317b025f273ad78773b639af1958180989fefa2599b70c68a028ef4e31ea067b38444a98cc276aa404dc52fffb57712670d1f19e7b7a0238caf85ece99752ef1b36898775eec4bdab128fa10181266000000904e0b81d40cfe9d1b4c3315dc46394adb1a409d447202e106f372d091d481425800026683cc05cd01a4ec5152c44965954bb81cb66463fc61018c549226fcef6d5ba402fa203aa353a965ff9e2feadb7125b0a6d0f5f17552ba90bae6be27efa386db8d807bb07eb388bd1a981f4c9f392f030f279d5e557c7d6051ac0bbfe1868e91541eac030abdc009967c3a6724050000009013041cded588c50538a529d282842e54ae057463f35f2b4844e5dc77761c1920ca5a41ba99b836a664f5214e7fbb4b9f4f06a794dd726f133edffd80623de4077acfa0887865d9cc6d89a1e79bd22e500b4b39c12bd5127dbe36d7153da668274613a31e8ab0683947fc67dffd8e720002e46517bac2a598f2712fb8f529bf6eea93c4772660bef673845e7e756339ce000001bc000000907d2b78935e99681c27d68d2d196425afc040eae419fb3efff2498070d1376a24708f657d887e88e493243bc1012016866572433d3525ab42ed3c69d51336bc1b62ba508a0fabeead6a0fdcd6615d1b011aeb54bf48d725c6c938abc9340863821f656fed760468c8b24b87ce84f908211507b8b4f819af0e73a81d9e3f8ab9ef52394fb3f2a84ecb50004356347ea40f0000009040c20a9d2ae8cc24816017c41a22d9da9c2135d2c3a5b71c82383a8d7f61ba080a6d666d12d5cfe8032a6acd35835a1f03bada40df38cb0419ae80bf2ee0c9efa4b02863f10e37e9c441a359d29dc3130297260327f43b962afb5b6406dd3456b260a5b1b58ee80b9381b17050b63e042a86d67555af1bb334a8d2a6f825a17039e93e8d620afabd5ce9e0aa6412da1d00000090063df44adda8384565dfa07941d978435cf1ad2072ec9b9d79fe5b39a947b7ad68ea617daf9471dd0d1d225d7a544b69c9b38cb894d2a6976ce42bedcc8d3c82c3d177922139ee8103dd4113cfc40018043ee6a9b3d18e56a679f4070799a3cd94fc90063be7efbd85f7fa76e1b5bca92125f9f881b6626b43cdf2bd607a43ad57e83149979332407a32c9bf27f81cfe000001bc00000090f89605945dde7a518c2aab34b78f0831a346c0ddc0bb9734b4437b2ec319093f3bb754fbdce71e62b9f0cdfaa5e1589dee6ff2e9e124f8b4bdd39765dd4a1a4480ea4a792f4665c858c5d9624ded3ccb25eccf8fb852d32a08b9e1e5050bfca43e25bdb2129b1047df887b35ff08d64b165fc2ecf4c27d7825ea8df02f0bf9283ba66366a61de12245bc49116aef6b9600000090068f8311a118ca829a61ce3b443cd79567b12c93cb950c9222f039b112242dc3410f9cddbb555faa0ba3ec6f534690b824a5af190ffbe772162152a7cef290bc6e198ef04d40d6fc6962f3bbe5ff8cfd1bd6447d7ac68ebaadff48ce3296b68fb5c0ace2b42e8649d900ef4bdab307a30b00850ecde2e9ca4e903e32adf86c723393f658e5f45f5dc4d5f703720abd5e000000900d493c43f1f52ab642a486391dc8c7fe4d182e21519865e5cdbd0923bbfba771cb7e271e516167f0918e279b860073fa0c1eb283767d4e159591db2f23bf49d67f93534adac491be319ba9d480eabf0107e9d63c30be1c587c2419b4f3a1f941660b0893528246ba701a6a657daa4837272aa3f90a36648b1c756f19beb3e681b75310fb5e5d8abaa5739dc87d8b8a13000001bc0000009001ffb46e21b01f52ebdbdafc158f4361ef390c0da5615e39dbd15ced8be78d182733e22100b6b14d244a05a332645c7a53f67c814bfc1d8bb246e4f3030ea00d282590fd36a5e104bf2095907cb84cf2157eecc218512df1cabfef1d42218ef2f9ebdcf2ffb79029d050bbcc0103a6b607d7407b4b1902d34e0e53113b4d0c6d360b9231a1f3676ae6ecf09d2c2362e50000009024e6af36bbd2e462b9555cf380fc687a902fcb6d9ff57ee70f3b588132193cf8632b0b6c74b83d14528ebc550c2cd35b19e6ce58bf9993a499fff20d5c7f74e6f340eac36d50d100fb2b9218ba5627b72fb1579edeae78cf2f7c216dbd4358c08cd1a0a295e971c35d798e12c194a05a0f88e844ec1bc1b9452396b91cee2df848bcae4e0b36fbe51725c7b1ebd386e800000090476b0c2836ba8ad84b96a276a398824d54c077b7fbb306013b4f295eb903e467caf963c475ced241d1c32da91d0c0d583896d5e09f46be5959b84deb56a40271e19792b469a402559b816e3ff005dc8b1b57e5db0fb7828f0b17fa47ca36bf2232ec8bece5d8793c7fb0f4e13afc66ad2eded52dece2313bc725d4645105380e4af3309ecd66fef12a76bf674553190d000001bc00000090019a48c420d89ee53949b8e920fb200e169e70536b51adb238dc6f0e2f855073c070690a87908f41d85bf5f2967759fd4fd6a047788274fb75d2dc4484d207ecd19f30819ad59a851be85e5f48cdfa21071f7e89ec63f62dd9e814a8e75b069979e4a8c8f28c26a8e20b95c2008a8c482a565dc01359dfa71490371251c73efe5f2f99c088daaa10066222a71c4d42ef00000090a88a455036b68ab135640510b8e39395977e1ce20588bb0cc84037673b254e35e4792c9c8610337a9486878c6de8bb3528b218d34ea04ab333528e98dcf7f9360f50a1ce0ed54f9f86ade5f2037d7ee12d996dba01634e24558444b31a5ac15c6ea414016b37eb469c40322bb1c7334a087821b940a9de22ffb729f513bc66c20220ea52d8c0be1f5be1c08008dfe7e6000000904308c6b8eb3cc92e54434416aa52413594869ed558f1e02efca0e0ec84a48f04985e3e1d92b88252a680da4e857e4328be9350d3c874c451f5d1e5cf181f9f31bcb1f81656b9591cb07d4f3dbb0d22ea095066a9f9d506cc030ea7cf13c43c3d615d6abbef1708501532e4ee54d3e6d01ef61a694f3c83eb9701ada874b1b43bab8647d05284e030acf7dda064d5c14a000033a000000ce4000001280000009058a11dbbaa33dc29ada68385fb562e19c0248be7a5018a1b7913fe9301989e23e6d3d6159da6a7cfd14d379230c553f4a5fcbacafbc829ac0476e63aed34a81e3d5df51d2a443ce47f18002d149136690c5c1d7b2e5ba79717fc2c3e88f11397d1b5204ee11a5ae3ac773539e81f11a80a57e67bdf5c61472bfdd0d19f46e6a8d5b4bd09fd82938be8d3c67e5f8419b90000009061c505cc43b343b64c6ae23d2d3a7f178f86fa4de2616658fd7444b7ad6d36ca7529cada529342f81ca222781671e52f6da1177d40ad92eb10c1e151e2e70b0942113e8f9f1d80050e9f5968e7098f2d26c8bc433ce063dd5fe37502aaae904a361878356c3dba2440ec803d7efe09d72b3030657aa269d9b0a2fd32f98515cea47fb936be2dcfb05330fd28c27eabef0000012800000090aab3fd20f1c2b74c0a98e44ec5b6d5871a39d7bde3be7c9e305a1b78b5b69e34e96ad2e54bea7bb7b4f1d1fd330b98f057e3e051bac002b6e049d665b7ac853e44b6e85d3c47edeb7ab8e0694b414d572bd4f6798af4632bca1763303a0adbdcb67e80025861638b989bf69b3cdba19704d8b2640c678e6d77f322609349d859e1d079f9592f82d7366bfc8fa1e3d09d0000009051172e8e627c51843f09fbeb88d348b86f71074cb76bae310e8ae139e94693ec0b768827676738a93145102913069cb19fce5739f39cc708f054297a4a11e392f08278baee64ccc7e7ff0ee2767ab3e9010fd066e5e2f91cacb7242a93e0d0cd216f47e0aa346caadbc266d5f5a3e1f909778820fa4fcdd4afe02c26fc232b1b65bc33e8b6ba41012be34e65dc9bc1c50000012800000090dd000b6fc17ef00318e1d655346368f29e0f3f017da41b43666f6e3802396ea1258a57f78f0fd4dea34b23950c0b5330b80109242d9202f0c9ac050fd8a8b481e8edbf4a450dbfd9676cda4323eb146f0a5ac92f52bf8bcc5a0d6f70ec69af45c4fdca41d5591e751f6576c5dd6769930b9b31c156cb0136cc17ad3bf71cb45f1e0c4fcf2deb699303c1b63f330efdc200000090a1c653fc27ccdab5f3a45dfd0b36f5e6015f6c33d709d1bdbf443e656bbd8d359f90d6631eb6ce489d6c25cd8696259add18e66e255c6af271fb4a4eef70a7bd0f1a2ba52dd0c8a818abb615ba1ad868047a84dc3537a251faf4435c25cffe516de034cc5f8300654ddbcf2fb5c688991e988f9a2dda3167b3af648a94690998d49d3f616c337cbc64b5efd9615b44fb000001280000009015839b2123bdc678bad7544bba6605575db0b4f73bd769765ab09ba984346acdbdd66e1e99faa7f104cf9913257398a18bd539f603331e3e4dc10496588a2754e30c56a9baa525429e9d171f2477dbfd08e003a672a180bc75a44bcc92e41bfd9f0165769d969c641ad670cf0b92959708f4365b90cf35ef1039e27a6df2e8c40965e77393d71c5b98c3c54f4cf7c109000000900683e98ef9cd8964ec56a6ed2682b8e94a85f0304cce4072ed7a00a6983c056039ce8f68de1f51e7daf63948cc4b633798ea0cacf136f0b2f56beac7938e3b2dd58c98caa99d99f7f5252b50209aa5e806bb3faede475cf356767c3dfea7fd3c931067b6a0232e864d194371d9582c7009127ac2a0db5a8a0e66ad47a0cdd8006623f63740877f3481139ba407f47c200000012800000090c7d794b31669d4c78c5d77312e2785573675e7b6bab6a54853d89a9d1e08af640c405a361288910a105df8f8c8a8a4afc1cb34237a43c761f05d63af042d9cedac42ce82d683ace0b573e5088f67948a03082cd6b4a4ba24469e8a8932db27390f3c34691288a561e305240a1d71db922bce51b4cb6b3e574317c31c0d465c10a4236a2de41776bf2ca2c28e8c5e4ce7000000906083258d6acc362cb3461027e3300318c10bbf85acc9f3488e8209376f9d0d65c6f07e4a65d1850b76e3f9326d6a87b9ca8902deedf3a66646778d7dd8b0a67ca55aaa1f0ffe24a4f54c415ff1ec9ce62a7c4ff1514a7ea00bf463ec7d54ec35227c15dc583badb708ed54fe42e2155202b3534c0679ee1e923658d3f7995f4a17feac263b60690bcc5d2a2d78f8b1500000012800000090814726dd7bb5c4b5c44f1217c622441ea0ea38db88ef24d7b031c4b207ca5bbb41d1520c63e4f2c34a6f317a32c5ff1585c3b5454fbafb074b13583c90e3f864e668acfdd4fb66df11d6a71e940d41861e5626cd5f7ab0feec7e6cb4887cbc40043efb49b3e15ebd7d5a7a612960e6bb0f01c6e536c9148595d9a52d0d5ec59f2d17920d31d98808e0c1d4bfb7d8cded000000904e81077dd43d002a7e940609558b0e6f63f491162b0612d799c48dad8139f3f06e596dbe2211ba8d3623348a5288fd719e87e37261a8a4c46ccb50483e7fafedcb6f823fff16850e6689488975b49ea91a7742d6c3966ad8956755114b54dbcb8d1cc01534c20611b2b1606ac0892e252050a63ce91a7ab7f6da691306f7599819a877c8a5dcd214127bfba43750ca4d000001280000009043d8e87f88881efbdf9fe3d6d981a79321c69201d1a001f9227724d2385f94402fc30f40d6bb5f5abaccf737e096bec2aa8d808a991c3457529968e6c2d686a2314a187ceb581cc75b57b53e66c8c6843040c55f61701fada588be2f69340cf3443772c2b81327d61849e4f59830898f2ee53f7c840277a979de5db5df84ae770836b68606eeb89114c3b88ff56922ba000000906f8ea16cc4c640c6b5b86f7c2754cefd623cd7789bcbad86951053e0b2bc355a4a79ac7ea269aefc8044a72022a3904be1a842feee01570f0a0be83ac9b81f04a7471051b7a20a197ad893e3f5eec0cc2adca5d6f09e10809238c3de4363c2af7c8c0f54b30f085d04626af86ccaf2bc2d751f44645e44cacdf9eb4305354aadedd930f69a6557d6a2a60d347e37f1b20000012800000090b848f0e992cff482ca897f00e436b6bccc99e4c7ed3e0875c737ce9aaf7bcd96699ecc648ec9fcd724fea3de7943e5653a34cadef91645ee312e75a116d742a1d85de2d7738759acdba78c58650a3b1c094d522339cbc97d4d01620f8c9b5c8e6650072657643becd21e6232ccc23ac617b0ebcdce3425019be128107fa1ba7ce245c0c2f8507f8394c36d365044b6a8000000903f57984eecc6c4bb21f3c97e7d6398215743f197c2c0e5a79fd044f349a0f955a18b7274ba74625c7b5472a02c2c1f0f64d5aeb1b5fed2f64db05f04c0b35fc228160ea7f1d19b7a00365d5af17c2c270287411d24dbe078e4b21dc38be0cb9a8f6465ea8e5b200bbb3bdfa71bce73981d05895cf5b95c3f932df37d8edb80e4c69a49def556bc977f968ec3eae505ee0000012800000090550d964357f7687a3b6d9126f765b4ea42887294396a2741fd0c759ce74376c33d54f5e4f221f0bd939d3281edabe62df3afd9fd8b4ecff170126b26c35a505b4f5915e0bdc91a138dcece72d6667afc2250a85061d63741d069a5f3f91b5608a2385b1e8c6248761b83c5bb65e4229e000e324222e3e295e8305f19bb9d462bcb3a216c8c61de6110f0b1460abcf68500000090d49a1c992f5162de4a3ee22df00939240ee88891919c65994bec0c949de8142c24269151e4ff4eef30b0a287c8a3f5a74e4d7abb215f442c2b21bc223b37830ba243b155663e5b15a39cff7dd3bd025017e80b3fac8e23f64cf2fa43a33a8bdeaed4680c346d79bd2ff1e57df284a09d049003c94c6d25743ed0d5c4fd89a0052f71db7d4d78232f2b8cb92e3234900b00000128000000905be3d7ffc8c42048601533ac19ac6c8efc11c857eac4f58b4b87dce507507e317c4bb5c2c3f1220f8922ac42ebfc321ed7dc23980abffb3c8389aa43e97525b4f559fa4e125120b8cb7679965ecea3dd113303b002d5cb07ec622e8fa17e4fa66f9f8e6b18c24189913715c30e17f06115246c45f34962c0c71310bbbb90f10b08e061746dc165cb8ab5536a0e9b4b6100000090ea8bb348900aaab0c7f4b6cb5afc2b2e6564e55ec4a12465de7aaf174d19f9daadefc949bb6a61634f0c14c804255861e505c8592e96a3790a016081ce3f92c434ad76883f68a1198eb83f93beda89741e85a95cac80c9db098828b23727635780285d94da0caf2e27f37edd1db7fda00f82b9577108c38230e8ce249e51f6898f5324f8ae3a708a464a68658eed3fea0000012800000090d69d3884d9fa8db5d9a0aafdd14096fa5f5e07f0fc2f471eb7ceb7e63c843450b314280aa0b6f3f1bb394aa5253ff8f9e61dd0604ddc6dbccbb9b232b83ea6a921c60ee49a5461d9dbe51efacd0437fd1b6f66bc78f6c35e513bd1dc3250759f138ff632e86034ebe805b5e40cf97afd208ebf9aaa5b079ad436957ff87faf48effd6f806ad31992fd597607e549f95400000090077660556e07674cac5a4eef3bba09ac0121d6aa597c2bfaee86d5c1939f02e9a08ae03d6b3833d03246d9a60965316c6b7350c5025ac2ddde4b5f8a3909894868fceb23008fc3c6bb9607e22e3ccd93137f2d16027be26d718852a0fe5da7875d0aa4e1461c25b29167ba4fa8cdd8fc29fab5f6e55c0e67321b9ca5fa5cab0c4f915046a3a29c1b8d3d943a2a54493000000ce400000128000000901f717e16576c5c10bd8a10c564904c84b046fdca1cb8c83da1be094a9434f747ab51918108f291b53d01c7e48c6c50eda1057710ffaa765a18dfa1d3823575f1c4d21238d44a11f6e112394c7d3e8cfe139c215a641c10ac6ab6c4fef72b5905e62c334e733cfea1d33d2de4fdb79c110b9306b1497909d2f89047de58cf661f86bff436b80ce3e9036cb5593358587c00000090c61c80377b209c6da5a831b2c525a59a14a13cf6cd6e50341fb5f2c21a70da9162847b9f6502d7a51d345ce3098d47f6462273f834ed8a3d19996e1b0c436185e5b4815e43a784eae77bd52cc413fa5d0725d5ca61384ae1abb0462d86e1d71f4f929ac8985c83ca42b0c7350b569d70081e486464fb1503638a53bece15315d1e4132d647ea6cf7f140fb0a2c02dd340000012800000090c860d8efce5b43084983049738c12c4781991242f0e564fbb21d010bc036fd088ea2ba31b627d30279553c74c1c93e84e9abe6fa76c126353bc608ff2b66d76cd376891b6813191ad758ce5f1d5d706d1bc21253d7bc9037b6aba329c82182d5c2046bb20f69c483dd1425ab7386ffd72b1ca2d72a4d8ff1b1e1357d5a00f62023bf7dac6782d3563e5005bd375484280000009020766effa4d23acb703176dc21bd6d2bbda2418176cdf4d14998c6fa6085fbe58a4f7663892dc8863a45cd364ff06413185b383ccc8d4b8e5ab4e0186cc125e420de3fba775a2e7ce19a8fc581949522046c5371b418f9c60180329e473d4f1bebea901360501c27b58c010bfb47fc5a04e855250450a084c00e39b848fce60eb149869d44f5139c86ec19643e503f7f000001280000009068003d2e207fe1f4f0e2903c7f12a889cd97360cea337b73dcefdb3de788919e6975714dfaae6b68977271313cca2bcbecc7b036cf479b846fd7e3a528b8b90aac856589fbead14d91f63b8754c27df11d33331e2930c3a7cbc1bb32e6a349b853fd9d484c27f9d8dd02e390bb4ce2a20bcbabd186e62e3737fe3c9a51011a3a5920b47ed0fa7a563dffffb65dffd77000000090f609f0c7359598df6953914fe57a31e020154b26b4aa28204896e3528a95120740b072bee852be432f772d671bf9f92515192aee0dfc5a5856321c21233c8d7002a03833146cba22d0a4190a08d1a47208fb071c276dafa999649d42b307cf5d86771e8490e452bbefb1baefb573d3762c742280580d7376e9f4ea1d1486bd0c541e3fd46c0b1ee0d09888557bf6d6b00000012800000090e5136e1c5018bdeaebc8a84386131425b551ed9376acde8199f5c48ecc2cef6852185999d2485763ac1b1f53967a90c700bb9aee823b4c656b595edfffbbe1d6d353b587f3054b59a0c3dd5372eb3e370acda847a9d561e15226a15dc9d0f9a5255426e4228b79daf88d5e0e2548760623073a3a3e5177ae05f1197981f452c6190759a1bb1418adf90b13003b95b8210000009031fdb894dad83f81f86c6a179c564c34e8ecfd8b22afc9514c129b9dd58e0c0a9d758063fe7225cdf04075a8323cf1551ab0c2d5304703b053e150e5924eb9679f1279b3b5144a6d9273cd879023ca6806442973f54405ed8cbcf285c3978b5e6510d3cc3c3a08efe916086c23be14c116e0a7a779e86bb9b5f4669e3167ba095bc41b7402ba61931555be1506a892b600000128000000900ef862406629a92c15574c89727bbb7ac1cf45d987b905923dd49a9523cda2f6af918410c959402239a323d54ad02c049dc3ebbcaf8b75a7a6f56946a5bdb39c2762855a72a91df2f9ff850549940cf81333d8e138c20de0899285dc5051a3935384a2190ba786082974296f78b662c114b4f6915fd5a5617de5f05f922bfeb56ba57eedf2d97ec6241f0289dae7df0c0000009090484c79b1e0b61a92ec61ce4ef2c51f480b28b7e2aa87d1b2c1391fd8bd4a4b8aa64f562dc6d35882348fb1e10d76fee3cbf2b4cb1c4480f95a617e7b6347223aea6b44eb532a69e880d288eab281c914debf1a6d0dca7fc5393bae0e930d5425ec17d97b030c3d67fdb23f68ed602f15e95682c5a1eb2088dc7e82a8ddbb589175af124909e9a2d0d4b0769b9c881d0000012800000090d3284c9c659d8b0707267e8b10bd9789f2556c96260eb05798809991c94ab291e727e73ca8f4477b830202315f99233b99c68951eeeaa94899c60f9c6dac4b3f52f436d80945839b3ef755216a37b7aa156c509162c1f88541f78e4e56805ef8a29d564423b719ae3a0a50307ae7f1cb2aef790844732fd1936c27b0f541114364b54dcb737faa15a175652950032c5a0000009017f42abe31639bdc24dc7d9f212ca97c6443784871925f35b8f4a6fa43d4989898fd33ba5275c61e4a2d5bc55cdc335f96e4070bcb8ee5b4107b72886a3932ea89ee9e94d556566e0b0af98388ebfb380e029ebf47e9a00680b51363b3e3a864e1674fcab446cf3d1d01b628f9546b890618779bcdf57db5b499e46b6c00ef69ea56efdebf94e34d594407387111556f0000012800000090b132e62183ded1c670bc4bd895899cd38f06bad9b8bdd4cfd672e20c12c8afc5839ac380c6fb6e68fd0dfdf19cde8d342ca01b34d947b83c652ad8c69a70786fa828c9e9cf21006d30c0de6c72ac6dda0eaf6f4f39fdf3029652ed4eeefb4d8ce2bdb445bef9a446d0c39b88a124bcaa2f03b5fbbee509abacf7cb4b7422575e3682ca5634e496432abd48f5d19c512c000000907c87d96d0d9394843d242f5cc6c163c061fda2dae63e3f659ec53a6216fcfc27767fc426053b1267a6faf53ca8d95cc2efa72eed3f33e215cd499a5c2e75fd5e6931349ae1fc12300ce47e8cf1ab8e9a0629c6a0147758df2b1205878553869afa05c2236f039d0b8a97c0010bfb8827210fd1d69d077d5766a4f7744d48c05a6c70ea1cb5bc73df0701fb54f5e06dd30000012800000090e47e5d22930f7723ca2ed676f15853713f5305623ff0b379bdb579995e997c8cb75cc6d38b20265238ae77728f50ae219e3ea94e91d61cc8ce975cb2401ccf2651ae0d90b7469dc7cd4728befd0a6e860c629dc959061804615987f4fc99c2cd054f02fdb523bb61d90b20d4d551b9561f1ffaa28c3670545c1cb04b86d800066127c64abad06333b7f2910c6150988700000090bcee3f930412919544bcb8eea41b6d5cbc811e0f859575723836ab710f3dfa7dc2336b8c587f63cf549c7199e1274e83e4342bb679a4a310c2d8eee33807f49d1e1d9b71686e031dab782ed97714d981149d1abeb4cb01b550ddf6230d282aa12dde65a87a4db8c851158d88c961418411ed1479306291de7392a48fb0993e96564c9279aedfac6d7b0cfa4ae8c8d0c90000012800000090cc95253f57e1e449d799d9ae88f705d44fe26e4b5bebd668c618424ba0ea1768d44dc1a7b3cd7990561e78e69f056b8e19264ea97f446a7d4fb009616a5b255ecd6d191fda872fd8b9f674f442d890c92448f12b249e081cebdde579134dc7a48874aa64dffed480906145a7c1113cf3189daa1781874bee162ec5f16ee312bf976cab53d24c04016f4dac5b4480f9bc000000904776d02d6cee37a71ec4453e2952e311d9bf36f0348edd0d5b4a3730400525aee6ee5e68029348e088e7c175ecd3bbd673b6a812a7b696c6971d62beb98077b63a32e244fe8c3751bcb8d659c935b75229c50e1735b182fde7ebcc6c9fe25471c50f2f3f95842a6d37dda83bf61c766112c570fe6cc0680ad71d79bd43e90d22e9b1619077c717fb591a9754692996100000012800000090a26e57830438298dd3838384705cf18b35e3a15039693890c52c431e51448366de6cf815d9d04165e37eb33cdfc4273ef58c12398cdd2ce7b9908b2658413862300518f285306a63ab1e9d27442106b320cccdec81c096e7810ee198bc79085f9e92167998213d3217735b229da0034b15d50665a1f0f1928674ccaa57aad3e56aacfd7bbc6e8903f8d2fc56e58df8580000009091aaf6da56e346e06bc185ae1b4707ab118e17c44e837dc7898902e3513b75e47f08a4bbff9c4946fcdf9d9695958740f705c0dcf714dc386d694052e491009611ba3654c18c650bde72c4b0e9588aaa1ee848824c4047be7d47f194fb3ee26e9effc349936f6de348155eabf208f10822bab739e4ed52d9ecf749c133a17cf892b6ea460ab9d1c2d141353553ca7b420000012800000090542778661ad1536265596e9b9acb62c924daa7d39bc9708f161cc30a193d1c26e48de678cd62b96a7adba0eaff03892c3c769a5d3afbe98504326b0218355bce4d8097f73a443c30f674ea9d16b96e7826908b96d258a3db1ca1d7d3e1014acd9233deae60afe89e7d34ccc4be8a23ff1b6cadf34bd65a361fc9ea082dd9ee0fd3fc3295d7250cd31260362ef41b9bea00000090b71c893fc2dfd27bb72055bf2b5da1f092a8b28c7cef6d5c0daa9a535e038fcc9ec51b6c6e7f4b5aa65a8813d75fc186d99b6d2714cec0fd39b4dfe8d9063d314b39950a7fadcd993df3cf226955274216a0aa1a50d95862ace4750bacfdcf95d8a1b11fe38bcce3d27a8419643e3ffa278f5c4ae4597fe9ed6214c05b6559913b06b19737467b977d9c04e6354fde9d00000ce40000012800000090df814d37251e81d9529dbb210309f4a0b4fe9917300bc980db42af0eebd1b708f3911ce74a3b2cd0fcf258894d04382c48d47268ce668a558f54459347c0a0c1bf0359727d927f928010952c0d611cca1cdd23b76143e5305a250be2f3f54929a3a18759ff59046597a6c9d877076fe10aeb57b23c9c454b9bc26ad78796618fb619bc361f38aefc899eea4a187cce6e00000090a8a060ef4b5f61dd86ebc67dec1726c3096d06d6879a2474e055de985cdb00ed0c0af11506162f21d39199bcd886bc17a23df10142d4575c7820d889de0ef15580ad003192010d261c38646a1344368f2a9dff1ae5b23072b70871cd2b7588fd65bd8bd44ed7719eec4e088334e5986021484946bd90786fd4fc39dc52fa86ed7886d001d3ee64206f0c5de7e517dd560000012800000090093af15fdd24dc60a17c63743a008945caf76d4fecfb8b973db7864fa2d23bb18a75df0d7d0c27bb3e8241363f4c2b252264173e1c6478617f1513528342001d4cdc6bafb17ab9799d0aef54910fbf3f07dc8e8f7fbb24b2422fbdf5dcff71a3104d34ab492e30ae6e229fbe3b2a18f510e28ce2d665f568c14f67b707526eb6c5423057221c87e57364d4f929d92a3800000090ea6bcb48020f5d194f522ec07220f2859e160a4def93c50d9b2e3838d744402cc902a12fb836458aa3724d521fbdab0f7ce5f2cad792baa06d37d9b880a3c3a6f39b760c0e6386b2ece755b0b70709af2e6fd20503219361878ca733d0846970bc36fd66c2d65a115d05c9be0f1895a5068551f353629807bb187b328dcb93610d1676470ff6692f37aa2c7a1aa78277000001280000009045fd3ab0ac586a55781d3ad84b47bdd448d4312c21b58756bd6e866d6a3aa459c8c08b3751a69d4ed7dad3494b61cfd4c40af77d69d0f4b74480b1674d47b5c052b0c823d8c6e270dc548de8994cba06135c22ec535e8fd699da3dbb013c8104c07b036013b9733ec7999a99908fb6af14c649a5f2fdef651151524f247f4cc868ff54c895683c6c06af0ecc5352f0cd000000900221be3ec7a77ac0c02a89f5f6afc7ce0d400af4c7f3c9e8f333db0f814453bfbc72cdbcb802cc6dd87b7d2402a70f0750355f7dc44bb5638a71b8484bebc29d26855821bf0bd5752717205f44b6083220e091cd96d0aae102d13623770b3694efcada6486d31e271be9f6ed184dc138007521e86396c8167bf1e0769292d6eb44205a4e7b8d7b14882975f8c852b8ac0000012800000090f621215cbf07f263742ddf8bcf10c81af2a3ba85c2b830458573aa064b63146cc865e2bfa6ece775548f16918f922ed4267fa6c5875fccc25077f561f75b6da876e4dbfbd32a4b10af407180a73c1d04081ca4c9efdd437e2db28e2d4611bcbac333710462cbea53c2481b75bb04e95128499f0e8799df086708db8234819064cf51c67888896ba7bc0d0e89f763439400000090293e6dbdfc2c738098231b4f1c8f0d739be756ad24dfc1bab7245ce3cab2cee0293f34adfc6b2b8545cc225caaf19ed3298dc00bedae7dc5de5516804661b960984916f9b978e6700b002dcb201ccf471e22f3ff617c4874ef51397c30dde547818a89b211f9dbdf3dfd8fd0d8d3a21a09da1a1161f46869d65008c3a039637cfe18c39a19df1374483b42b6cf9767b80000012800000090985d646180b524e4b49ad555323bedfc082613c7d6979162b43fc3c7719c15c801685bcebc7e855b18aaa215f014fb290812dbe0c720ce24fdbd0f4b4953c8a9bc8bf4c2f9ca4bcf73afdbb7430fe659282277f19c72e657c3dfeb0492e55caa22ab062f983eb417eb74fa6e518e6a30150854eb71d0a8aa344b1de99ed6afefdadcca0b97bc7c1c2a9d41997fe83530000000905d1e0305028278eef7df7c8df1d39a9945c64a925cdac4b7247a7724175b3b1cee30168ca5234b6efc50c2d23e7877924e2497d6b7e4ed826686e1a8093aec5ab08ad36cd2e04ef235cf7a30a08ef19c23fb2add0dd306fa4ae8881e91ea81b7db90bd32e28829b96075805fa1cab6900d9e963ff5232efc60f516bd73a5158cfa7a29a9bb07ba3a6c20be2e8315c5c0000001280000009007faeb8e333cced938005055ae4a104329ae809af5e6dcf92c13d351487c87d3915868c20b87e59cbaa6eccb9174d56f1ad6a4922be01d2671f5cc1d1d160d9c03611572b49bde324538fb7dd8e24687297e6490ee16de68a15f0f3db95955d8bf104cdbc6c90c5c76aa1ce1b27109552f0b09ed4e193f5cb47b3f68c5b9aad2e59b3995420e3bc6540d2fcf26d30af700000090ddf990e84cca0077f0d8c4ec255c2eab76c668e84cf5ae5ce39e06aa31ea6bebafea2fc22bbdbd2f227327cdaac2118731b620882606e69069db26b1773eb2d4f245227c34ee85ce7b87f19bc235e58723aac9fda228bf5260b1e9d8c64b1e4ac89f788b294e2a800ec83824e152379a1408b5e850966e49836a51af8ce92c211b3ea936557152c88fdcc16f3e398dbf000001280000009010002d75ba1ff4554ad77a06af2fac51123649ec050a90597c7bbf478b34983b6f7b15944b5efdcd8d54e4ebcf40a56026345a578bb526cff840fd54f335c002673717bc46c72a97dcd059a2d611985e1a19a8367b402f52524385a5ec56e6207a9e7c4a10e84fac572d70e9b3cd1dbb1fa7fe1e39bb6415bbaed8f6303a99a23ec054507ad79c9bc29d0dfc0bd9447b00000090f7ccb463266a4ff7c273e9c0a136956b7c6c429e2ab773a18576ba75a23b8f8f543493d5adc9e49ad9d30b0d3f23932d60020d2f2847ee8357fbc6533eedc9be6b55d81d87500628aa400d331de9d83d2a3fda76c9bdfc820d094625a4596e02db3e604da144fb834934a4e2d93d133e0d404301278631650b7b68bed665cb50e03f214684d822e14a300a71457778e5000001280000009080b451e6c9a2c420625c89eecda47b21b03a949e5315c38d9b1c39e59f5009deade992bfd878ae2397bac5d4bf2d0284aa9f860a70e6f41ac3b1dc5c0349c2b5585f550a5fe67b70b817657c92579da82ab5ea0d7f61481f802c65bd54b3c87f52dae10c80db0c79d9fa1cf9b45b7da51fce4e7fc0463b489c0512b1165f3f42c75ce5eb050843318907374e280d31fa00000090b217fdc174010515389583c88d932d0f285943bd9c3357335e36caee6b9730f391e6f34c191f74f64d501bbc72d370e08cf50504dc2ccef5073ce027c9ab057da6338d64db7891f135a8033c395e9e53206e12f5ebe3796201c8c5fb6d0953641c5a2e89efd038aebcf9a0c4f50d1efe2464346e02ae75c843c6b11a1cd84a1b996417e45d4b9632e9dbff6b8db094650000012800000090e93cdb4a85f24cd964586f1e9702d831f03a265294325040cb2d5510d18d4a5186074cba2d5a70a0a862590867842de3baa87c6ca244fa5e18445f78d21fdc092b3c65a21f34c04f69e10c201013efa12b63b34d3a5f84f6ed2ceedc99608fbc6877950e61e5c971e5d0d70a8a6c65440c083a8218ba4687f3c1c60a94a5a5fd312276373e45a4685282a59c347a5cb200000090e2b0dc32f29f76e093c78c03bd76fa41ff202875dfd2d4dc7b699c2bc3faf4bf2456d6c69ecb03c27f23e8a08f6234f58aa364dc86f829db03509e4076a1f2aa9937c64cec202f020616b3afb1808acb154ae4da1dba87bb1f7ef9ec18b4f81c93699422fbf92201ebb8d6a9051da20d09fd65e6a5dd210d275d2ce5812a6938fe864ddb6b2f2eda2f97eccc7e270cb90000012800000090dc850cdd754d5562d2cd0a79a93dbeaa8073e8c59be2570e7baa1fb1c4708bf5d247b4c48f47da5504112331264d08219e885e7fa72af442e567b79cb2e47bb074f50ff258252ed089b52d73999ad1c6016079807c678fde5d22a5882e20e8444b3bdac43c815022ad11918c83b982cc23b269e045508b459b0147df499459b9cf406fc80a366fe92eb48fae1ef2f020000000901d1f47c4c1cb18a284d574eb6dac526160fce963527d2762b13f81e4410969a6fddcc1f847fc435907806060857bddd7798b4b04001edcfab63ccb41ec96fa3ba28f8ecae989f85a444f4dbbc226a69a24c309b920b961ba352e9ebe153e51137ff5afe88a0c6e1b1e1044d51904c31305b4180fcf006cdeae8184dc4b5e2e0f1fbfeefb57d3309d45ee8d924f0438e50000012800000090c00446a7e4204241776d5234a2bea9ed935e437d9ff8d31cff62c072c294cd709336c171c4d2008a18633174e321640679b645b4cabafc5702f8936605d9825eddd72a4aa53b6899d22642e58486ead90e7f35b24a3beaa472dd3f8be3c8b65c001b10252457d252120c8273f645f52c2a2cd4485def46cf3368fb5e4703f130cf1b6ede3df24c3cba58ccfbfb5c1d710000009022a8ef23801ff2e837f3e5db3361c6897db0cebaebfff4bc19fe2de194ae245718259c23897359d07e8594d4086da22c0969b3cdafdfb20b6df113841c3e2520b776025831c68c0a2a1dd4bc581df7631d6a743a468d357ea936317efca7f6ed04c1be2dc7e6a1b829e3c9fbb423224c0813db64b88a639a1e2bb0d28c118f29d9aea07e5f7eb68c0e6c044d92e6c5a200000ce40000012800000090e2bc3a48af462e994976367fde39209c31d47fe41a4f37fb644f56fe6421a805cdc7cab167dda0238e4b2d6fe9ff7190d5b00977da7d3bbff603adc831d7b5c2991bf9b8fa11f7b0cea097d0f2f4437401198ba8112a0bd4bc1f536d844648050559ba594e2221f41ff991b831afc04c16d1e2987434b415a200227d598641301debed676bc98f6fac8dd6b00ec3d5ef0000009090adc3bdfc913e1e8f6fdd10fd6e3b62f9a64220c762fa0e0074c2b6fc4f61c91fded0e9f550dd1fba9ae651f1ac0450a72f1b41be401fbf02f969d1a3358514748f32d4093cc1c301db661942c58b49274dba34e513a07634442e055dc224fdd4954bc4f5ec39b56f263ef83ce6d81105dfbcf76b28810a08b23399c067c0730cd643ca0a71c14dfd7fe6a7ca4c7cb80000012800000090cbd5b3d8671123dc24f039239bcb164750d2b94f9e10b011bfad3231ea137b6ca803f15a5adddac120f372364e74f8fe2503f3ae41e6e159d22e02e86eff74db1af028b4d491ab8dd8ef1b712c9454291d8e74b1faa3a9a3a2897661d52b5d38c879f0ee6c25d9a4cbb334b344e0c4d724c3310ad42fc29094d89c434ea332abc10a1b59469f892b4fd60b01bdb4fa9200000090183be88ab1402a8105ce14826e74cfd26ac966dd9c06b2fa1cdf0f92d2837637cb37826e4c05c5207220d0eff1a8efc95d161de351749daffdffc974d40d50412fe80440ad1f03fbeeca8b4169086efd1710aedff6957061c9a814b7c86fab671102290d3e28786784e925f5fec867cf1c64cb4e4d2d7e9719ee7ef0ed4b1cc0e4de0a4d6372de36162ba9cd661436370000012800000090492b1ab03ad6554322c047f02efbdd83ed97509f1820395508471b0df7ed58d463e3b73735051b72d82c513eea1b98d4d51cb7b8ca4fe23651f3f5155f18e4555c093b1eb6c2a98171b714c6601f440224e4f0a5e1cfe404f51d314024cf5c4b1424a7dff3597204720623c0d03b83552ff2b3f159e3764f400465a9637d4d5ecd540df7f378b00858927e1df1c029be000000901943fd9faf476880c444febbdb07802a24dd21a945512a7f86560d1acaf786801b297ee3fdad4d14db06afad27c5181aa8c3ed4db540f4f819866471204e2a7efb9903839e71df18c998f3bba2a5c6e504f43bc05c038d0e7301a6f57bb73e9b3d346dd24bfad2cd28024666d7aea47d0a6edac531b795820968adb825f07da1aa3da448e6bf57880f81d830698f1f0d00000128000000901f0b90e626f010f5f9b965348175df86cad98ee79276e02f5a8ab74d96ddfdb75f1da24e300f6252ddfc53c30b7d57c58977a242c8bef37ecf77e7afc8527172780ff4b8bc2e1b52696dd1c6b79faa1e243e88c996d3cf7306f4e3f0062a6c5ddf4d1e0efbc34adb2bea97f1904944270fc64104193d0210726362ad9fe624bd2953651ca3ba77247afbc581b35df64800000090e7ce6a2a5ec7cc4b32e12ba70c1c491206a85c6bf637dbf7ea3e9ef5c52fec6b421e71eb44fc46950137dc8f780d2bec886dc91616afdd2c700c24832cd53fc692a92a3aec923e85eb8a1421877347cf1678ef20365b09bee2f356edeb6066db70c6eaccf4e1afc436136c5acc6ef42f0a64e5fa94a66f3c7ee8fb08debbe7950b0d0307dbc49ebdd86d5295f53bd58d00000128000000905eed1effd49b3c182fd72fc371f22360fafbc935c94329bbea121b76c3f47c10d7a24852dffbece757558a2a906fccf152698cdcff1368c5ffb433e3b9a16135ca0058af88ca48bdcdc00b6e7dd0532511783b35ee2e85bcb2b5c2a2a0178b8bed4b7dce99d2ed823e9ce610b19b8cc62684e4c14c6085508b7e2cb240fa6efd4ea0e755a720a019e47a1b9ead8ebef0000000909861d898f71affefaa9c24629753b3e6988263567d48672571bc46f69b65f35e0371c72a53ab087fede69bcc9bff623055ee1426ab173447a6cf84ec2fdbc151daa772f1c24de647d606fe99bacff8f000b17c743ed65e5abf0d5f7eba1b53adf37c43c6dcbfa399fea776af3842eb2620fe73dd99bde3c733b7966b9da121511e389985f51368d69dddb05d8ca4a45b00000128000000904f4079d8a2b1fef6ab268d17e10f748d360790081658a4dfaf52931efffe7c2f041923dd29a8a0b5ae7c0a16b1915d68921698d3c99351d8325f4da2422360df766a7bf49fab1b29b7d873951f21d3840f521987c97272fc20d483ed63f6a461273ce23bc3aa6dab2976243655248c0b2923163e782dfb8bf27c3171be7f86da6231fb2992e539dd1f4743558826d2e100000090a98c0b3206e0ef65c45ed93069c78aad33e45aa2bfb121a7e5a45313cb5758c6cd78dc20411fab5ce6cfb52413a4593a8afd3b8198cb753cde0a4d96d3839b66fafc974611b39fb9aa04a640c4e251800fa3ceac5567b9421a19ed92da33ec3a9b145ed09ed058837cb8d51da7bbc879052258bdaa60e493eea98e24bbb556d300eb0206ad4a2b336f3ecb818534533000000128000000908aa7ae30702c869425bde7798ed24dadb39c459ff83ea139d9f6ac6e06a984475cf323d7d45e95c240e346e393174c3d5e91ed9a4f05f497bfbb68a6168fb83d82903c1a5bd9513253a2049abd087d5a297db4b7a90452627a890a7fb5b914af3733951cd13229e60c4c72b7f8be532021cc9049bbe19b38a40ca1f5c1921060814928dc8383345821e4fe686c3d30b6000000904811797f420982fbafd20c05b67a7ba97ad472240e24b1539f533fd790c8b31559ba3b593391ce329096c708d20cd8104e7c834b646ce963c5f634cc4c97b85d2a923fca24d6282c01eb098c33c81f8829c69b93ba28f54c7d0bf2bdb9fa695ad3e2fce86f02adb1aa053ac1848fc01e04776495af37c4115237a3fb0e833cfb47032ba8ab4686a7796d23d5e36f9fba000001280000009026dd418e127c509cdb836ab92258ff19b76bd5e36ff73901eb16b3a6bd3a84df61b3657d3f317f95852e0d723ccf96f19b7fc91655a6a597755164266cf8b99becda4a71d594a7469349cc0bc34e3f10062716c1c60b10662c4cfe78d21248409ec50eebca288509c0a0dbf5f320a21b28dec7530b02753f920944d3efdc7d7e59c0a4204ca900e22aa59e04c5c5a6f20000009097ec2bfba0e6dc44f0c7fde2a6b8c08da93af4b60313d597ea441cac361dae66799037a1fc9328b37850cd730a6b2895d111bc7a80c7d94ed8dbed022736042e579a8a0c96e40abb5f61abb1536718f51d87b83c4d69ab74c99be50aee9ceb67d2951a16b265e9356e264c200dcfbf2000967f66bf7f490bba839a2f4a73fd5c15677f6cf311b65672e708eaa2503d5400000128000000903d05177da328f50a6b1735b7f3c7ee275b145e2effcc456a0c5a2b6b85366acdaebac9801eb0510cd1823bd01139ab5d3db0f38d2cec64e653a14a0c5461c5e2a904f640d4ca3bafbb0b0f4be9739cf80bffbee46f92294abe5558926bab3118826687aac02ffbf1d68424fe9af65b2916ed9211d0d3d2d6917c658545188720424ac98fc35342de7cd07429def9422900000090e1d45e36164240913087d829bb92535b93c0ffd41386ba5c3d276dd57611f6e68b3244f1cf5f75764992c8c456850c135e3aed4486dc85eddafd4921cccfaacda04c274181cebe2ed0e580d1350d8a3e1b4777640a7126168ce8772f7ad20463a3d5b9c05dad1c26afd2e9cf762c3e6304f289ac1d13c4edcdae63f8277af15e80590889a55337e81b118ffcdd9982180000012800000090f0f12e1fa0945b93a198c6631fb878417b46cb176a2bbf347eea9ef4d1729d28e940a208f2a1132325f403a3d4661da1e1d0b2544ac39ab2c6023e5fcb2ca1737e0a545703bfa9c4ef3f90dae7cb42151e25fcbd5964fdb9002517105469c59b5482528fcee58c786344c30cde4caee9040346581b540d44d1287d963b5889a0066dcba50ad62940317292d9794cfd530000009078dc1348b125a76fee5aebd336661e4d0214c5cbd94fcddd08c1526f67da9b789cf7bb879f6296647396073b4036b462e0d66e6b45c3e602494b8c99024ba54090fa7d6cf9726b49b6d22aa7bee4cc33096bdd8e3015a9561d352e009dde3a772739291878b2b17e96ee8c415bbb6cad1ceea85f24360cafe7a28cbe08d8074605a72facccd92bb307fcc855d413f8ec00000128000000908d2a8d2e41f9d850def8241eeb22d8fe08c2555c618b155b75d95e96bdb0b0b377cd0ca2376eee3307cb50328931faf5767ff80eddb2ce21f184b7942aa019bd8e60a881715e6c382433e77761296bbd025dbf23d1b00f9d25dbcfda67f9b4ae86a387fb7bdf3c5241e0b78c839b90322a7e03779942b0dbdf47c34b13c7d671358b008a96827396b695f0ac3e32894000000090df5748605961a0e6be2ff2e92b6280110752d8a76a8ec69bf9b7f4d916ca4a5dfede149be73b24e6426e993ded9af3dae9ca39f2e43363dbd1b36a9ec44d2b7736a4936a16096c151be8f8a3f907ac33116b667bba9a8297de6a994b2b7e34ff897749999724668a3753d5caa80d571b0bedc76486de3d07973636e9ee1897e7e62f94352d22ec90a956a16db6d36027", - "calldataHash": "0xf4525fad966caa2a5a1c5c4ca03520c2652aa2835f67fcad64b97e05cfb2870e", + "archive": "0x238d559a05a8fef1cbfcc8b7e59836b7f467fa8e93d433bfce8efb75a6444448", + "body": "0x000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f000001000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d90000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f000000000000000000000000000000000000000000000000000000000000071900000008000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004410000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000048100000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c100000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501000000042ea6fe02855d8c72905f35f08604467117c037962e324c9a793505138558b3700c94efd9afe573212f9bf596ca3a4b42ae57f59e670a7cb5b9440c54bd8ea2961856bc4892b0b3f156ed2aa87463c389bfce0fd675a37cec77ae5d753fcf593c12f9d3f397c2edc9e4a6a5e485641163525ca802e3bd93994af997a9b9a44f98000000000000000000000000000000000000000000000000000000000000114041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001180818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000011c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1000000000000000000000000000000000000000000000000000000000000120001010101010101010101010101010101010101010000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd0000381000000e00000001bc00000090c13d9d0180efb0cf4a6d1676f61f735ed5237557862809c657aa892a154646f002740dcac518dd1d753b4e8c83cc4b820d7a92f8d3455ef8d6b782406a966e38abcccfcba2bece327a31225662a0e51617a0f49b0b6dbffcf2dd0fd020106158903111091982c078d4c3674969f364fc0a71e2354ba07e5794615562312bd212033dc0cfd54419fcc5ab8efdee25f19100000090dccd8f5a0daa473e34d076eeae33bcb6afbc88dbe6897c7b315149811fd15efac96150d7e0fa1579376d42f4b911e155eda5ee5456a9d6c0a699643c6beff9cb0eb2e1b36cf3fade1af2b33ee0c0bb472acae19d029a57a53882b8ba8389fe0e30429fdf159c9693fe2006334692e67b1b1fcf6fa166824ec7076564e555e49dd085a8e4b54bb1ac0f18e31118190e6600000090379379b71c561c7622aaf4ff0d200b4aa507de6b631c841e84ec50b80fb6719d5278706bf3400d47296446f1c13e75cabe1732750f02a7ba2e278a6f5b144cd0333519ed882d956d16cc45175bd00a6c16cf2171d48057133603ac31d8bc578b9b481c0a2040a5725d0224e373b3f043247e2bc5856e7216bc45fa196168132578c74e26d88b4ff36eaef01d3c7f915d000001bc0000009089c7007a588bd867a1faee4af2137ccca39e4d930507643479212f21630c943c6f430108f4bb721838c8f1bb34ff73841fa2c37934cc6e2cdbcfda0e9c468ad150dddc942d41b76c0758433eb4a0242e26e30592948a866293bb4e29a584a8907676dd085cb9360afff7ab84ec5801fe07a56a33221144d05716a7f2db7ae035b7e80a56341d289af3914b0721a00d08000000902b13f3df874d19d5829282e4eb39007639ff7c211e86e7f8be619ca4ba39c5d81c8d145a5192f4a3f10895e2797f2e25a7131a1bcc6b1062f6af45c94d85de2c419ff98bf9cc3715c1039b2e8ed4ad6c0499353d1db9426370e35a27689ea1b19ae662edc37422f8cb8592f9c6f8fde61dd54d1fd3bfbaf5023d7bddf2311ca15af50e55673a51a0a914bf4532c9722000000090539a9203f6b58beb64bc593fcd09ed470344d5394aa75974ffbf7f996c7b066a8f2175d3e9f10ba74227458fa6150ea458ef71baf2845c3ce67f771741aceb9abc9ec54a601399e81afd137ad3434457239ebf4d9c8c846abbc844ddbf723d686b365611aa69147196cf8df5c22ea6dc27f19ee20cf6fc0390a49c304a851e624db98d7e5ad0f450c3c8bad71b4a5de9000001bc00000090da222fd69c4e340b559c3dc9bf8d0bf6008a106d09f504acc95a3ab1c93c1481e2e2704e786271b93745fc97c7b0788a6eb74aa6e72c6ad2b6877d7439eb41279bc6107b7794a16257bbb4d0a20ca42303e778f0158c37a7cf4698c7dc402292b6d224b91f884783885a44c4b22cb2e1197b400ffb4fe08750914ae9639d5447c8bc64ffb989e07b8ce53a2043185c94000000908ea72c947ebf55d77062f0b89b668a142a198842dbd2dac59f115887ae962f7c162ecffe95eb0078e9ecc34874060fcf3da11c14e08a92203b8fed924ccbc787482875ff28aaeb45859aa0d1d01db986137c1764dc112f53424f750a28900c8c53e6973557e33d7376e0730bccf2a5d606a3e795498757161646d549a0a5af18e3958557963648083d6e76c9fc6ad1e100000090fdbeac241ed3f7ca3be7180b73150eef39d6a366bb834fa7903267719e26e83579db2cd65cb64ea43a9d203f5c8d837c1efa6325e91e032006a7f5e98dfbd0eece6aa4c7db4415259601ddc5b049736c0bd34df57ddb365dbc441b7905adc29628e5559ad6d5b3bfe0f0392ebf43fe810d8a808231fb44958c9a96fac08161ac0956714bd3c74d9c851197ca7b1a8c57000001bc000000906e199cef996acff8e6408667d2db579909371083a2b40e70dcd78a3b6c655ee906d32a6a2e4bb9d1ca738f6423f006ffa3f7ceafd91e96eea421645efbb0e40388f9687acb66dd29aa5483254c111a831ba7e8598f6360924da54146a7a03d128a412f9e3ffd0397856b66ab9e8b524925cd75b0ae28efbf9c70b3f5b6a97e3f035453116809651ce45021ff596167f200000090dd2cba45eef3205574b614aa62165a4ee28430fff5b14a32cd63328c61f81579edde9efc3dfe5d7dd1526640f56ef9a8413c7c404907d88f32d16dea6f5958a9f56abce2a07c97569f8c26bcc74f2c9d141b0c142f32949e264a3fa9d1e77083e8b916c2df83261c0da074fc461a2bfe2e1c37540455dfd845002c4b409f9226cb252a4f11eb97706bb34fa6679068cd00000090e69c94a722b2f3cdeab1fe8314357bd692975c2261756d4f2e42893ba0bb2bebdb3512194c20a5b67bd891cb60c2d1968dbe96d5484b4964a5929de3c2a5cd0effa311707ae0fba27fc768c80f4bce83231d783024d854556157346463fb7012bda42dfd618b0aca7f58cc31dd15c6972303ff2ed3ae6d388f478577aaecb76fb12e7238ef29c2e5505477eb86b80477000001bc000000900f5ef582e8f2b358a287f69fb361c846bc362796e2766f502d677b6146517246b69ce262540e375c2424a887054b16608904482f40ef323763ed9e7f299404f25d608e6e0e4bcda16a92354986662e882eda68e23fc827ca6597c85e7b2c7f1a5f9409f6c7223104cf3b5dc3bbff99071977631eb91b2113c5fe3e3ff3ddc8da3bb01bc785683396c5470183f910dab300000090c51abbf871caccb44d13c60c2a6f8429140005f820b70f74077aba9c7f32cf74d9ece0ce1b24cc19980d787ba82d3f9186ed2d08888626deeb8ce1f74846c70ec434efc3e33bfbc86213df64cdf73fdc21fb971bde4dce6ce0cf00e204e065c5b1f57cb613c3ed8ab6e54d31c1636baa264dd3ecedfcbbb1dec253095757d12bca1d76d2631ef94e76245798dd47af030000009022d04f9051a6626fdff3d609739cbacd11741343c4d8ea3177ca242e4de50b37ccad4739ec2c882d5d17bd084f1d3fabc72268d28193b522600a4fb708231e58a7ef5b23f91389137beafd14a7d0df55048f605b84bdde04f25c61ba7101bd5c58d397375879af5a4ffe97152630c801260d6e9ce6fdcaee074e2f665238668386b35a772a861eb4e9b3fc3556ca1974000001bc000000907e2e2070eba81d16a60b826b11ad0a7a348148e4da106d6e92e01e2ca53e99cd643c4faadb85efa26d2686e15df7111e080d9b2f08b8d1799dede4f9091005b95dce8018d40aa6bf530206560bfa3b6005a351fd26639df63ee65b51de7b68e077fdc01ea04b73d878c3895dc223130302ce398479d642a13db0eeea714edbf4b6011a4dce09c1fa516a27aad43606e700000090498ba863b488e2698f2b2020eb4c7927ad3dc4c9bf3d7cc556c123db1ef46dea337cd5cb99ad0b8e521103a54ca7444a8230be7749816a240d8b0f88522c629f98bfc97d8e980244e4aca243dc1d8256289d3b37f200f4c5c9f4cd63a3edb7954c75d547577a5d22bf3f77b69953bdd323b82b33481f27c55dfc4f15c859fd27da61d786836685a16122ef59a7ca7ac70000009046c3512b1c79aa1e065a8e4256c595c9293dca1d56fd05a119cafab59416499ad8aacb94f92d99388f774ff6d7d0ba468fdacdb8d8d595c7be3ac58364d84d220bcc50460aaab158b837c1f834af3bd918cdc85c632337166ef39a085b6112604af2ffec61e77e9023863308bd2566751f5437bcf1ea2387b364b9099d087cfc5bd0e26ecacbe348de1b418d55b4875a000001bc000000908adab8f017417b5bd46fa1e9779632be5afba45eee6a58daa7754be749861997acfceb86f08f30b61ff903dd7acb46108739d67425d42f335498d98640fef4cabee4bc1593be601b8f85aabd966b24fe2147a3b6a75dfec1d644e0076f106a4051769f6aa62715d2e62bec25379e3fdf2091a5b55925577c3485574e37696c83a970b96c169e46877baa784d8a7666c6000000909d4bf0f2d2de7b2396dec1959f7b7de8b805425819c8b80798cae313d89e545d8025ff56d9a92845135ac58fe672a0fc92245eed345b5859f67540a5c19c80c499374d282f293a6c6fe12a8831a09f4a1107c3e23b62b0c34d7bc37d1fa74e9a6bf158f1890db25e9e5af558a463c85f104fffd61d3945110ba4543ff2a78e36daa74aea25b0e4905f0b76b8102901b5000000905584f775caac62723960eaffd596a5f64c7083ddaabdaaebfc2e60fe575109bd1e030a83c7d98fefab9494250ea6191e111f06da98f325b6db114b081d8277593d7c7c21b59248510cd872041c66e8480b33673cd6947e1be4673318549d2fe339e55c81b22301fe039ed1f9aa1004d51492f446b0797f7f27076842a05de5d9c53a8f0b45987af90fa814f5014c7ea8000001bc00000090e41c2efc5d16d3c931e59cb67106901c97b62ea2e65a49df476d10bc4193d36deaf6fc746c076bfeed7572d833c13ad4a51c933a86ac96ba919855df3c97b3a970e095a8de48e656eddb0630d208c43a1ef50bdfb97e408c7228fb2a13553807cc7fa20370e6b1818b11d43242ca70fd2686012dddb4a7920ad9752c93b0d8648338b7d453efc270a19cb0de5fffa2ad000000905aae1d893ce8543ab9ec6b411142dadc73a5c8d4318ea84c92f1482f3ee4c83be1db4e4f24090036eb9aabdf351325fc5865a36ec5b9d8fae372d8e5e42a97872d7ff6161ccbcdd20d56f7328bdcffa2090edc7fa952da75dd796b3c24f7a505acf739c62babb1016e67198d76ee4f7e1fde045d25ee1bab55b3494f55648df759e89e867da0cd6595a0916a0714905300000090772b55f21dcbfdadc07da90c672dd84e3eb7b887beeb448cc1170d05aff5ed6d2a0a67aaa36d0b76ac95acdde219bc952afebb74bad19640888f01e3fb2bdb8aaff26919e5b4ba2963018294487653341bc08d07c211cdea452937f2a2398917bec1a4cbc26f5a7a276f95c7827955e71b7c0d5e6b2836d8d81506520ed72933ec1356eb0e86b950100598e01736e87000000e00000001bc00000090132d9159c2693b4605031d9d3a8614931fd0db820cff1586861610a76845ae37c482268160a392d9503f26c73e4729eb9ba4e48e81ce46acbba5940b5befe62746a0b0d404d6d2050905640ff7ad60170968822a7680b69074574389dcd34b1bd979f232d474a3570a95c3b2720db7a31ce639fc503648592f9b394d65aded02aec9957f94fe094920fc061885fb59bc00000090dde8d4d0b0994f657c19ea77b96c20bccf7b42d2cfc40fc66500b6bd4b7b16f72ed38ee66714fa0727b946425817164bc9957a9fb8e5f742010a8b25824fc0b59941700ed1be933747bc2f18b35a4f01192bb2cdb5e56b6e94f90de95f2d9c8cfcff964523ebe0d4fc7ce9f7ea3026860ac8cff5739701036d90d352667aed8db6aeb4db8d1fa8e6089884c62c0156f8000000904153b073474c5db528f4be51601df0112a8d4d4ba2f2dad5ec82ae03437fcc1e1285f240c75a7713643657728145511fbd10da85ee19bb331be6067e453c6ed6a004eab94cfa133987db6b24fe4b4b5328f6d5edab27e61ced83baa42c7b3152732865ebc7f220b1f139fa6f27d2e05928f542135aa723c11ff508b83338960cf2e075bb43369b6ed46f309ce7e2582b000001bc000000900996b066ce34966c5fa8466a75f45ed2238062b136cda336793b7282c677d084bbdeca74cd1e06ee73e03a4b2319db173e6355dc2cf5eec9a1a0b85dd39b9ac260f7cbc3822ad3891e3c993c082dbfcf1c099f20d14abc5f4eb82e6dd7365592bafeda7e046f7f0396ea4a7b92e91d0513745d615ecf41c7bd8d130985740dff55a3dbe6026a5e80f8ce6951608e9add00000090ae6ef7a3a04a06aba48c357353e6c650967659f01659407980461c4c74de0884f0710ceb1572c65bdaa13b1de3c7d87b2d7ea4c5e175443f499cdcbc419fc4cfc9a6ddb7f4203163cccaef1746833ec62417f587cec58ac40abdfba21cd2add2927c04a6a95289d9a28ac577acb8c595239d5766d3d4c2393156ecb2a13f9226fde236435950396b6a56ee1870822fe100000090f5c8a05db5087e5ffe39815fcb37bacb14bfbf2e953c52772196959a95d165b703dbe921570b16991e99e15b4e2bd68396c4db8e97f4160356add145b3e9ff608f530f2fa55f9813930830f8df5a148e3045546abafd7f81a231ca7b975abf2962a5dbd88b969e5690eedb26ce4d3f30238b380c78bc2d1e4d2e5e919969cc45e415cc276965ab136d16a69cf34758f2000001bc0000009001df829a357a44970ee6cc4d401098330479eb359c3f69bccf7858c574097b6534bb04d7e3f8110b15c79e3d77ea1fdbefa57dd532ba43cf31660e9d4d0afc5b16696f5ff10e768ccef3128d6cd4792909129b9f9c4fd742f07d5a5033662d2c73a0c29d3a3a120535b776e0371fdb32198861115ea1d29ba8d1d39c9a36ad5c70ee0a28366ca0b0590c87e8b5b1453e0000009051c19f51f06efaeed558e6007aec37232a35fb7b7b54799b265865773dbe7b0a0a21282c2e7117651bf2d581ac8b040853c9a1be9b691da9d69a81a6ed5b2f186b05566a1faf567297233df82c15e9b515ec50a7779d8b2a2ce03c230e3c9131c6fceb6ee0257c924492c071100715422d7393f65393f3d52d1a2713d368bf37756f50a18bdbd23e4a7c9b80a6815e2d000000908f2cf32ce81164301b92839f7f83a03f1270b5b93eee777ef10865560ebb475dda85aae36d47b71dfb84331af504fc7e85ba2691d5c08719ac8146c349c9a628e6848c67f3a94d4955e7e77dd73439602c8baedd0694dc98d7b7682d9a2be35064f90b4cc40d6128a1629a383a63e68b10477a7c93e1feb16d9d01f28250d981a0014364a7eaecb958a9e0b8e1fe2794000001bc0000009078bf82480ab9af379874a177f5131c5737a1d315afb04bea2abe470b5c8335c41de1d90ab17530cfd4df0c0053968fe763c4525fe11d27e3831eb0dab5ae94a051be0afdd96c5e52bb00a90bcc7240f007808aedfdf71604a531f3106c8b532736c54d7580f5db68859c9221a6a246f32d0fd2fa766c225e76c431c23b15911c72a6a449b8b332d59a0ffae46065d37b0000009079c4088b4916ee3eea335fa522fb8a2c817929f79779914a6d70bce9560db262320f4f35e377461640fd8f5ed83a8e2c1b6a571b50dfeb335f0ec46eea761e1255947c339d960afdb69f462d4b4a96171f4c0ee5369eda087dd385d3a73553d8f69a66d3cc981513d3f7b97ea277c7da13c5ad6625b3719cc9922a33b900d509372e65685073456a9689d8f3e671cf1c000000903e43310f6a0f4b45a417eda3bd54c5655b6741ce1bf8bb52c759432201cca9859fa2bcd9d25c38eae0a2eb724da6bd423db952927ebc9260e130c594f2573729e52c01a8608786d48ab7dd4f9539f1fb13dc2590cd703450457b7f2e9ee5efcedd9bec09482778efa1f2452087b5ea2608c16ede459ecf2b771b8348b00febdbb4c743a887bf22ab9db65591cdae1ed9000001bc000000903df172e06543a3182cccf2a11084765c3e6bf28b0e0b87b78d4995c5262966bf6e76411c6af26edb7ff83135231bd395d969a78aeabbf1a009b1e92aed0d46bed700fbeec8e60bf18f004dc464e29ab425fbcb2f9ce3eb20afa7714cfbded8ccad46c7c6cb6631a19d5305878f91e6650452bf6b77000046d7e5acc19362d74fe0d1d7cdaf7828e4584e8c7ff5db0a3a000000900e7c0465de744c7dc835b984858450b15d0c9068d49213cde3badeb7b0ed7ead242ef5fb2a36da2327effed1d6e1546ff33189c5c9d8985ee21465891e46c287cf13c5fb8fb5f3706847bb3b75c11b52156bf5b51d8b7620e6790601927a544c713b70db2740e3d511d9fcaa5f6d146d00cdabd162b35f6d7f4f336e4e7b33bbcefb0a8d120108dfd68e915fe346a0e000000090ba5272498ab1c5001f484d38a82b91f3a255d7a5b0bb835742379750c42a449210c814730296432e381eb32d239854ceba60841a3e18cddabaf0c128e9dd673197d0e2ed6c6431cd52ad32a107cd955900cd6b3a0c054e77edd28d86860c5f63a5c48ee87f9b9ef71a9b3a72a01ada8a2490ea1c08b5b48f642f4db559159af3dfb462406abe387e350171ed76abf47e000001bc000000909d08c99ea2da1e2e868070a52b6717503ea37b1c4a801458bc5a5090b2d976e9db9f34b3807f6b9f066f6c3db6fb4f7858e31209b97e6552af165d4f144a2b92d4f677db6964c37dcdbc6b8f2ed48190073dace76834a34d319c7c8008d07e44640bb1db4b6ae72c174dbf5f59c7e304145c4b213d5e30dbe7cab6c50ad3c43ac5df01bacaad452dcd852eb8139027c1000000902f2f2f4042bb83ec7c71440941752fba92929c70e6bbe524fb904414dfd4ca683490c74a9b707a8a94de43c7aec160c4025390ccadf8333c5a217afa28258e83dcfb7c085eed7a5cbd591cb316bda6d60db2c649515dafe5a34157bf952a8837c0f266e9bef1e8097c774c094a1e3fbd221c65fd93c3ab6dcc3a4c72e9c2b51937411e9e935f0e368a8c17b722733221000000902ba5e91c85c88efefe97256b0d2a285261b9f3f766ece5e6ef0d19086b13f410bf9a24df9f0cf17f3abc9fc8d84145ee0f0c05118ef0d0fa0d99320f5daf8b1307513f7c46a8ca355821b98dc7e409a029607cad1fa4290d08b0f377d632e8309fea56003f2abc8f8232157eb0f99e831ec90c50c5c0d90609f5b92bb81cec93f57ebf2e8a85934958ec194a27919ba8000001bc00000090acb6759efa9edf780a8696476098e2b0e698d37f0529cc7e07771e20805ce183ece93a6d8220fe5e41f8f2c4f66f7d7600cab1e5a432239448a4cafac2664f29706b686ecbb9ee7a585e07ac328059a402ff59578da4e6c644f587093d3adb925e26aec2feb8a0ca70a89f09e36c627a07281794087566010deffa8026376f7486b6ba38e3f754db746cf74194a4650a00000090cd127b6b398aa63a9a73b1761bc918762593612e1270efd742b9f44ea325f6a290fc37ab2e78d604f3474b42314cdc14f10515479093ac62e7fb8009218217d17dc2c1be6979425d1f99ef36d05a258e291b3a3cc7dcca71187fb2469a8210fa7d944673c6612a74f7fc91d0d740d4d2201bfd7ddb9f169445c7852cfbc34c98457bd126da955e97f4308dc91310a9c600000090e9c97269047e138e4b47b8cd15b47f75db80aa24ecbcbabbae439e4af1f5554eb1b18500ee95fb4e5fa9fe8fa1ebc4b2352662ad8e557221c17098a3323418c6a5c6e209a9eb3ea6150a37bc5a1aa7760b77664e65a23da337ef538d13a8f322ec6c0cacae03379328a80650cec29a9705ad4a8c798250af9cf409b45074f75128973eccb68e627e2aba87bd1f35dceb000001bc00000090090959743b24692cd5ea95be03a90fe28eddedffc9caa45766141e1a454ae3aa88b9b51520fca9fe0ccab25f78e313a27df6c3fc31ca535fe4d5ecdeeb4ae6cb2e9059afd5036c342d0998d511a835b21e9baad20c0ef3c5be298e5273eca51df8041d08b4f88e08fc3695bb7d3f126a11b4f9af53680091d66168b8b4b2ac9b112d58df3acf91a5c1cc86e6f488c65d00000090d05387d02c443c7363d680111021068fc45fcdfb27d26f3914f05b48eb73dd6495e00c8e192dce422f7dfff826c41e7a5c98efc82d56ec2a1856b46fe18103dfea5b416ea3abaf2491cf6cf960bc2e9f1d5203b3f2410b36bc309f7fd06467953553d215372cf74ce674127ceabe66732d1fe77f64af1c2e4118d09036bf5929f0339a26128b5310bcf267147b085f6e00000090786c69a19ad57b5675bab6576b4f0fe2d6008f0b8e96b4a5691f1ef61b7bd2d3fe369e73b7ba2a0329888bc9a05d4de7315abea648c97744c02cdc0247f9477b634484f3e8daf469c96cfe6e37cd850c26640cb55b63489fecbcfd9688ccbfffcb4102175633b6a5377efcd0b7cc17cf0087ba0d1653cdaf6c68d49fa89706096ea2d7a9c29ad2f3dd867d1df70859a100000e00000001bc00000090a3876e16ed55d821d4636554fababb1fc42d06cbd92febfb62719d17b0f2bdb03d139f03e172349fbb12fa71876e71453c43e13ce97c64f8dbfc93415397633a065a1d515d26b62f3363bfc2854f8bfa10ffdf2a4efaed8b701374ab7f1e679a18ceac9c210fcb9acafb8cf37a73251f08e844a2b2001c82544d3378a05a9549fc7f61910e88cf90347073fd6e82835d00000090b5ff3c7f2f01945fb574824a039d5c8f42610b4a22c8b38b84cce82196b2f2ebaee6887ee5b0cead8b2d6869905cee40342c48e8efc6c2e9f832471f198074b291669e0ce93ba735756fd1c6fca3ebac0aa462812f3112e86d740a2664453eacea944595a408b3d4d8db332594fc5a102aad8663729ef614958a89a8b811cfee1d04540edf80cc168052d388469f0e6000000090b88b5d5719cc71eb2bb8e65e65d5432c51017975c69c91239547519b9e3c2d4628f9e599498bf8e302c4db9d1dae86963a18265772c4779a629a902121419e70a44cee9ae1129d1655e1ac4b1b25df362e67bc16884a13f79792cfe62a93585e14f29b2afbe23f15d1615f3705caacbf2d349c9d6a636d70237841d62796d49e3dae9b0c72fcc3b9bf91180247730568000001bc0000009006c722129a887a0e14bbeb91d2b1daabca1e3ea84f6c08eabc2deda6f75464cb597e5d05d0d823f8bc5f61221a336a976d225ff6fdc4a55a1fae420affad4450d1188825bfd87cd9ff4dbf25801900fa19518a80845efd7cb9eda2de5ea170cde239b239c07bfba655a5bb7dd54b5898210957fb956ec97b2dccb426dea1f357cfd8cfec662257afa8057f879a25c8f4000000905dff93700500f84c17a5d4978e2b0919e31d688d946279884a5cb09846dbc907b40be46b703041b02b2be0b1816374ce7403b92d14f4bcd334a1ca74ed7deb0a7d4a424a18cea800d23aac41f4e319a405f5aa27f508471258f487eb39b1289d102520641b12a47ecfe0d755b9d92806174fdbfd263a80f130e1b44f98423f769a15417b3298de41caf2d78f00850f5d00000090bbfcde9b17102b338768d92ce80368c9a2f4d6949b28be3a44746ed12c0d9ef2e2b66ba398c6050fc7c37ad565242d970e3e439bb08ab9d45dc897ee4828ed045dc4d2b0dcdfc7014e47320e70b14acc1e305b0d9424ff136843f472581ae3891bba2a8452089e70533c2466c89e403d038a8d402008467ee4577d68b2f14766370abc09c249eff0f906d0d1e093b8ba000001bc00000090e31a0d8d00cb9f8fd05817acbbde48215cfcfcafe44646c8d1924850509055c24fd79df0cd8715464e5a1c9bb6cb1f3a4bdd663963eab4c0752aaa1cff3a7b2eb75ab40a996b93f0f2302f6ad963806d0c503bd84ab49a02eeec51d263f1994702f69b0695ceb6cabeb7bba3bf52ad83237badec785ab3a745914806e6f26953a6ca04fc3d7cd696209bf5f104f86ef100000090063f775e7ceb26fe011707735a2e5888e7c230255e25e0979035744f3588eede48b272a0cbc80337c17972944aa6f28f70600506926e61c7630fdcb977bce23d8481128c814a778f9138879e742136b00d089f10d3d8c533045673b43b77fb383b4e661ace6d8d0162c266fbb9a6ee1d1dd8d16898423a2f00855cc213ce2d9044deeecc20a7ee74100ccd6e15a16cf300000090c9f9ff48464c6f94de4ed0abce66d7261db88bbd45ded714b66fb19e5bb89ce727fced3219274c155a314dace0bae0180fa8ab396b989830bd01cbe7928ef72559f89ef4d3d39d77d524a36e6816df1824dbfbcad5773867833c941cf338b17473bf2b82dbbf7946637b68009a1c0e1d170670a34b5b36d17e8dc7a3b901b710cc234ad174728ba4a1a12cb20ca5caf6000001bc00000090e482d47efca5ac34305cdd7cf1e0357dc9a3702db439d0ec32a557be756f27bb31464cf5a6fcebd489d99a93e23f8ec3bc9d6907bc21581d10d66a551180a5d13cab0d2bc41d8a1f6d2352bdb9d51a042d52113e3b937d9964600d48e6d8179044be056af36b7d28717ec773fc116c53028000a5f29c579fab1ac3a2b8650800ae68ac9a53a1f275c208c389013bba6f0000009089ae58cc01b9b4d1988af7aaca738ea51ebe24dee59a27948325a1cbc58e4ab31312369e2cbe9b0b21652e91072f57dfdbacdde7b7b6d221b3ee1c26d55baf5fc7e667b3574a6deed960f1522669f71d13566e4e0b0112c5a12585f5608812a6c602f239e99d3d82ca640ee8eaacfd080b4d7398bec0f577cf72403ccbfbe2f71dcf9ceed0499776ed5ee0c4957cb4c600000090e65d9f202a140c0a2022b6225cf2558d3f5a74a70aeb12acc459db2ca2d3e1826a9a37e98ac6b7c01a555e2114f7951822da3937d011c7a2cefb4c1b94ef44bba2529551281404e375a79950501261b01268dbd966ea9d77da87d9fe434442339186c81fa5c2dd31dffe8c23310e7d3f2a4f8272093f358c6b080b5a38f487a72a7d704b32572c536694618194172be9000001bc00000090e4466379aa91f3bce88e053033ebf202986b24940b07ca54164f0cccd41ca2521d2f1006404038afef6819f047d200d8f16b955629c7bec12ee1c5270f0392d8c98407c12448a429775bac3aad5cefa004872024a2b68eedad94e7663e2f4b21b4bddf32d138d844287cada5ee2dce080a36a7e159a32f219ee6b4e027c82ed2b456ae6e6499b13eee1581011e2e6b4400000090e3038f011ecf8122724726fd8db040ea9e24b16589ed2635f3751b1ade8596162fb96587ae669443d81dabd555a5358cf2395769e1079e10b467b9392e72ce23c810f6ebb2afec33762c8929f7b08f5b1883ccc2b03ea2df7dff0cacc8a2b9d47c2cdfe9be11b2cb64aeee7b22bcb2c31030ab1e56b449cf77bf7341df47fe48f089d5b0419675f8ff6230668da522000000009034fda1924626a90d62ba3a0e77560c6061bf610393bc208e92479ee7a591552f2ef5d34b8cccc41e98566d095b477b6f9b35a0d77db66384489d2c5b759f9b922fe8ca8d89c1e019c90a306a9b228405213482b7e55ea72cfaa28a983538434189af956e90ba1ae65146b08d92d451681b452d1ac8335c202aff95a6f01d387e9e377e313889ce43777c5c0d4915995e000001bc000000908300f26d3083d051387eabc1fa6ea58ad6111d5ad459cde12b4414126838bfe80feb66f89adc287849b52e352bb159abb21d7fe5b2f96afa5a56ac91e2393a7f43dcb867527e553df0b82cd01ea1f65110a950eb54c3ccd5692340d5e4e258770a4c4f5c869fd017c55dd539801b691f1657c78f302683645f577a3811910cbdee1cc7209049d3b1f23eb5d8daf1e1d0000000908480b44d561ea59bcbdac63423d63c3d45b314fa17cdac18a35f02805193dead44d1675d119f0377ca46c6625a3a33f86eb2cb6ee6ac03b9311690ff2d4ddb5670d34a8a577079af14339deb75c09ece1dd33cb17fba31c4deedf7d37ed1b5cefda8e270c3e3883370bb8285fb8fb7dd1527cae5b86022bc1d7c1745e0df1cf1c2501c3398051375ddfbffd4d5ec4c8f00000090770fe8024a65c310145b1edd9638e65b5cc21a4fab5427ee0d5a529aa0f770e6a209dd8608d528210d73c37e2159f2774716cbc7e0dccfc79e39b6b53b762034e77d067237c1de74766583c1f4484ba3064242fb6cefd1993cf4bbcbab8dedda0b7a4546e17068512ce6db5b71e8fbc31cdc30adf2e51dc6858b4865c5f96d769aa34ce8f4b63763d2e7fd0afa3ed132000001bc00000090290b968330d9b2a6a8429b395aff8a353dd65597f38f50ae73c75c1e4b471995b3b23d3d08aa1f5ee4a60471053d1d78fd50a24fc8f4829b43aba4604342c1080a603eaef54b1e03c235f151f8a635be2c715b158619bbe48a16f6201dd37c0323f59537e0e0424c2bdccaf24c5e3b2124f6275ea3f9ab4f0f3393eac7606405653742371717aef2bed00c867d5135b800000090003891a78d433b9cff782fab1b12d3488d4d616f84cac4d51ff1206015f7f2bafb9309521c5425cedf5e4a054e2783c4fd49b54f0c2758c72459b04cf8f3d217ee25ff6369aa0f98a8a1f28bdddf165b0925b0db8f19a1cd1528dd5863d25ee007b07e136a6bbe605c8b5ccabb4e3b8025bf5fa4eba51c3abf2116baa338643c472c3f67fcf8f86ee1225e2a68acb8fa000000906240c30ecc2e1b81aac6375b7624902e826c7ef31eaa1edbb328de81fa510d77ee3984891fa3e065e55a11422a20e7837fa5e2dce0fc007b6b42349a70fd49ccc7103ba8ddace83f4b8becba2cf709c41e377e7c37de9cf6937e975277b598a1b1ed960be7f1cb1468085246647c5c6b1d305e6c6d0704f6045bc8d0ebef9527ad356e325a7727dd1981ae243eb00111000001bc000000900e29e1361514875a00ff70111ff79784f25cfdc3af735a5e7b74e934051ac4ed1992c3f8578624175065276893f775acbe3ab7a307f6352f37128fd69088715466745dee45361e1943a1bb42c79a4ac606f0dc81e6229de80293a839449cf77b84e6b595e9098516dd479ce5ad0d99680a340e7809afc785e4b448a669c076c11aa06f70830474b808079396468f886800000090543bc7a8713ef2d048a6b7d3cb0420b27d2ec2d1cd4cba84c7f8dc2b278df74e392acb5ea8f63992cac9d830c4c41c2558dd15068d18772feb80b7fe078fa12cb1ac04bdcc5f1f13d703b8fae3e1d9391bdb20c632ee66855a0f9797e82e2ca6c8e82b755fe7ff70343360b46364296715903c0f9332b38d5c5f82d5c2678b7be0a1ca117998466b08683ec43f685fea000000903d102425c2f6a06dece97ed3e1024405c8a4b6c80704c0107dc067e4f0ad0dbce5a9c66f477d45adc34a0c6aba10bd89ad720b07508710262f0bc332137a513b6ff63a0de6dc5d1c835dd8fb7b12f0072212f1ee47da9cc45894cf5a987c44bbf1e3d4d135d391d04e725237805b4c1d01c79918589ee1a68bdae93bdc9cca3150910959ab78f4ff7eb936689bdbde9600000e00000001bc000000904f9a864e690819a00fb8224e5d3155788abeefab5507e780edf2a71530813c32f89f2cdab2818b50834af7fe6db96dbf98be1b603550bea8f83ee2e9ee48276318716e1b76c0d7ddf83b13cde5c9b72a29449b6a53fcd372c9435bd66bfa1f1e2ad6f334452b04ab28e9140fa760652b266637eaf4fd6c15199410e0442dfd6853ad8039c839cbc38c8f8a641b4557ec0000009053778bd9d306881e6437f02d1c060c6ac911dc6dc08e14dc2fe7d07707db0bf6d1317e435d10bbf694eead58bd9f247505f45d2474764f9484f51aa3d47b9ece0c873be7a8eabfa750681261208a3fbe1abd5040e0f3cfa195fa47e57c9eeef7abbcc9e44a7a410b8f642a7f73172398091c39940744b315f2bb1aa543bf2300b7df1f145e51a9ecbdd7edf6c1f940ca000000905f8c5f38e2cd1526e302f63617c4c9442d7a701e64f186f4643495bb0f2225f4d447161caa374675056fd347cfc9c326abbcddcd2dbf7fa0a7c65d66a00c9267934cf5024613982dd220b5722e732f2b233018f448a53711c9125341245ea58ccb0319c067fcd85345e2d7c01ddd145017d6eb1fb8dca36f5aa255c7d6cf5d0fbe53d2280505061a10fae56a8037f9ef000001bc000000902d323435155354833a8968b946c70a808c7e5a0c957d741deb6d5e5a8de5a16c9c4e919d122e71018820419b3bb3ea11bcc20004fe62fea8d2ba9fb60fb876b820cfb3f9b1e9a4b150ad8e068ff23c2c18eb725ef932f7edb2f127a03e5f1e6860b836f2bcf6d158b5436b373e26c3c5236af647d18c743d8f4d0cea5c99dd134b47c98959f3e21dd4d432e47a953b35000000904550746a5407fc155dc61fbaa7fd755c1eecb77e8436f97ad949b11abb5620d73e5d8e0a4b17f134538a6acadf3d0dc4002abc8ac8e3346942c62d5987689524de70ca521b9138cb85322d3d139eb015024d269932c7ed0293cf0b10aa5e4fa1aed8b334bd2da9538887291d4a45908123521208b53e8802d8822973c96d095d142847fdd2647c4096490dbc21b89ddf000000909e6a9f692303985214bd3d440f42da18221f968a9842001de8589c9cbbda59b89b0f072eae9806c576ad4e5d36ce09dfbc1ce7192fd51263bea155056bffab8c1fe28c1d7df7cfd69364dfa06463143e1c23fa6a033cfa7aad7ae3d3ff76ef9d9b02db4c233d7e2e273e1363d1aa88510e897831bddcc98055881aeb1416d3a6b7530b777503aebc2e54d6ab10c37d0e000001bc00000090d58a0acfe904837b752f41eb33c3d959affde56bb5947f8e20696e0c68d4e953e8079930620497ab7e7aa39694f7243ece745b53d450678e9f989059ce3c00a2fd2fed4851f4a2981e532c924a4229080d331f051722acf173ea3580dd246afb3f540af9e403be1f550f4ca957ad0ac10fbd4a4d9a643a1f0c6128d7bf44ad7bff2e84cc19ca5db71575b9b52076e5c50000009097a819c4b0baca0937186c55c7840fbf353123c45346afb6366ce03ed1007e6cc6425341d00e7de3f234963e14b1f36990d9a08170dae6b366243b9df8b9ed34c5b9c3752428ebb827164ba27345ac88268b66690366970da8019354582c203b0c91e290f71e0eb314c617c084af18c718f5896b1fa2e3be304b1759530a4b0da0a57d1e5e9d94e96cbcff3ceef39af9000000909aa7ac7b6e139c864a92fc2cae4aa465d428eea35dc90501d60b64d527b85c9dcf116e257495f8f3e4b5ff275ada7c77811fd81e16090b33968a7866f94e4b9e1d1ac3103cba4a1a96cca7a145eb2a9a17c67c30e8843e28fc74702e7701391560da1edf7efe2ccd6548ded4ee8743fa12eba27029beac848fc5cb5542c1b38078ee96b9ff5e44827edfb6abc1ef8c6f000001bc000000905f457d742ead95b5eedb9b948f86be096590d0e8e112383d744ca7ea0640ecb703cd6a42dc251d0ac50a65b6810a2a330524cb21817f1cfe8ddb5da561433d545ca5d3867cb28ee6a7055e620f80b8b40f110d07b3e07ef2b58a4d7310ccb1c9499fd0763aa7ea99229b8c604f28ff02083622ba713712c31103eeea2e1ab0789f2a3fe03d131652cd452fc538be8327000000903b8939cb4709958428dfe265eba9fc58c4a72c3f3f9a5d685681f1828c317d44769dc018b8aa017c3f8a4855e885bbd1b9104f4e12dad6554c86d6e3d68e3b10b81c1ba7874847edddfb85835398930d2e965aa6f1a9348fac83cfd8907d032082fa1832f0e6e9a3370849fdcc2bcd0502c306678c28645be7661b14f7d195e89dab565d436a55c63b9874b820790371000000905ac1167885ea7eeaad310ab9384ef3a85345c6e10bedcfa00f0eddf1d2186ce76e35d94dee3701f21a340d6ca6be5f5771816c78dc7d4d9642a0360f373c273b2f85fe07012da5142754ae9b4c1e683115f318b02e54319c3eec0a1f57ed259fad61b8029918bb04abc88d5418031a472bfb38eacb9e6aafef22d059b2cad66bee5f27951d7653f1d5e6a1da7d7fad25000001bc00000090186c54b312de2502ad90df9d21c0ce039879cb91c919fd22bb38cc261c79c3f6e465013bfecc988abd4b69df333a8f616787e0280e4f87b70a617e4cafae0780bf83078216e35d3d331a1ee4ffd020ad2448a59aeb1b2758f92194e6d3b81afc33f106d6479295451e96e64ceee3e51b1b94bad364c09520d6cc5227c50aadf85f82e0c59e7a3da5967c45f9292f4e9b000000902ecbe834880fde873379b8f70e3f0de3ada567546eae1c9c9af258f4f3312cfe439ee227c5748230dcf227580b6072fc17e3710b4f156cd877bf40f88b2ad26955df72281a2d2cc0754234c05978ad8d0acbadc8f9797ad222723847294785e8e17c28e183001d281a7ed57aebb00ab9016cc25d4e89b4fe2fca8c6454acb10a7ce5ddebd7186f0dc2d52682ea2d4d4a000000904c5c6d664fb12e3471d405a8182e87e91443bcf78b545796e8c73ba29651af4e98c2e7a95c9a9c46dd5d3c8df95a0f5439fb2b296cbb8e7464ddf15c389d2d235dfe994da79aaf9cf6891e8efbd94ab51bc8f73bc8f10fa23f0bda83f9be9e76c25e2af740f2bde9b5b0a0f76fc5fec12e6d9e7203dda27b27eccc42fac592fe6e5d51d991e51d12223ce89f4394cf1d000001bc00000090eb34f161278463b602e60cee956c56a68b4fedeadcb8c77685bdef0b7ea3481ee297cdc07da286af421064251ea71598cab671f1f4996eb1cf176047a6e89c2aee237d289d7bf9fba91ef7799d8cd9bc0f77b2dd8a32a1f2be262f3a001f8cbf4435ef612d0072197f8615a52ff7afa713cabbc93c14bf0200295cf634630cad118a1d988bb10fb3c2814e80a4512575000000900966fca2b9d5cabde2a66d5c70d08172f1703507d741e7a635a4927fefc4ba2b09ef5eca8fce696413a95cd9334da60f7a9862cada5a9fbd788347dd580e99caa43968a6255f5b54610fa3569589a1690144414c7ecc579815de419ef0941b4937da5977957a745d6796ad2aa1383c3e2efec4365cc356b9041a12b290c5d43a3f3b1d77473d597d8a20f23190c05952000000905ba55db35d62212a6e561944103eed603ce9c61a94f386114da015a7d1b89e44aad3a53166f650e9c0dd8587de37c999d8a156b9e17e75d24e0ab4dc413ce6d32c62cd6e4e6290d2242f416c7120b4501f5ed62312005fdf126f018799a41816ff5d0f2a7d572b3af4b6b1d7e7b675931c4eb811312060cd88a5f00013e1b4a3d76e5eb6b433b7decd9525b6ac310678000001bc000000909c5a60a7ea583c9914b81f31779c244ebd687884e42d9f434375722df9f47688056b354b5f02d3130b311b15fde7e71c1d0f7b69135a465394e219e1b0f462b8344e9ce29b417141b88b358a52dede49157da2437df6eb92eebe8edfc1098faa7508c414e5e237ff9c15bfe6d54eee2e1379a4cc167231e2594e62363d1fd43b809995da5720160806ebcad8476c302000000090791a797d26384790a3b36b6dfd89684f28427ca87c8ac83c136294e62cc7cb7a0e2ee61c1c018fb9f78b843380e12c204d4c682289c156895077350ddfcf62fc6e2ebba789d75a571ada468b288e1ae325d5b798db527e7c154acff67a5aa52b91de9983e3c2babda6abf48826ed16be069fb8d5f43234514971c56160f0eaa805feaa5ab8b4b7d58938ac565f95ebc400000090b491cb9ff91c3aadb441623a1b327ec20de34e448ba16d5da4d6fccb99ca54d5c80a8e12ea9d9e81b94363e7ba45b400cfe959dd46886dbb8bd09088761f5b757b33f2449a59b691c5e43b83a89199780696c2991cd1ee09b637fd8958c78579f96f410cd08acc37882ae9bbeb01a78a1f8ce2cb9c1c44496e26f1d5eafcc825b6e36e060aeb33721ca8254c18c3f679000001bc000000907da33c299d26e34eeea01f006a110d5eccb3bc6ee359078ba7db61822c4d330f15fa724fd856f7c52fc1a1b159e48854fc4acc31e2441a8166c09f41a36e28ec4d28fa82d26b0df515cb44877d025b4e11b074afdbdf6ac54b501156d075c5cd2e335143b697d8569bc3f1649971c5ae1765b97b1f3110f32c247593b11f0c469a3eb837b01acc06cb42e7931a81c8f900000090a30179aa3af06f3d0af1256b70daf420df531fd45f1e5b60e30ca87df4a566a56cb04df18e8dc75c574c6159d1f0f1d16a3099cd70523df46ca4edd3af1700bd81b12d34570d92c895ac8e950af5358824981da13cbf6d40b1e6cb7f6ed01acdb38a2e1f8289ccce83fc22f98cdcedef16d7c75f6015cbde52df1f8a398883df68f7f9b83f6ca7db9225d10642d7ae55000000905973c0c6d830bea7f2109523b3a3f0e8b3a0805103f755cc55508a06e6ef0fc44848d1a6cf36ec4457b2579d800c7431ef9822db5565036654354475ef6dc5a4cd3cdc5b0b594dfdad56a2a0c7dc59162955f7e27e655fad747e137f81280b1491cc7d54cace55f4cb97c60e7187d43d1b304492a7615c8d2acff874287f7fbcfc083ef81c5c85e4805b0ffcc2c8cab3000033a000000ce40000012800000090d1905502bfdda3ae7a7ad5b8b4f2f0eeb59cc1752d40934520c727ca05a2572c2a79837c6fa647a2b0fccb5220ae8d669b56bd4a829b9c0378969a2de759580adb811b9a2f86eb5dc40eae174b3cef972ce9bdb652ead9df39d088644e4a8333c50ba5fbef3db0539f062a293a583a7424e214b300e6d33957cb37a88d766ca117901e7bf696bd7a60fc37e380818b88000000908a835e9e543b4d3dc26b5fe41a104021f8cc76a76dd6561a548208afee29332100a35d0b84337985b2fc71aa91c1dad221e06bb0bb66101d07e6751a1e6386a6929bd87e97c762dcb3a9813276337489018cfb72c40a18958c16531796042877664fe5967b33b990051f4fca9f81941f18d2191edf8b4de25881f851e771443597f13d2f6178afe3153201fc53e56e300000012800000090c80e2c8ad9f0df4dff2b3cb6b1cb64ba731bbac16c1afde6a8ed0d80f2065d89bd5c35323ef4289e6d946469dd2135c7afc8d2468e2f31531d4fb75e069e8bb47c40cd63642a6ded6a1f459c161d399f03217510b4e322e452aa0eb0b2e1bb5308b66d500a96d95ea206242f55c2d7910b72005d5c29786648b9909e5dd36fe31f33f04a1fb8ecb5a8020ca9b147d7e600000090b7bc70b9b15248819fb334bb519ca71b94961df9498d1bbabc1c4c6469ae6b9bdf953134a2ac9f49a77f599c80524b1fc19f09fc843bd99d52a0c33f0ef8052c6a6dde62a1d0488e02d3b32831f5184c27050dbb6e761e1a8df2d604278b19fb23bdfe9c178d2c7c076d804852e463db1b60fa77e817d9eb5e847941748a284750e9207abe6e05b5a50431c8bd6884f700000128000000905f665b3b5faff4c044ff5ed2a885d0bc4f22e6af15c3fa75e1516ae0a9b1105ae7e12c261118fbadd5923d5dadc6dcef42785069f58d10fa0355d690fe8a4b558add1498cb1085e6cf6f80cd22ee2c781dbadff6377db9efa8a5c3ca7594f4dcce4b7244e8d9597d4ec442e3b24466c2286ad94eaf7a5716277fa3c981ed52c41ea5e92220055d44b8d18bb37d410d85000000902c7bd784116cff39b2adcd15762380929ad0e311e8365944633b0c3b4256e22f12563f51cf6e7060b40a36ffcce0272451c19b5aa6acc6f59e422beafc3d835ad508bd46d6214382211a4f939a2828271c90ae7f1ac9db3e576b965e53d5269cb929a6cf72113430eb8dfc4718acd6ae03b44eccc4a1778e75156ef832914dd19e87fbf6308ddbde7be1d66a6e050050000001280000009079abf20bd2d8f39a4a63f3d567e7d90fc09feae46719f58811c4f23bf8daab3b8e203a8798e48ee553e517c1dc62bb7ae71de60d12b7aa26721a991d93d8c50eced62dcea7fea4cf7579f72c124ae23a2b9a9151b716671aa2523847c60e117137238181b391927c4b7ebf690c040f8d1302e5b280eb51b772bac3f1374c5cf0ba3a4cde90381af01f713e5f74a2988300000090d0e251b71d84b164fc2a5e92423d28a1fb8790716823ba4a81370d1bf80858e853be3ceb93c8ccd4159a1ce68aefcf40bc6a08978007e8720e37b8aa46326a818c4dcd5b45024a9899cd6f83cc74e61c195bba4b7c8f0f8ad74603c97fb144a2dcecbcf3646087fe1ac79354fa6ad92607b2879cedac1f78ec1f294370e26a2d3c99ccebe2aa6cbc11cc76bfdd99510c00000128000000906cffc8d66ecc763d1f9bdaab61abc993574ed1980e688551a1f473c3bae409ab6bff793f77c5c6243b8836035548c2152116b672a63f55681121fb0598f7f34b42348bdcf9f36e590dc13e39f75d81001f6e603a0e6d781a1aa6ff2e99e983e2929c8faeb88735a911d9a2760d28560e16ecfef2d1bb9f2ba04e5e6b3fd7c2c55fe03b3482bf4bcd253f9cdd882ba97400000090f83c9f1275aca4c32c8d8cbecaccaf943fcd9dc2ed6214c6d30139622e9a4ac84e3a83b18072fcf6b43606375622527e275ed31914205cdb2e547719a8f3a38f734e31d1a0321098613ac9ad847730090fb5c8a755c78ce7801a217c95529fc2f27b12032629ba5d6dad5f84391e150613b8f2305df4b0ad9f80d62f383d76ca5c380c371f688f9009e1e18785ec63e60000012800000090129dd7c39bc4e543b4228ff3cda6d81602edcfcef4a76d785d675661da95dd6c5b6aa104d9c396cad8052dd8e2b0af4d9fd666a9df0cf18a71495704943e84768bd1536ecff3b070d774e25d8abba0ac118f9a46a272f0a052925512be95f59604198c76999f730f75489194f0ee50620a1da9159d2c2fec13f4889ff2504f1e7de758a6706b82430bb66f3df68d73e3000000905aac7a384a7eba4c579bdbece9546dae1d26c942d4539e00df3cf77b69b9ee876b91d63b196c6c4b4ba1bc9396a1d8c48dfcc98bc701d4c0618ef54d3e1ed188447ccdcd8d733cd051863976a2b5e74112f08274aee099890d0575139403bebbae791efaa456c5fbc66485add46880c92fa6ff5005ff848b61d2e09fb25d81d9e08563dd63740af23d49f41035a43d5f0000012800000090af9a4e40e8e108a8cdc3d51fa0a64f553948d41472a33c9466a401f8738fa4e8a2ae87075b434030a1e55bc88f6873f3eb61556c755008d7d00867ac7aa2a8041042c16d36cdf4965ee358af7c2e8c73224490fbbf16e53d62c2ccd7b1d63bd8302fa03838f25210693ca227678d458b13f4567ce36ea57348b0272a9145dac30b3ec73b71dfffb64e7112a68ecbabd80000009031ddbb3923caca21f9baeab0d4ec4b93efbd3374553474fc72beeb1f442fd2b5a67b020ffbf783587bbeb6bae515862f13699961ebbb671dbdf9ad5e5d899d74eb50800e72e41e26adcbf02b7ecc3e9e18f6d051a7d618e7a3648ee7e30a78033e9ecfb4ff8de40608780cd31820e0e6001da3eed13df55b1d49aa277a94e02a49ea6443ab81f04dee97d81762c9e5d300000128000000901fbf647989be185f76f8cb2576048070b5203f324130e5a2a4047c8ba5ce9f3ed3ad818d5b893bb4fe722d3316561e880518a6869b8726022f3bb75a1a3e4b87cb52ced27e8392d4bb5052f94adac58816f385c34702ec0280952432fe6446601176af2bc8bdf457c5bd3fa42839935801d0afd78d27fa50c09d735270053dcf43d26a76e7603dbc7016dfb03d29da4900000090fbd06a73bac0c4b1821816265b032d2b116b124a562628409313c3b0fe21651cb6d73be44ea7ce6cec081137274c91cd92c06f255870a549544f790c1ba7b9146d498c69526a08a5d21ba8d6b25d067e181ce6e311139c9f402f6998d3765a4c7c7ec592ecee5b0e0b9355dd012b96042d81a176d087d0237db9861f7ede02c1f07adadbeef2f419eaff709ca3f95c850000012800000090d7c2bcf98fec6893a4b74c68ad3a0309a5f71211c8e891e6b535eea780dc673c2781a48323f8ade10024be2601a81d0671032e74823f2f55d5b25ab4ca3bada178b7a981c9d1a856354c745b4afc2726255099142c0e31eb2a5da9d98adfcb46d1917b7d84e1e2e77d326987f7cec355112bf6c26d4ba0395ead9f0dce334a0de4efc64a71809810918934bbcb6a461c000000908d7516bbbaea081bb212451b528b8cc86bbce048db2d8c5772ed87ea9d4e728aa7b61c87c57bdd141c6ff39b05b503738d1d28dadf5371b4b060bda65ba3ecbd41be6ef111cf57b6548da2032f0a191a0bdfe1b27d90ceb6b23f04f8a5863e126d0853747b9b082b487198a4920872622af67ae94b4f3179cd5469b1c0bafd8c02b42bc8799e6ae4afb79ea72cde4f86000001280000009019b7e77c5be67c435c76291404bfd10b5b18466c1dd37f8a52fc0977a7bc31f7ea0173215fc5a448a2d24248a18fc60ffa2fbad7d8475951d6e1ec4462bd9b9319c40dfc3790342da046c6a010a64445226f2fdec5819a1fa19020cee7ff19b68b52e988fad1bca1c3ce88a74effe63b2269c7f78fd7d11a7cb61676199fc26ed50acb3bcf72666385bc6dd6da8d07cf000000909adf698c4100086a212716abd6261b4aa923bbf41c554afb8aae3198f79902d4776a3d75a20439ce0799cdaad64a568ff3aa4a057cdea09d83b552488c55c4d634f0da5d5e63cdffe3cc903cc59c80e90b17fca95c2cef6319e776d6ace7695299805c4f888d32edb5202a3f50fce54408244857ba5f6d9e700c2c297451d0ef54e0bfe991e713157d8e305aca7bea27000001280000009092e0543de57e6e227efcdc03e8082029df983f760b71e48e080644b0762ef393426c17c75b79b19eb2d987e60427498a2f56b3d71ebed4a80dce9b312f85db8b05bf9c3b1aaa38518115f75edb89ce3f0a5f1684b6f8543c30faaaa4cbf2c2b27c1769a0a0037f908652f979184d15042b209b37841e256d093ce675fe2447c12c71c9c1484a1bdf489438bf4f1baba0000000902cfd837a912d0bb6d432ab447303d975d1bd04938a49a0c7c64e5ef58fbd6107a46f190dd80404e5788c51979b300f162d1f7ebe4f8cdde34303cdab18fc449cc3dbb3ab5f4d4949eaa49f3749ef0b0a0a1ad2cab1db5b5ef6aac87ccfbc70ea6ee97aab13016f0bcaef27378c4b39040b64ab2ec04016197e4e9f022caa51e9669167200d6da163e5c2300e8c2d1cf400000ce40000012800000090dc587aa4332202c6cb7166c034697783e03233d9ee1f3ee7e1c6602ca72390d529effd755655c207151e09c767522f354e091210eeaaab36f6998df78cf65c65cb3621b310c6b6505789a52beb235e7e029d00de64046fb9ad323d2f31a6910ac78f3d69b3ad2764288711682745395013073a18139125a385b39ab54f8374c6ee1c3a75961eb01724041da6505c2bc600000090bd5aec0b649106c5b0b81a92f71e7f5eeb670ff3d283b008543ea0724c552eb415087e0d6c6f62f722f070fbe94813c5bef249f71e83f71d73760f7e5031b2b8750a949a00a8f9e342eea1e7ead9b8b11330cf4ea7d3dcb98d64b51c884b40530f9c27878169fa4e33a98ec717b24f9a2f668ccfa8b130e6eed8849c5d32fdbb945187c2b24c7bbb269370eda993061a000001280000009019a2be31c8796821dd876846233d0f72d8d55722d08d6300005ba90da68fe75f9937194533834ece95eb25b6dee9e6567b4b80daa63b358a785cb86c8f850cc669ce6d7d30a472e6fe8f37976740444a237232482c8055548f97b72df3ed625f0a4d0695bca06183965300db8badbf6126f2ebc128889d1bca33a6bf88e4806cc26e5966190374f94bfafbef0d21ac7700000090358babb9cb8691971aae68609d38b10feb1d2a8190910d7422a5bfe0aa58f0bc6783ed56287ef8ea4741bc1def75219b838094bbeb8c21476fcc69256ef36b84c3a9d79395aac2d19d4669b1641d3cc721eb517e6e92fc0e0236e950cecbf17d9dd8a8e9670d2b89d2ddb1b6bf65397e2bd643ee46aa88398e566c55e109086ecad8d1d56fdcf79034f6431ab924ec36000001280000009029aeafc335fa8e95ae74da73f71bcc7007c8c33b37711c8214e447120c37746dc97e9c65d7960f7c5e7320e75f79087692feae942b353a54f1165a16d120c271e3e5af74a1e0b9e0f1cd2c5d31971c6e1385483cdb8dd34906ce5d4cabf56deb0e276587c32de7c85e15e5bcad7f2a6e2940acd0f5fef55a9bc98c8aa09014379d83345635bcd48d908bc883c18b7a5800000090881a9e6f7e94e86575c91600d2abbe813a36c564df6b2ca8ec27b51e6f35a0bc4f8d68d5c4075d0e3e87a5550ad353dec40eec028ee1f5b42a520e1b139998f992df29f03daf9d3bac5297de8099d0530bf2c0036b5033120264a9502338f229edcb96a01f1ec2c924062fa313f6cbb02ac0914620a0d5a97e6ce1e9cf0eb7c48c7543a298759b4afb437d2a1dbc48e10000012800000090e5091f2fef0eb8df60f95f8444f9f7745dfa5d699d306ef4836c64e2b98268a7c6fc399564d4d49d1ef7ea4a3d6a7df458a3e257bd1393be9e84cdf4bad769a6f3c5f3c2150a019b0b1c4aa305f04dcf0fe6c8650f71f014dc1e381be69eea2f1e4fc0d308a81489492eb186a6ea3bc31e3b360147677cbce8597942a4dc305a1c485469a7e7920dc1a74500b62b819f000000908cfd83bf0d0ad99129f802f98bf4370798eb4215dd86510f6db1b8ff8c09f3581d2ca57cbe44d237277b457e605a67b76f8da1c39d06bf41b904bf8416481acb03da65940038a83f6ac45d792f2902d1207f03055150bb78d277e49122464c205b4d4f7241ba15ea532aa8cfa65024f40785127305a1449eac0603659300119487f5ef065d8fb4932caedc4c7221503800000128000000904654a6046603b6cc049242caa630c290a5f236bd2d8117f2bf709457025220fd94aed67dc69920ae0241d674e5fb16bfaf405a151c3753fad8f015000da5d3b0c6d4488ab3b2cdcb3cd53bc2c6619c6212e94f10e7b4c7b6ae798d3a04a2babef49dd2d2973facc3ab135dd446b124312471e6a515f341cbf69b4daee6ef8dbab575ce788c1334d57ac0ab27421811dd000000904a95ea082c55c5903663995a454090cddbae42a173c3e14a3e9466f1d4f3b0506b5f4e32c4ad9adb958e2cec97f906733205b216c3206986a66b55770876ead0bad7ef67b620af8399486e235ba7be572f3e3f38f9fef355f6a30c1ca79e2f079239077524bbb3965f19c9a608ad1bb00c6d5ed4acabe3703e614ee07d63f66be71c2602f5d292563a3f9375547b768f0000012800000090c9a80869eb7414055e9aa60e96f1426c1b26926be0fb1e5096140b52e3d9a33367e26f6ee80748faa5c7c8604e0d428b2af4650ac06e5054ed70bfebafe027c1742177bfbbf147042efa25bc3f4b0f882f4104e4968239e13bae19c0a2cf12b1516ef7d95598ccce1e7f894af04196a41f90e78c56e396e36b56d6ce04195c666002f970c065136b7e8380e6b3e9a42e00000090384c10ece0a90d1b7c7ae0fbc69549d807ee6d9e6639ea43192eeeaf9ffada9178b8f3539a0b5dda6ed1ffd3841f3c9227c46288aca019c1c78749a335b596bf13fbaef22250a906482065607bb0b8a72a5ba7f0a2ab4776669acfb5f68a5c09a9664a076b05cd6f46b31552fef89b242d893e40a89ce617bd3e798cd75923f34eede2f2d004b755a3fc0ae4cf811b140000012800000090f07b110e3bb4dd56f549b2e01aedb0b50bc6c1a46fbcb0276d3b680fc2d0a3ba6d07eedf092c2fad2b5ae450b2dab4d613f80a51160f3fdf345396456d13aa6bcaf2c0f81af8423681a92a5ade27d5e12a8391d3905270565eeb55eb99fd39011ee40586cb5b8916ebb2327a7f74228a1a5768b6748494cc156fc28bdb52d9ff1a396e8651c9da2c109175a460751d4f000000905c3bf40c68346b39d431671ada024f4a21e96d7a110953ab1683e79f49fb8ad7ca1b4a4471d163b128b70b6c1e2f7220e03eced83cb2b9a4c50e891e9c4d71700ceb04182913ad2c4b80c566592b501d1e49d7474a65b36dd1f024ba26e16ee454588b8aeecbdf4364019c0a781d121a04b1066d2e035738dcc00d28952630943a12abc1f9d4d1a680901544efebccd70000012800000090fc4a6fc3d816ba0a3885d6a7a901279f62af6dfe8526ef236a4ba9d60149099cae6b220da594b763964d15c366ae002c8316d367f909cc0033d132d4f22eff1b8a11b03c60557808da6cb21cab9d65cb2c1b4a28540767020a55bc55081c5227a5e6f949644f7c86c58b080d8ec4b99e0f4538bd25e6f274978b2f466f009d74e3376f76c026ca8e1bedda1f350da157000000901456cf4dd8e308692b2f994b1942bbf8796aaf378ff14a25903446fa8f070df54c78c017bc78c03aa89115f28f9780743aa738c99a0a150901ce43fd25fcf66ecb1efb1ebb56350b7cc4b86bb6c2388319532180d1c6eaaa938edd4a86916d7b89f43743bd9df883b58efdf9f52e1e350c553c60cb3b671365bde8451bac3f042d25f2c828a8c923ca3e05ce4e8492e200000128000000902903d864ee728289e1f7bf2ae5c9c2949b37d4baca2574a25d380863967a41d73889662558670596e5d322b22061e70cad78bcabd5c17daa5da2d530c8724c1170fe843d83a4869ff8ffe1d6bcb0f2a62c7b8b3e650cb59f6ec647609994e2bb9e96f03965b90f7f89e03f2724391750019e9e76541ec54f958c27fe8b037e99c7481630a92579716879ac717faf758900000090cdf542f37ff778bd9a658de2cf9d49e04f7648ed16f0de2a7c1a64c3b2785649b08baff74fa6cf69cc43acd4a7dd06db48c354c1c4b1431d69a1b55ee89688142245baf3425b88f0f693221ff0ac1272272417b00cd9ed69a300f5f7bf216dc6728865eaee008ee7813b28c75287a74b104cc6b8b7cc79451783d94c59038c61321b6f502b3d0ef71729cb4d54ea1c9e00000128000000902d8a00b5ccfcfb3a4fe9b255e32d5271b8509c43c65aa456e4f4f339cf7154d3fec1b33c295789586216369ff1f949018f880d539bceaa2c7dffe06a886a6aa98d441644292eb57624eaae712a9e30cc0f27bce54b31f47e72ccbb8065093379a245509991c1eca28e60a1bd80317f971964ca59e07bc005f19f438998fdf646aebc6d50fc9806afc8e5f53dd67eef1400000090e7c284f83939609ddc5034139cb7427f2749af0ceda579468f9f12f479d7635c42ae47924ba8d3ab720843b3965e8538bb4d3f5eec343185ab072852a202a1fcc6c29931b249290af29f909b1fd905772f21bc9db8b7e15704662ab924263420dac87f6596d3bc4e71a46a1cf88d4f130485fae93bc967dc32857b8e01d99ebebe50fd7fcb2dd92faa1fe760bd9b117900000128000000908d7ce67b739022c93cf68de7f4152edc7e66e6f3143d1a44eea1b64ec04df99a9d771b30c172a41107d84200910bad13432b7671508aa27af24c750e64002630619a0b65e54108c7cc30ddd12d069e940d114eb6ab90ee9be749a7bcb9d3295d5089b897b7293f24e7fb0973ad1f27cc180fd990f7821070841668a1c06d990c938af7a09aff5a53d7bf728d41bcfd7500000090dff4bf92d32b8b2e3a7371871e4f4d65727e6fb33ed9e2ea1e2422deefe49edf5ef2c295a6bf68ff112ef4e095753b60502bb42147723ec52452ab4a37d4f570ca86fc00d9502f948a5c5fa82eef730406dbc1727dc7284df5eb15541c0d030768979f802a46bbe2e7344d675e2e46431e7346c318f763c8dc24f4c50801e33ce39ff804cf65ce6a686e00d6ab5fb5a500000ce400000128000000907c05563341c4d959bb1ec9f9fc41d77f23142b298c4a1eed904d69a7157b0c3a50189d5c5955bf5d0435d27ac263bd4b211220165c7fafffa2bb9509b22fd06d3980a31d6dc535d8348a7fdb18111578097d8593f94d803409b86b58dde71104bd3db6805e1210826662237a8cd46b7a287d0da7441f6e16bca0c7cb632935fd5200946348a0a63b545772b8423e9b0e0000009029f26d7c01fa7cafab88f9c071037f4c37d2410658cdca53b9fd841e3edd61eefc8b447820c16b64dc580c87d2ee3bd86d980184853c62051086ade474138865436b54fcda93feb678ebb58693b3b14711b516c7b47b506e1e395cc1256b24e2c395e41c5a73a71bab2b04106a9984a50d8e80bf0a83ac05f25a327444f3db4d7475e579de9d471b09f10e483b1d2cc6000001280000009070eadeebee733c4c21a01360efc1e965a2e81f0178035b0b7ec4caa6679b944780d48c11ad55c38a024ebf4a0fae56e705f7a00b0add5e3a5cae06134d0b92771242fe98d4712a3a1c696734edfe95e62c60fcf93377e6e5090f9dd5566a389604e8d7dad82361b9f08688c78fcd524716b361cf210f134447905df5f58684aaf92d1f2fccd3faec8257844c590b155500000090c3a22867a8620f0e9cfffe28abac99b5449612bb6fd54c64303404077ff93221b0a6bbafb6dc1853121a38e8c41ceb201a4f72df30772822d0b0bf66fc5dd591fa7aab4dfd97eeefebf334097310658d0b1835b434bc3c7f4d3eba6051adbe7c0a56fbe6b7c99a3d6bb819b99b0646b710c09af243e9832dab652c0c777fb31c637aa7990452cedbbe5bf99fce564c1a00000128000000905cd7fd8043ebaf521a9cbd850967d37102d09f6578502cff586e78e552fb106abb60f660939c2a3a3425b9124b497d6e6da586baa74107df8af0dce982ce18eedaf56291a4578ee8d1fd147f90dcc8d60c0bfab51bafd8a24ec632ae09d3c9a69be585ce4e2ccae10be1fbd4a9fd76901e434cc1de5dc161de968aca244423a3a0d210d9d85c4518392b51aae13ff5bf00000090048a99423dd6dc09bc6ef055ccaaca0c591ad76d5dd5ee848580b5d183ea8d161b8ce35ca9dda3062b1919d347cfbc77c010a9a05a570f66bafac197419623b391d9cdad6621d9d9231537da704053b228d75d4f7f81682b8d581a30341a1bfd728965b622ff550008bcc73449d31f98098c20a8cb29424f1e69839742c2f17dbdf6a281d2f5fd28fd7182c77a9bed44000001280000009062a63d4cf8d7e88a831a4b2349f029df81f36572692d59e4a00a832fc78ac0c7d51aba71d7c5214c15806414e7c67b80fd6b87f0f5b7fdf255ec1794892d916eace9d91a8c6e4b0a90f009757b7261e8117d0f9c42a7e9b8b32ec9a46ec5fdd90e1ecd316dcda61c20e3c6eb9a8c850b15b0cdb0f70fef21bbef0ca1e514a28b1cb31871c75544235aecbf71a21c545900000090071d96e7f10252ddfef08711ab174fb56815d2886d3cb0ff770d8f271ecb28b52c7538cbe64f64a2062338df714fefb0dda0d2c3bd84bc961f7c78ca64e0dc0fc14aa1461a3cbf46c7a37970035fe98228c639c8b16c7b7a8fa6da42025581728142ca87773a67db46c28d7010a37be02948daaa6e9337189af4e0a7e16bb81c2476fa89bf00293017e757bfc1cb61310000012800000090305a5f090659bc284517b422b4073f2e32dc2ef731975ba67b96b4fcc6c952a52ec5cae273e7baf8885dd09d34cbc26a1ee3ea3498e3b5afe3f6e1aaa16bb544361a14f28cfae1a432e6b9ead74e18c12ef26791a8be4f0f7fd1959c0adaf46aa248fcf9c8cc776a54e188a4359fcb5d20faa413d68296ef1cb4ef274d42fd14aa5a92f37da51a0a6ed70ee12ab729df00000090f2395c0f619282673828c1636b1ea89a24302c610aa201824597322290193f759bdd5fba022e8545ca4e2edf05a40e97a5f41c18c06922a6a51dad573c0b7ee8c86cb0d290cbf2911e85a6813d7e11a20113f2dbceda944ff9308864ddbaa44d3f4c973e8ffb2feb80ff262a90773de82d90b97f239e92bbe51daa611577e7106038b7ceee0653fdfb71fe139effa92f0000012800000090f7312fc5ca7141f83996c597a01d9a0804913e7ef437b745189b553fe644b8ca9feeda938cb44eba925da1e7013fe33dee342cbe9e0b2788b7ae84ceaf235b71f94d9739b3227aea90a9d5405c0842d20c176184b55a38c7b0b8796ba90b07d1c6025fde1202f338cb3823898f23bdbb068c8dd7bb497a495e16ca21540e5f666d72f81f84943458256f1752121363cb00000090cd285bcaae2aaeac2d03b8c6956c3d34a00713d06965c991537134b6e893b5a3883390755fc103d92d3aa86c12f5b4442996d90dea03f021b806587046527c81b2e9f29e9187981dbacf20c462f6d9fb24ea5ae8a3060d7086221c3ab203624d5ffd1f0c5471d39d8abb1cf97db3faf30903520eadaabc77bd632031901e332f9f59eeb827ca7c2ac4cb3fff1cffea7400000128000000902fa51fbf4061a5c510008fc8f50dd7bea7e307c536d6ac7a1be04f63e350854dc001038d15c85f02046cb4ba99cddc1d0854f732c3bbd6c1a2ce3b9539b09ed75cc6799b3e3f7ea1906cb3e19b680978172d5e3a17d534611558b0974f27eeb80f11777d5c318b41e6844a205d90fd101e89e3a3ae05e2e9d335f38993d1ce40886900f317fefd077ba81368619d3f720000009082b1c27b7a64487bbf9d21871c878d04d6ea2d2a2a02373731e778750c81b8c89cd49b77f4af23ceae879f455029fcd1cf1dd56e1bee390dd3ec7c4e442c8a3607aebd50588621cae5b2e8e39b595f0c08a2a2f9fd73e7ce1bcdb28aaaa2a69bb3e85c20b58c861c3e158d4e106c785b0d65a543d817766a0496b91a90177b11a021181890c57d1bbbdc24f889cf1b62000001280000009001486e187b12186066c262477a0c9b4d03da45d3fd17af3487d985c03e46b03827b85622a2d8d00a1d8d2d07a84334cbf46c2ad6237afc95777824fa36a6049a568928d6a44f95f56ce61ea7457676b808c5acb1048ffa52e82ab9c059105deb84d041e13b132aa83142025293d9ee5607d19c7ca42e4ad037fffc86912010ca66386ef730cca4fabf41f7c6f5d13d3c00000090b7b2e46bd11fa912cbb171373688e4dbbbbe2b1b1ad04b37ceed2d53383919ecb1ec5690b91e1b30580453e59ba400bcdb76196d7c9d4927b00729e83ece424027a00e3276a93a61e84f520cc2f9b22209ad7cdd9fc875574302af75edc79983ec50596913c818961ad536298a310bc9183c3356971710818f06d0f260bd55d281087c8443058caaff394fd5a16a591000000128000000907a02b1a361c9e424797122d88f4883f61f09782cf351770c7d5577ad63d8291cca761a30d0a12cd1907a3c5f49470ee3839fc53d553db7bcf7978f5618007f4ea5c8ef5e230de4dd58a41c44a37fd9d129390c2ce362eb410da7ced607affbc53b841f31b58b6c0390d0dfa2b40e523817e47d9632e8e99d4a790f4f1476b47f63d6b90af6afe874347831f17e09820b00000090dfb3da723599fc52984084adc867d5b131624fb3a245e28097259b2ab9b5b60150fa80d7ff242fd0fdfda863778237e27d806cf7cae596e4f7c740689a7841b29c9a42d91eeeb3f3855d3da4d0d6694a1dcd9883ba8e205afe4e4712ef9113b129f648b6d3565fddee1d9202ef11d943145d3d6be489fd048d4626d2bc2ebc67ffdaf751ddb2cfa80f208aebf82aa3ad0000012800000090031c03dea41e91646208787581d5f4e1fb17302c08af4cd0668bc69dcfca307c928f6882dfaefa3f63793669c2168840617186da887e243c32a81d832a7070909d36021d76e58e001b74741e8cf37caa2662b915209192553f3a8171d57594d6bd4fcc3f41a8b27c16b7235ab08e317d1e953df7144645d59c657ccbe4b62ee8d64b3296548d7bbf1563093e87d7af1e00000090607f885db8abe4abde918c437fc0081506c5e8c1f25572fe375e43360c6c1013c597cb2b8a240d62864c00c17ef60005efb0fa59a155efb45fd62f17f862b53635ebe15728533820c500fd561abddf461d242081b026fb75401170bd90373cde8c5ba92a46caa46921dc6e6b71a91b2d2a94d77336cf9aeef2625fe24fd6e30a38a4ab63d1487c217fede88a5da38c17000001280000009086150a0013518186b565e0a6194b5ed3735e8fe2dbffffe3d4f7ed2281729dfa1a3334ecee8ddcebc91b11297ca7faa95d33f42e04e0e504e8f5fab8cd765a62ebd6e207658293914365809ec1497fd2298ad1cfc963aa5be4f2d86833961589ed49aea8df5f799a050918839cb1f4122978dce47fb40af8652e272155161c817cbb6278132d83265032d0f827c175ac00000090ee0452ea31f58cfbfe6862d55fb398794f3a199f3246b25dc4c8e4c61bfdab38f24e55749090130ada3eb60a284a88e294fa3b2e53890cc04849fb7588e10e3c3e4004c852db076c35de46c80a77260e1485f3e68ae14a08291158119ce92e1daeeadf640d5200b1b1db5c0ac2eb06632a83c101c86519295e058572e190e60275aa6a48d510ecdffae2095c6762300b00000ce400000128000000902c803df8807403369c656432cbdce60e1d926579bbba600313a8d722004e1ce464c3497551481be9f557671cffef62cf33348341244dcc7a00192f577d9f6fce776bd7b1529c625dcbdb80c61f2052e607086554e7057fb4303431adaaaf418167ff9fdd6d368d483713bae6a36f271e2bd77291619445eadf6363ef91ab37c95471f15b645264038c8b96b2dcfc8a3d00000090f59f02cfbb765e4a792754cc77ade007c2092e7130b95df0372803afbaf98ed2c5358375a5ee56e7f7e8bbc1dc7cb9243e8266c5361549fd869e956bd4618ed69c66bba2f1ce02f1ff77be776a59581d242876eafda24466264bdc6ac348b1ebe8d441181bde9aa6a534ffd7b446ec6c2bc6cfe5da9ff2c0e01153ad2f16611e830fb986e0aeb74c6c63d47c0c11410800000128000000905567fd5df02f911fca4e64532ef338fbc78f51e0711d133520c87a53dc004d5123b21333da8b8a92f0c02b4cefd1a3b74eedb56197983bfc0782c22d0595ae7bf6fbf909f6d240f412adab0e7330e5f1037eefb93404ec11e5ab0786b4c26da0150d51823dd51a5e9357febdad38f762240b1c7df5f5243248a7697e42b37fd714431b773d88fe2e7053976d4c773d1a00000090acbe7b8b2ff927a57e136525fdcdddd5fc9fec566fdf556f36fb87a2357035fb2e9f1c42a1ac92435a8cc14f17b73a87b1a0a3a6cabd1cb1fb4fc5190a6fe82113a0185071cd5f4c2e744e90ce435ae30ccdd0febe82f66fb54c36568b047519a96a18ebc54166ce442cfea254468de70c9513735ae8838bbc9cf0fe268d9f531bcafcb435e050a753a870466a16345900000128000000909dc9ccaaa169fe8f19996407f90983d83d1c6f297cb95066d7f8ec4313f5511cbc17ecbb4f0174606f923241ffdccb87467cdb5ea0c109e0425538e919ffcfc59591b30b2243bd8d04678a7bf7e5865a01b2ddcc608a28726322ecdfe1a3acf5c78844eb23207c21cc5694371725bcba053ec047b8790e19db88aafad5fa2849dfee7518644406873caa13ff0d0a855900000090348d0b1171214af22f5a822da37c072a2746c5884260dfcbc603c9ed223be74bede40529a01381808b1722f6d5b92f31a3dd0a8a89b2f25c32cac9a0e67e26c3f1566d52b1bbb081363eb3fc5bcd96872ab570861949126649e9d01ca995f837f673925eed0e23f70fcf0d1701b3875f143b10a44e6762968dcd217361d1466acb824d61175b08ca34d9a9374011d7d80000012800000090f48952a0956883a34c401a10c9f97ec53efae1c9ec4c7b5230c864ae0ca7c0fc218729bdbaf89b347614e766d51aa170680688118afe46c5cb2a817b4f1cdcb412e598765d460463398d286e893ba96527fa6cc20569bc654a8cf1e76df5e41520450f3e9646674910a7cc5f2f6ad6cb07b03a6ed5e7670e4494fb13f7d5a75e72cd728d0363d7aa08b7761abef4b3da00000090db2897a0437ec2ba9f366e88ece23670290ff06e269eaafc1eecb43b41aa7f53a96fa2933f28022938dc4d4d7e397844e4a9bcd7f79968ab01e05277e7f8d820aed271e6198e5ee96f6a70bb0c1cbdb929a9c306aeab9c7afbfe3b2c9558798659aef641daefc0a1801b4aa613faba162dc55de1173652dea99a971823c29032661767bd75f24dc53aaf995f98cdc6890000012800000090c7a4aca8720eb3649eac8eb7419ecae0725206544f9f14c135f867014c33595ab494a94226c3fba20a3b6dd078cec20d7032c0478533261815d5c6f34c7490910af1acbf60dfa203a974b3526e0d6f170853c20b3dd2891391e32c4e5e6dae96aae97bf3a0c483a33d2bfed18b518dd60a43da0389df5659213258d86506493a11c476c6173346943409877f3f1eb8280000009044cd6d5591321c78d3ad1ae1bf3920701d1cc0c6a73b5b5d9034c05466de6a3b7c9dcfa0bbca612a895d7a418e1b1513413160f9e6a343415f57b3e9cc3865c966586d3b70c285048326cfd317ee6b9f250307f80b904bbcaae1cf998bab4d7e0c3c9d6067e16993e186577841c0bcc42a7732ed26e008b9e9a8ec5db481cb59cf3533dfc6200ef3ebf40a40c4dff644000001280000009005acab802e3f5f7d14a97db5dc83caa849d21005335eb64ee3f7d7890913e47c41935942c6492765d1683f3e58618210b938eadbca1972fb3ca6f933e13eb53cc28a8cd4bb551016e8e6da5f43bbe527212154a463316eeafe582bae589ec21dc4a3f04ce8be15fa7574cc8f85297a7519d803802bb93115202731de6c949bfdc7b897c2c20e55699a45b639e74197f700000090db8755368a5883f4c8fe4f1bab8967d086a2c03cddbe926a6b89d2193ef0e497f2082b9a924618d54e483ea64081ae51a51c10602447801112189d25e238ca3f40e2c1b0fd34aca316716b7bd3294e4413457e9893aa9397a1d8ef44dd4fce4e51426d55377084185406aa294c6c05e82202efcb16b1d3d895622c79efaf7de68f35c641bc19758cf04bff359e492efd000001280000009087ac7014e5e07bff87399657ee1763c71b8999148890bec2db8c429b1f90bbd42d17eb24235c38a58e5fc5731d4817ac467a3cc83c85940cabee34021c15207429514ff47a00c8b2064f38ed9513daa827655841b9ec89ae70fd3322615750c4e254c912b65a0e47da5e9d887dd6066c14c97dd4139a5e24272d10c6c8af9e008326ffc35057b8e61b56b89dd7026c48000000908f003eda2f032f79d6daa0afae9e777d8395e8b99a14c184826924c613f2c2cfd771420c41e34335484310ae29eb2f42354ce93093db217cd73f1ad1d7c82751c9840f009bf99fae72f6499e5aabe4e7303b2e67e46729ccb482876659117e12fbea701f7f693c686690f16037629e3f2e4afd1cd9ba7c7792e0f75312d43121d679cb3700ba52bb99bf7163175f39340000012800000090fcb668f4eee987dcf91f02506c4e276cbda61f718d249c1b146908ae48773bf119357acb0d33d981d04fa30e254b74786b8af9d6231aed0d2ab609a427aa1cd7269d05a908be3edff62849db15916753094633d30c8e1e1824d63a471510520a61500be387faced8d8f2397897a79b9100b2c3749f0cdb1b89a4635ac91966fef5328f7a51d75f6a64c5cf262929d0ea00000090e1fd1913250e3383ece01108e3676dbf45b6af7cd54328a1a6a9e032b3acd5c84c7330714433f147691a15dde1097a246a54c59aac1547f291930e5fd3994c71eea3b96288c1c2444609b675711a615608fedc92c08b028e141a647c4c6240e10e01a1b517bc9b1fbfffedeaaa84939d108fb5b48bcce4a6403fb3a6297a864177d35ec2f56b2f41c1a5c18fa77c78000000012800000090246b9ef39b4c1f688e2a9bd94cd7886aba49dd6c2d7a994a55b3b210fa54d50b1d94c7314b1dd66727a04194461377f021887f0bf08d7132952ac4fefb34a22382487b2819ff3f689c191ec33cd639fc0354c3c1f82acb0665b97f78cf4d7ea6edbc09645d6fc091fbdda38ab51d614206ed1eb6712031a70239dba48af173cc72ce5c8dbd4b2f2ead260eaf139fc76c00000090c47bca9d4280b30fdd30ff309d250754b715513d9b7d45b38690e683cb07c2aaaeb63b0f0400b0116a77e295240d94e39c7682a0f1ec9e1396aafcb5ba80053a5ffb4cdc262aee196781d2c3c92e5ec31abe900aae102106925359f393e17163def75522a8363506ff77b008dfb3598f15cd1ad0f1cd2c9940d6e35a85fa4aff06b2fca127af77cf85b7ecf2134c127200000128000000901efcd448119223b36296649ae27271c8ce44425c2257bb3b4d322767bbcc93df4e3405b9d57b89cf3a321725617ccd1718e3c2b485bb72e40a5b661e7c6674522447171d2d600265fd1068307f5eddbc031b050c27fc1f6035e51fc86890af02b773a7bf6a2b79151cdefe58e55c368405fbc782501d3ec15e509d762b578fee3711ec85afcbe3ca31714291ff4e84210000009020105be65d60c582c38af508ff84d115ba0be30df8b55ba5b2644bbb15c4dc9dfb46399a7bedc1e12e57530f8d2fdba47e9f59062a9384c5eb496795964f33e222a91ee413495921cd45f18ec0bef4a013d91373d3e7c6b40cb9eab782d295c6bfc1fefe73de88e8ae380363827204bb2fd4f44899b714ae567340e9d2b75ce56290389379b01521fc01b1ca40fd7eb40000012800000090221861a7da93d0ea2098a2dfd72369f097f2390e73e14b94284bddb6aa412027cd015bd818e966516ad0808b28e95ba99b04271cd979480ba3a70513df67c7d10adbbebf39059d48bd90d70fad88a11b15a453727995b3da07902ea4ec062384240e406e45222bc6fd8b85c2a97bf1d2282e381e70d50ed6a430be46b27ae56fde68dfc666c7301c37cb7109283cdee60000009020e262f5717b624c3dc1b984830aeb3377f9952d1efcd31851ea323cd10d6502da352474fbb82c370582a685612f768d4591761d67d3923c697222229eb6e39aa40e9103d896d9085969a6e250ac170826e9d5dd40287b9c06c538743a402ed9c7d4c84429afa70fc4a308caa453ce4919a295d209efe58669e9f8b23280e245ee5c5295c434be404440831f44d4bd63", + "calldataHash": "0x484df1f693f6fe8712cc9129413652b277db358ece78850f1073d963c1258286", "decodedHeader": { - "bodyHash": "0xf4525fad966caa2a5a1c5c4ca03520c2652aa2835f67fcad64b97e05cfb2870e", + "bodyHash": "0x484df1f693f6fe8712cc9129413652b277db358ece78850f1073d963c1258286", "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1705501882, + "timestamp": 1706272843, "version": 1 }, "lastArchive": { @@ -92,8 +92,8 @@ } } }, - "header": "0x0000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065a7e4ba06c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e00000280022612683c6c4a0955c8248d409bc8ec8776d96a3bfe5b5a7e76e492a4f26cb000000008039e689049f104493f0e819b00d874663f0724639f854b8722e8ee829b0f136a000000a01f1de772c009f5b1660876343eb57b7a676a84c695b0c526de2f238c4181090700000002f4525fad966caa2a5a1c5c4ca03520c2652aa2835f67fcad64b97e05cfb2870e", + "header": "0x1f1de772c009f5b1660876343eb57b7a676a84c695b0c526de2f238c4181090700000002484df1f693f6fe8712cc9129413652b277db358ece78850f1073d963c125828606c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e00000280022612683c6c4a0955c8248d409bc8ec8776d96a3bfe5b5a7e76e492a4f26cb000000008039e689049f104493f0e819b00d874663f0724639f854b8722e8ee829b0f136a000000a00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065b3a84b", "l1ToL2MessagesHash": "0xa10cc8559615be5a44cfb608374b1f84fd11cdb5844ebffafd92a77c068350f1", - "publicInputsHash": "0x280997cb13c04842e88c31fb0d4db23d591c48aea40d9a5aa2e18fd4c72a0358" + "publicInputsHash": "0x2cbde160e7af7c59ad9714ca77d07e5dca90aa6016d28e7939e201190b06740c" } } \ No newline at end of file diff --git a/noir/.github/ISSUE_TEMPLATE/config.yml b/noir/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index b5ded344eb9..00000000000 --- a/noir/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,4 +0,0 @@ -contact_links: - - name: Ideas - url: https://github.com/orgs/noir-lang/discussions/new?category=ideas - about: Share ideas for new features diff --git a/noir/.github/ISSUE_TEMPLATE/idea_action_plan.yml b/noir/.github/ISSUE_TEMPLATE/feature_request.yml similarity index 90% rename from noir/.github/ISSUE_TEMPLATE/idea_action_plan.yml rename to noir/.github/ISSUE_TEMPLATE/feature_request.yml index 02fed1fc48b..979ac75811e 100644 --- a/noir/.github/ISSUE_TEMPLATE/idea_action_plan.yml +++ b/noir/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,5 +1,5 @@ -name: Idea Action Plan -description: Outline the scope and steps for implementing an enhancement. Start with "Ideas" instead to request and discuss new features. +name: Feature Request +description: Suggest an idea for this project. labels: ["enhancement"] body: - type: markdown diff --git a/noir/.github/scripts/wasm-bindgen-install.sh b/noir/.github/scripts/wasm-bindgen-install.sh index b8c41393ab0..a147a46cde8 100755 --- a/noir/.github/scripts/wasm-bindgen-install.sh +++ b/noir/.github/scripts/wasm-bindgen-install.sh @@ -1,5 +1,5 @@ #!/bin/bash set -eu -curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash -cargo-binstall wasm-bindgen-cli --version 0.2.86 -y +# TODO call this script directly +./scripts/install_wasm-bindgen.sh diff --git a/noir/.github/workflows/docs-pr.yml b/noir/.github/workflows/docs-pr.yml index f4a1be826a8..87bec37c438 100644 --- a/noir/.github/workflows/docs-pr.yml +++ b/noir/.github/workflows/docs-pr.yml @@ -54,6 +54,15 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 + with: + key: x86_64-unknown-linux-gnu + cache-on-failure: false + save-if: false + - name: Install Yarn dependencies uses: ./.github/actions/setup diff --git a/noir/.github/workflows/publish-es-packages.yml b/noir/.github/workflows/publish-es-packages.yml index e360654b46a..2c825ffd45f 100644 --- a/noir/.github/workflows/publish-es-packages.yml +++ b/noir/.github/workflows/publish-es-packages.yml @@ -15,7 +15,7 @@ on: run-name: Publish ES Packages from ${{ inputs.noir-ref }} under @${{ inputs.npm-tag }} tag. jobs: - build-noir_wasm: + build-noirc_abi_wasm: runs-on: ubuntu-latest steps: - name: Checkout sources @@ -32,16 +32,17 @@ jobs: - name: Build wasm package run: | - nix build -L .#noir_wasm + nix build -L .#noirc_abi_wasm - uses: actions/upload-artifact@v3 with: - name: noir_wasm + name: noirc_abi_wasm path: | - result/noir_wasm/nodejs - result/noir_wasm/web + result/noirc_abi_wasm/nodejs + result/noirc_abi_wasm/web - build-noirc_abi_wasm: + build-noir_wasm: + needs: [build-noirc_abi_wasm] runs-on: ubuntu-latest steps: - name: Checkout sources @@ -49,23 +50,34 @@ jobs: with: ref: ${{ inputs.noir-ref }} - - name: Setup Nix - uses: ./.github/actions/nix + - name: Setup toolchain + uses: dtolnay/rust-toolchain@1.71.1 + + - uses: Swatinem/rust-cache@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - nix-cache-name: "noir" - cachix-auth-token: ${{ secrets.CACHIXAUTHTOKEN }} - - - name: Build wasm package - run: | - nix build -L .#noirc_abi_wasm + key: noir-wasm + save-if: false - - uses: actions/upload-artifact@v3 + - name: Download noirc_abi_wasm package artifact + uses: actions/download-artifact@v3 with: name: noirc_abi_wasm + path: ./tooling/noirc_abi_wasm + + - name: Install Yarn dependencies + uses: ./.github/actions/setup + + - name: Build noir_wasm + run: yarn workspace @noir-lang/noir_wasm build + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: noir_wasm path: | - result/noirc_abi_wasm/nodejs - result/noirc_abi_wasm/web + ./compiler/wasm/dist + ./compiler/wasm/build + retention-days: 3 build-acvm_js: runs-on: ubuntu-latest @@ -97,7 +109,6 @@ jobs: runs-on: ubuntu-latest needs: [build-acvm_js, build-noirc_abi_wasm, build-noir_wasm] steps: - - name: Checkout sources uses: actions/checkout@v4 with: @@ -107,10 +118,12 @@ jobs: with: name: acvm_js path: acvm-repo/acvm_js + - uses: actions/download-artifact@v3 with: name: noir_wasm path: compiler/wasm + - uses: actions/download-artifact@v3 with: name: noirc_abi_wasm diff --git a/noir/.github/workflows/release.yml b/noir/.github/workflows/release.yml index 22a733b38c5..7dfc844d18f 100644 --- a/noir/.github/workflows/release.yml +++ b/noir/.github/workflows/release.yml @@ -11,7 +11,6 @@ jobs: outputs: release-pr: ${{ steps.release.outputs.pr }} tag-name: ${{ steps.release.outputs.tag_name }} - pending-release-semver: v${{ steps.release.outputs.major }}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}} runs-on: ubuntu-latest steps: - name: Run release-please @@ -80,9 +79,15 @@ jobs: - name: Install Yarn dependencies uses: ./.github/actions/setup + - name: Query new noir version + id: noir-version + run: | + NOIR_VERSION=$(grep '^version =' ./Cargo.toml | sed -E 's/version = "([^"]+)"/v\1/') + echo "semver=$NOIR_VERSION" >> $GITHUB_OUTPUT + - name: Cut a new version working-directory: ./docs - run: yarn docusaurus docs:version ${{ needs.release-please.outputs.pending-release-semver }} + run: yarn docusaurus docs:version ${{ steps.noir-version.outputs.semver }} - name: Configure git run: | @@ -92,7 +97,7 @@ jobs: - name: Commit new documentation version run: | git add . - git commit -m "chore(docs): cut new docs version for tag ${{ needs.release-please.outputs.pending-release-semver }}" + git commit -m "chore(docs): cut new docs version for tag ${{ steps.noir-version.outputs.semver }}" git push build-binaries: diff --git a/noir/.gitrepo b/noir/.gitrepo index a1a7bb59118..79073b8512f 100644 --- a/noir/.gitrepo +++ b/noir/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/noir-lang/noir branch = aztec-packages - commit = e470b94de7f3a0db4999a4b57d6e97298505415c - parent = 9136d32268db350779d51e45884368be3a694220 + commit = ea6aebcc4e190d9dbadaf1dd0f70950651eed615 + parent = 37cb60587bb2c8f4b7b9275110e23b0f6babda3d method = merge cmdver = 0.4.6 diff --git a/noir/Cargo.toml b/noir/Cargo.toml index 8a827cacfcd..5dfff3dbb5d 100644 --- a/noir/Cargo.toml +++ b/noir/Cargo.toml @@ -52,7 +52,6 @@ repository = "https://github.com/noir-lang/noir/" acir_field = { version = "0.39.0", path = "acvm-repo/acir_field", default-features = false } acir = { version = "0.39.0", path = "acvm-repo/acir", default-features = false } acvm = { version = "0.39.0", path = "acvm-repo/acvm" } -stdlib = { version = "0.37.1", package = "acvm_stdlib", path = "acvm-repo/stdlib", default-features = false } brillig = { version = "0.39.0", path = "acvm-repo/brillig", default-features = false } brillig_vm = { version = "0.39.0", path = "acvm-repo/brillig_vm", default-features = false } acvm_blackbox_solver = { version = "0.39.0", path = "acvm-repo/blackbox_solver", default-features = false } diff --git a/noir/acvm-repo/acir/codegen/acir.cpp b/noir/acvm-repo/acir/codegen/acir.cpp index 487bb33a6b2..0f94e91ab10 100644 --- a/noir/acvm-repo/acir/codegen/acir.cpp +++ b/noir/acvm-repo/acir/codegen/acir.cpp @@ -265,7 +265,17 @@ namespace Circuit { static Poseidon2Permutation bincodeDeserialize(std::vector); }; - std::variant value; + struct Sha256Compression { + std::vector inputs; + std::vector hash_values; + std::vector outputs; + + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -661,7 +671,17 @@ namespace Circuit { static Poseidon2Permutation bincodeDeserialize(std::vector); }; - std::variant value; + struct Sha256Compression { + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; + + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; @@ -2848,6 +2868,50 @@ Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable BlackBoxFuncCall::Sha256Compression::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Sha256Compression &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Sha256Compression obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BlackBoxOp &lhs, const BlackBoxOp &rhs) { @@ -3732,6 +3796,50 @@ Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable BlackBoxOp::Sha256Compression::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256Compression &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); + serde::Serializable::serialize(obj.output, serializer); +} + +template <> +template +Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::Sha256Compression obj; + obj.input = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BlockId &lhs, const BlockId &rhs) { diff --git a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs b/noir/acvm-repo/acir/src/circuit/black_box_functions.rs index 358722900ba..97b4759d350 100644 --- a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/noir/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -61,6 +61,8 @@ pub enum BlackBoxFunc { BigIntToLeBytes, /// Permutation function of Poseidon2 Poseidon2Permutation, + /// SHA256 compression function + Sha256Compression, } impl std::fmt::Display for BlackBoxFunc { @@ -95,6 +97,7 @@ impl BlackBoxFunc { BlackBoxFunc::BigIntFromLeBytes => "bigint_from_le_bytes", BlackBoxFunc::BigIntToLeBytes => "bigint_to_le_bytes", BlackBoxFunc::Poseidon2Permutation => "poseidon2_permutation", + BlackBoxFunc::Sha256Compression => "sha256_compression", } } @@ -123,9 +126,11 @@ impl BlackBoxFunc { "bigint_from_le_bytes" => Some(BlackBoxFunc::BigIntFromLeBytes), "bigint_to_le_bytes" => Some(BlackBoxFunc::BigIntToLeBytes), "poseidon2_permutation" => Some(BlackBoxFunc::Poseidon2Permutation), + "sha256_compression" => Some(BlackBoxFunc::Sha256Compression), _ => None, } } + pub fn is_valid_black_box_func_name(op_name: &str) -> bool { BlackBoxFunc::lookup(op_name).is_some() } diff --git a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 110a524f746..ba4964c8912 100644 --- a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -155,6 +155,21 @@ pub enum BlackBoxFuncCall { /// It is the length of inputs and outputs vectors len: u32, }, + /// Applies the SHA-256 compression function to the input message + /// + /// # Arguments + /// + /// * `inputs` - input message block + /// * `hash_values` - state from the previous compression + /// * `outputs` - result of the input compressed into 256 bits + Sha256Compression { + /// 512 bits of the input message, represented by 16 u32s + inputs: Vec, + /// Vector of 8 u32s used to compress the input + hash_values: Vec, + /// Output of the compression, represented by 8 u32s + outputs: Vec, + }, } impl BlackBoxFuncCall { @@ -184,6 +199,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, BlackBoxFuncCall::BigIntToLeBytes { .. } => BlackBoxFunc::BigIntToLeBytes, BlackBoxFuncCall::Poseidon2Permutation { .. } => BlackBoxFunc::Poseidon2Permutation, + BlackBoxFuncCall::Sha256Compression { .. } => BlackBoxFunc::Sha256Compression, } } @@ -201,7 +217,8 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::PedersenCommitment { inputs, .. } | BlackBoxFuncCall::PedersenHash { inputs, .. } | BlackBoxFuncCall::BigIntFromLeBytes { inputs, .. } - | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } => inputs.to_vec(), + | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } + | BlackBoxFuncCall::Sha256Compression { inputs, .. } => inputs.to_vec(), BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => { vec![*lhs, *rhs] } @@ -296,7 +313,8 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::Keccak256 { outputs, .. } | BlackBoxFuncCall::Keccakf1600 { outputs, .. } | BlackBoxFuncCall::Keccak256VariableLength { outputs, .. } - | BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(), + | BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } + | BlackBoxFuncCall::Sha256Compression { outputs, .. } => outputs.to_vec(), BlackBoxFuncCall::AND { output, .. } | BlackBoxFuncCall::XOR { output, .. } | BlackBoxFuncCall::SchnorrVerify { output, .. } diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs index 246eeadc095..970eb9390bb 100644 --- a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -126,6 +126,9 @@ pub(super) fn transform_internal( | acir::circuit::opcodes::BlackBoxFuncCall::Poseidon2Permutation { outputs, .. + } + | acir::circuit::opcodes::BlackBoxFuncCall::Sha256Compression { + outputs, .. } => { for witness in outputs { transformer.mark_solvable(*witness); diff --git a/noir/acvm-repo/acvm/src/lib.rs b/noir/acvm-repo/acvm/src/lib.rs index 626bb2c9b91..264479d8a12 100644 --- a/noir/acvm-repo/acvm/src/lib.rs +++ b/noir/acvm-repo/acvm/src/lib.rs @@ -31,3 +31,13 @@ pub enum ExpressionWidth { Unbounded, Bounded { width: usize }, } + +impl From for ExpressionWidth { + fn from(width: usize) -> ExpressionWidth { + if width == 0 { + ExpressionWidth::Unbounded + } else { + ExpressionWidth::Bounded { width } + } + } +} diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 3baf99710ad..0f026cd274a 100644 --- a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -197,5 +197,6 @@ pub(crate) fn solve( BlackBoxFuncCall::BigIntFromLeBytes { .. } => todo!(), BlackBoxFuncCall::BigIntToLeBytes { .. } => todo!(), BlackBoxFuncCall::Poseidon2Permutation { .. } => todo!(), + BlackBoxFuncCall::Sha256Compression { .. } => todo!(), } } diff --git a/noir/acvm-repo/brillig/src/black_box.rs b/noir/acvm-repo/brillig/src/black_box.rs index f5f5c53803e..22fac6f3ba3 100644 --- a/noir/acvm-repo/brillig/src/black_box.rs +++ b/noir/acvm-repo/brillig/src/black_box.rs @@ -114,4 +114,9 @@ pub enum BlackBoxOp { output: HeapArray, len: RegisterIndex, }, + Sha256Compression { + input: HeapVector, + hash_values: HeapVector, + output: HeapArray, + }, } diff --git a/noir/acvm-repo/brillig_vm/src/black_box.rs b/noir/acvm-repo/brillig_vm/src/black_box.rs index 9935005a5ea..e9c25200c47 100644 --- a/noir/acvm-repo/brillig_vm/src/black_box.rs +++ b/noir/acvm-repo/brillig_vm/src/black_box.rs @@ -200,6 +200,7 @@ pub(crate) fn evaluate_black_box( BlackBoxOp::BigIntFromLeBytes { .. } => todo!(), BlackBoxOp::BigIntToLeBytes { .. } => todo!(), BlackBoxOp::Poseidon2Permutation { .. } => todo!(), + BlackBoxOp::Sha256Compression { .. } => todo!(), } } @@ -224,6 +225,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, BlackBoxOp::BigIntToLeBytes { .. } => BlackBoxFunc::BigIntToLeBytes, BlackBoxOp::Poseidon2Permutation { .. } => BlackBoxFunc::Poseidon2Permutation, + BlackBoxOp::Sha256Compression { .. } => BlackBoxFunc::Sha256Compression, } } diff --git a/noir/acvm-repo/brillig_vm/src/lib.rs b/noir/acvm-repo/brillig_vm/src/lib.rs index cb957295819..0c258ab34d6 100644 --- a/noir/acvm-repo/brillig_vm/src/lib.rs +++ b/noir/acvm-repo/brillig_vm/src/lib.rs @@ -168,7 +168,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.registers.set(register_index, value); } - pub fn get_memory(&self) -> &Vec { + pub fn get_memory(&self) -> &[Value] { self.memory.values() } @@ -741,7 +741,7 @@ mod tests { let opcodes = [&start[..], &loop_body[..]].concat(); let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.get_memory().clone() + vm.get_memory().to_vec() } let memory = brillig_write_memory(vec![Value::from(0u128); 5]); @@ -897,7 +897,7 @@ mod tests { let opcodes = [&start[..], &recursive_fn[..]].concat(); let vm = brillig_execute_and_get_vm(memory, &opcodes); - vm.get_memory().clone() + vm.get_memory().to_vec() } let memory = brillig_recursive_write_memory(vec![Value::from(0u128); 5]); diff --git a/noir/acvm-repo/brillig_vm/src/memory.rs b/noir/acvm-repo/brillig_vm/src/memory.rs index e2309537283..8a6993f1353 100644 --- a/noir/acvm-repo/brillig_vm/src/memory.rs +++ b/noir/acvm-repo/brillig_vm/src/memory.rs @@ -39,7 +39,7 @@ impl Memory { } /// Returns the values of the memory - pub fn values(&self) -> &Vec { + pub fn values(&self) -> &[Value] { &self.inner } } diff --git a/noir/aztec_macros/src/lib.rs b/noir/aztec_macros/src/lib.rs index 7c62f8f8169..e2c232e3233 100644 --- a/noir/aztec_macros/src/lib.rs +++ b/noir/aztec_macros/src/lib.rs @@ -36,32 +36,32 @@ const MAX_CONTRACT_FUNCTIONS: usize = 2_usize.pow(FUNCTION_TREE_HEIGHT); #[derive(Debug, Clone)] pub enum AztecMacroError { - AztecNotFound, - AztecComputeNoteHashAndNullifierNotFound { span: Span }, - AztecContractHasTooManyFunctions { span: Span }, - AztecContractConstructorMissing { span: Span }, + AztecDepNotFound, + ComputeNoteHashAndNullifierNotFound { span: Span }, + ContractHasTooManyFunctions { span: Span }, + ContractConstructorMissing { span: Span }, UnsupportedFunctionArgumentType { span: Span, typ: UnresolvedTypeData }, } impl From for MacroError { fn from(err: AztecMacroError) -> Self { match err { - AztecMacroError::AztecNotFound {} => MacroError { - primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml. For more information go to https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#aztec-dependency-not-found-please-add-aztec-as-a-dependency-in-your-nargotoml".to_owned(), + AztecMacroError::AztecDepNotFound {} => MacroError { + primary_message: "Aztec dependency not found. Please add aztec as a dependency in your Cargo.toml. For more information go to https://docs.aztec.network/developers/debugging/aztecnr-errors#aztec-dependency-not-found-please-add-aztec-as-a-dependency-in-your-nargotoml".to_owned(), secondary_message: None, span: None, }, - AztecMacroError::AztecComputeNoteHashAndNullifierNotFound { span } => MacroError { - primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract. For more information go to https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#compute_note_hash_and_nullifier-function-not-found-define-it-in-your-contract".to_owned(), + AztecMacroError::ComputeNoteHashAndNullifierNotFound { span } => MacroError { + primary_message: "compute_note_hash_and_nullifier function not found. Define it in your contract. For more information go to https://docs.aztec.network/developers/debugging/aztecnr-errors#compute_note_hash_and_nullifier-function-not-found-define-it-in-your-contract".to_owned(), secondary_message: None, span: Some(span), }, - AztecMacroError::AztecContractHasTooManyFunctions { span } => MacroError { + AztecMacroError::ContractHasTooManyFunctions { span } => MacroError { primary_message: format!("Contract can only have a maximum of {} functions", MAX_CONTRACT_FUNCTIONS), secondary_message: None, span: Some(span), }, - AztecMacroError::AztecContractConstructorMissing { span } => MacroError { + AztecMacroError::ContractConstructorMissing { span } => MacroError { primary_message: "Contract must have a constructor function".to_owned(), secondary_message: None, span: Some(span), @@ -222,7 +222,9 @@ fn transform( // Covers all functions in the ast for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { - if transform_module(&mut submodule.contents, crate_id, context)? { + if transform_module(&mut submodule.contents, crate_id, context) + .map_err(|(err, file_id)| (err.into(), file_id))? + { check_for_aztec_dependency(crate_id, context)?; include_relevant_imports(&mut submodule.contents); } @@ -264,7 +266,7 @@ fn check_for_aztec_dependency( if has_aztec_dependency { Ok(()) } else { - Err((AztecMacroError::AztecNotFound.into(), crate_graph.root_file_id)) + Err((AztecMacroError::AztecDepNotFound.into(), crate_graph.root_file_id)) } } @@ -323,7 +325,7 @@ fn transform_module( module: &mut SortedModule, crate_id: &CrateId, context: &HirContext, -) -> Result { +) -> Result { let mut has_transformed_module = false; // Check for a user defined storage struct @@ -332,8 +334,7 @@ fn transform_module( if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(module) { let crate_graph = &context.crate_graph[crate_id]; return Err(( - AztecMacroError::AztecComputeNoteHashAndNullifierNotFound { span: Span::default() } - .into(), + AztecMacroError::ComputeNoteHashAndNullifierNotFound { span: Span::default() }, crate_graph.root_file_id, )); } @@ -350,11 +351,11 @@ fn transform_module( let crate_graph = &context.crate_graph[crate_id]; if is_custom_attribute(&secondary_attribute, "aztec(private)") { transform_function("Private", func, storage_defined) - .map_err(|err| (err.into(), crate_graph.root_file_id))?; + .map_err(|err| (err, crate_graph.root_file_id))?; has_transformed_module = true; } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { transform_function("Public", func, storage_defined) - .map_err(|err| (err.into(), crate_graph.root_file_id))?; + .map_err(|err| (err, crate_graph.root_file_id))?; has_transformed_module = true; } } @@ -371,7 +372,7 @@ fn transform_module( if module.functions.len() > MAX_CONTRACT_FUNCTIONS { let crate_graph = &context.crate_graph[crate_id]; return Err(( - AztecMacroError::AztecContractHasTooManyFunctions { span: Span::default() }.into(), + AztecMacroError::ContractHasTooManyFunctions { span: Span::default() }, crate_graph.root_file_id, )); } @@ -380,7 +381,7 @@ fn transform_module( if !constructor_defined { let crate_graph = &context.crate_graph[crate_id]; return Err(( - AztecMacroError::AztecContractConstructorMissing { span: Span::default() }.into(), + AztecMacroError::ContractConstructorMissing { span: Span::default() }, crate_graph.root_file_id, )); } diff --git a/noir/compiler/noirc_driver/src/abi_gen.rs b/noir/compiler/noirc_driver/src/abi_gen.rs index e546cd822b7..7fafa719186 100644 --- a/noir/compiler/noirc_driver/src/abi_gen.rs +++ b/noir/compiler/noirc_driver/src/abi_gen.rs @@ -63,7 +63,7 @@ fn into_abi_params(context: &Context, params: Vec) -> Vec { // Takes each abi parameter and shallowly maps to the expected witness range in which the // parameter's constituent values live. fn param_witnesses_from_abi_param( - abi_params: &Vec, + abi_params: &[AbiParameter], input_witnesses: Vec, ) -> BTreeMap>> { let mut idx = 0_usize; diff --git a/noir/compiler/noirc_driver/src/contract.rs b/noir/compiler/noirc_driver/src/contract.rs index ae55d239cf3..5f4b66e7dd2 100644 --- a/noir/compiler/noirc_driver/src/contract.rs +++ b/noir/compiler/noirc_driver/src/contract.rs @@ -26,7 +26,7 @@ pub enum ContractFunctionType { Unconstrained, } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct CompiledContract { pub noir_version: String, @@ -51,7 +51,7 @@ pub struct CompiledContract { /// A contract function unlike a regular Noir program /// however can have additional properties. /// One of these being a function type. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ContractFunction { pub name: String, diff --git a/noir/compiler/noirc_driver/src/lib.rs b/noir/compiler/noirc_driver/src/lib.rs index db69d41c704..6fd69f8b576 100644 --- a/noir/compiler/noirc_driver/src/lib.rs +++ b/noir/compiler/noirc_driver/src/lib.rs @@ -3,6 +3,7 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] +use acvm::ExpressionWidth; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; @@ -16,7 +17,6 @@ use noirc_frontend::hir::Context; use noirc_frontend::macros_api::MacroProcessor; use noirc_frontend::monomorphization::monomorphize; use noirc_frontend::node_interner::FuncId; -use serde::{Deserialize, Serialize}; use std::path::Path; use tracing::info; @@ -43,8 +43,12 @@ pub const NOIRC_VERSION: &str = env!("CARGO_PKG_VERSION"); pub const NOIR_ARTIFACT_VERSION_STRING: &str = concat!(env!("CARGO_PKG_VERSION"), "+", env!("GIT_COMMIT")); -#[derive(Args, Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Args, Clone, Debug, Default)] pub struct CompileOptions { + /// Override the expression width requested by the backend. + #[arg(long, value_parser = parse_expression_width)] + pub expression_width: Option, + /// Force a full recompilation. #[arg(long = "force")] pub force_compile: bool, @@ -75,6 +79,20 @@ pub struct CompileOptions { /// Disables the builtin macros being used in the compiler #[arg(long, hide = true)] pub disable_macros: bool, + + /// Outputs the monomorphized IR to stdout for debugging + #[arg(long, hide = true)] + pub show_monomorphized: bool, +} + +fn parse_expression_width(input: &str) -> Result { + use std::io::{Error, ErrorKind}; + + let width = input + .parse::() + .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; + + Ok(ExpressionWidth::from(width)) } /// Helper type used to signify where only warnings are expected in file diagnostics @@ -391,6 +409,9 @@ pub fn compile_no_check( let hash = fxhash::hash64(&program); let hashes_match = cached_program.as_ref().map_or(false, |program| program.hash == hash); + if options.show_monomorphized { + println!("{program}"); + } // If user has specified that they want to see intermediate steps printed then we should // force compilation even if the program hasn't changed. diff --git a/noir/compiler/noirc_driver/tests/contracts.rs b/noir/compiler/noirc_driver/tests/contracts.rs new file mode 100644 index 00000000000..c3041292352 --- /dev/null +++ b/noir/compiler/noirc_driver/tests/contracts.rs @@ -0,0 +1,42 @@ +use std::path::Path; + +use fm::FileId; +use noirc_driver::{file_manager_with_stdlib, prepare_crate, CompileOptions, ErrorsAndWarnings}; +use noirc_errors::CustomDiagnostic; +use noirc_frontend::hir::{def_map::parse_file, Context}; + +#[test] +fn reject_crates_containing_multiple_contracts() -> Result<(), ErrorsAndWarnings> { + let source = " +contract Foo {} + +contract Bar {}"; + + let root = Path::new(""); + let file_name = Path::new("main.nr"); + let mut file_manager = file_manager_with_stdlib(root); + file_manager.add_file_with_source(file_name, source.to_owned()).expect( + "Adding source buffer to file manager should never fail when file manager is empty", + ); + let parsed_files = file_manager + .as_file_map() + .all_file_ids() + .map(|&file_id| (file_id, parse_file(&file_manager, file_id))) + .collect(); + + let mut context = Context::new(file_manager, parsed_files); + let root_crate_id = prepare_crate(&mut context, file_name); + + let errors = + noirc_driver::compile_contract(&mut context, root_crate_id, &CompileOptions::default()) + .unwrap_err(); + + assert_eq!( + errors, + vec![CustomDiagnostic::from_message("Packages are limited to a single contract") + .in_file(FileId::default())], + "stdlib is producing warnings" + ); + + Ok(()) +} diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 62a1cef50a1..96d80cb8131 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -341,7 +341,22 @@ pub(crate) fn convert_black_box_call( len: *state_len, }); } else { - unreachable!("ICE: SHA256 expects one array argument and one array result") + unreachable!("ICE: Poseidon2Permutation expects one array argument, a length and one array result") + } + } + BlackBoxFunc::Sha256Compression => { + if let ([message, hash_values], [BrilligVariable::BrilligArray(result_array)]) = + (function_arguments, function_results) + { + let message_vector = convert_array_or_vector(brillig_context, message, bb_func); + let hash_vector = convert_array_or_vector(brillig_context, hash_values, bb_func); + brillig_context.black_box_op_instruction(BlackBoxOp::Sha256Compression { + input: message_vector.to_heap_vector(), + hash_values: hash_vector.to_heap_vector(), + output: result_array.to_heap_array(), + }); + } else { + unreachable!("ICE: Sha256Compression expects two array argument, one array result") } } } diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index db005d9d438..b084042981b 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -564,6 +564,7 @@ impl<'block> BrilligBlock<'block> { }; let index_register = self.convert_ssa_register_value(*index, dfg); + self.validate_array_index(array_variable, index_register); self.retrieve_variable_from_array( array_pointer, index_register, @@ -582,6 +583,7 @@ impl<'block> BrilligBlock<'block> { result_ids[0], dfg, ); + self.validate_array_index(source_variable, index_register); self.convert_ssa_array_set( source_variable, @@ -690,6 +692,37 @@ impl<'block> BrilligBlock<'block> { .post_call_prep_returns_load_registers(&returned_registers, &saved_registers); } + fn validate_array_index( + &mut self, + array_variable: BrilligVariable, + index_register: RegisterIndex, + ) { + let (size_as_register, should_deallocate_size) = match array_variable { + BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { + (self.brillig_context.make_constant(size.into()), true) + } + BrilligVariable::BrilligVector(BrilligVector { size, .. }) => (size, false), + _ => unreachable!("ICE: validate array index on non-array"), + }; + + let condition = self.brillig_context.allocate_register(); + + self.brillig_context.memory_op( + index_register, + size_as_register, + condition, + BinaryIntOp::LessThan, + ); + + self.brillig_context + .constrain_instruction(condition, Some("Array index out of bounds".to_owned())); + + if should_deallocate_size { + self.brillig_context.deallocate_register(size_as_register); + } + self.brillig_context.deallocate_register(condition); + } + pub(crate) fn retrieve_variable_from_array( &mut self, array_pointer: RegisterIndex, diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index b36081d5e3e..a8563dc9efe 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -510,6 +510,15 @@ impl DebugShow { output ); } + BlackBoxOp::Sha256Compression { input, hash_values, output } => { + debug_println!( + self.enable_debug_trace, + " SHA256COMPRESSION {} {} -> {}", + input, + hash_values, + output + ); + } } } diff --git a/noir/compiler/noirc_evaluator/src/errors.rs b/noir/compiler/noirc_evaluator/src/errors.rs index b7e89c7b213..73b6e671bd5 100644 --- a/noir/compiler/noirc_evaluator/src/errors.rs +++ b/noir/compiler/noirc_evaluator/src/errors.rs @@ -70,7 +70,7 @@ impl From for FileDiagnostic { let message = warning.to_string(); let (secondary_message, call_stack) = match warning { InternalWarning::ReturnConstant { call_stack } => { - ("constant value".to_string(), call_stack) + ("This variable contains a value which is constrained to be a constant. Consider removing this value as additional return values increase proving/verification time".to_string(), call_stack) }, InternalWarning::VerifyProof { call_stack } => { ("verify_proof(...) aggregates data for the verifier, the actual verification will be done when the full proof is verified using nargo verify. nargo prove may generate an invalid proof if bad data is used as input to verify_proof".to_string(), call_stack) @@ -89,7 +89,7 @@ impl From for FileDiagnostic { #[derive(Debug, PartialEq, Eq, Clone, Error, Serialize, Deserialize)] pub enum InternalWarning { - #[error("Returning a constant value is not allowed")] + #[error("Return variable contains a constant value")] ReturnConstant { call_stack: CallStack }, #[error("Calling std::verify_proof(...) does not verify a proof")] VerifyProof { call_stack: CallStack }, diff --git a/noir/compiler/noirc_evaluator/src/ssa.rs b/noir/compiler/noirc_evaluator/src/ssa.rs index e2da5652faf..0e3076923e0 100644 --- a/noir/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/compiler/noirc_evaluator/src/ssa.rs @@ -63,7 +63,6 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::mem2reg, "After Mem2Reg:") .run_pass(Ssa::fold_constants, "After Constant Folding:") .run_pass(Ssa::dead_instruction_elimination, "After Dead Instruction Elimination:") - .run_pass(Ssa::bubble_up_constrains, "After Constraint Bubbling:") .finish(); let brillig = ssa.to_brillig(print_brillig_trace); diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 1ac5f3d8e49..da59d674213 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1872,7 +1872,7 @@ fn execute_brillig( // It may be finished, in-progress, failed, or may be waiting for results of a foreign call. // If it's finished then we can omit the opcode and just write in the return values. match vm_status { - VMStatus::Finished => Some((vm.get_registers().clone(), vm.get_memory().clone())), + VMStatus::Finished => Some((vm.get_registers().clone(), vm.get_memory().to_vec())), VMStatus::InProgress => unreachable!("Brillig VM has not completed execution"), VMStatus::Failure { .. } => { // TODO: Return an error stating that the brillig function failed. diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 1730a1f6a20..b86fc4eeb5f 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -281,6 +281,11 @@ impl GeneratedAcir { outputs, len: constant_inputs[0].to_u128() as u32, }, + BlackBoxFunc::Sha256Compression => BlackBoxFuncCall::Sha256Compression { + inputs: inputs[0].clone(), + hash_values: inputs[1].clone(), + outputs, + }, }; self.push_opcode(AcirOpcode::BlackBoxFuncCall(black_box_func_call)); @@ -617,6 +622,8 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // The permutation takes a fixed number of inputs, but the inputs length depends on the proving system implementation. BlackBoxFunc::Poseidon2Permutation => None, + // SHA256 compression requires 16 u32s as input message and 8 u32s for the hash state. + BlackBoxFunc::Sha256Compression => Some(24), // Can only apply a range constraint to one // witness at a time. BlackBoxFunc::RANGE => Some(1), @@ -667,6 +674,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // The permutation returns a fixed number of outputs, equals to the inputs length which depends on the proving system implementation. BlackBoxFunc::Poseidon2Permutation => None, + BlackBoxFunc::Sha256Compression => Some(8), // Pedersen commitment returns a point BlackBoxFunc::PedersenCommitment => Some(2), diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 457fe41de93..331a02a6974 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -1,6 +1,5 @@ use acvm::{acir::BlackBoxFunc, FieldElement}; use iter_extended::vecmap; -use num_bigint::BigUint; use super::{ basic_block::BasicBlockId, @@ -10,9 +9,15 @@ use super::{ value::{Value, ValueId}, }; +mod binary; mod call; +mod cast; +mod constrain; +pub(crate) use binary::{Binary, BinaryOp}; use call::simplify_call; +use cast::simplify_cast; +use constrain::decompose_constrain; /// Reference to an instruction /// @@ -82,6 +87,9 @@ impl Intrinsic { match self { Intrinsic::AssertConstant | Intrinsic::ApplyRangeConstraint => true, + // These apply a constraint that the input must fit into a specified number of limbs. + Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => true, + Intrinsic::Sort | Intrinsic::ArrayLen | Intrinsic::SlicePushBack @@ -91,8 +99,6 @@ impl Intrinsic { | Intrinsic::SliceInsert | Intrinsic::SliceRemove | Intrinsic::StrAsBytes - | Intrinsic::ToBits(_) - | Intrinsic::ToRadix(_) | Intrinsic::FromField | Intrinsic::AsField => false, @@ -545,179 +551,6 @@ impl Instruction { } } -/// Try to simplify this cast instruction. If the instruction can be simplified to a known value, -/// that value is returned. Otherwise None is returned. -fn simplify_cast(value: ValueId, dst_typ: &Type, dfg: &mut DataFlowGraph) -> SimplifyResult { - use SimplifyResult::*; - let value = dfg.resolve(value); - - if let Value::Instruction { instruction, .. } = &dfg[value] { - if let Instruction::Cast(original_value, _) = &dfg[*instruction] { - return SimplifiedToInstruction(Instruction::Cast(*original_value, dst_typ.clone())); - } - } - - if let Some(constant) = dfg.get_numeric_constant(value) { - let src_typ = dfg.type_of_value(value); - match (src_typ, dst_typ) { - (Type::Numeric(NumericType::NativeField), Type::Numeric(NumericType::NativeField)) => { - // Field -> Field: use src value - SimplifiedTo(value) - } - ( - Type::Numeric(NumericType::Unsigned { .. }), - Type::Numeric(NumericType::NativeField), - ) => { - // Unsigned -> Field: redefine same constant as Field - SimplifiedTo(dfg.make_constant(constant, dst_typ.clone())) - } - ( - Type::Numeric( - NumericType::NativeField - | NumericType::Unsigned { .. } - | NumericType::Signed { .. }, - ), - Type::Numeric(NumericType::Unsigned { bit_size }), - ) => { - // Field/Unsigned -> unsigned: truncate - let integer_modulus = BigUint::from(2u128).pow(*bit_size); - let constant: BigUint = BigUint::from_bytes_be(&constant.to_be_bytes()); - let truncated = constant % integer_modulus; - let truncated = FieldElement::from_be_bytes_reduce(&truncated.to_bytes_be()); - SimplifiedTo(dfg.make_constant(truncated, dst_typ.clone())) - } - _ => None, - } - } else if *dst_typ == dfg.type_of_value(value) { - SimplifiedTo(value) - } else { - None - } -} - -/// Try to decompose this constrain instruction. This constraint will be broken down such that it instead constrains -/// all the values which are used to compute the values which were being constrained. -fn decompose_constrain( - lhs: ValueId, - rhs: ValueId, - msg: Option, - dfg: &mut DataFlowGraph, -) -> Vec { - let lhs = dfg.resolve(lhs); - let rhs = dfg.resolve(rhs); - - if lhs == rhs { - // Remove trivial case `assert_eq(x, x)` - Vec::new() - } else { - match (&dfg[lhs], &dfg[rhs]) { - (Value::NumericConstant { constant, typ }, Value::Instruction { instruction, .. }) - | (Value::Instruction { instruction, .. }, Value::NumericConstant { constant, typ }) - if *typ == Type::bool() => - { - match dfg[*instruction] { - Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Eq }) - if constant.is_one() => - { - // Replace an explicit two step equality assertion - // - // v2 = eq v0, u32 v1 - // constrain v2 == u1 1 - // - // with a direct assertion of equality between the two values - // - // v2 = eq v0, u32 v1 - // constrain v0 == v1 - // - // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it - // will likely be removed through dead instruction elimination. - - vec![Instruction::Constrain(lhs, rhs, msg)] - } - - Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Mul }) - if constant.is_one() && dfg.type_of_value(lhs) == Type::bool() => - { - // Replace an equality assertion on a boolean multiplication - // - // v2 = mul v0, v1 - // constrain v2 == u1 1 - // - // with a direct assertion that each value is equal to 1 - // - // v2 = mul v0, v1 - // constrain v0 == 1 - // constrain v1 == 1 - // - // This is due to the fact that for `v2` to be 1 then both `v0` and `v1` are 1. - // - // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it - // will likely be removed through dead instruction elimination. - let one = FieldElement::one(); - let one = dfg.make_constant(one, Type::bool()); - - [ - decompose_constrain(lhs, one, msg.clone(), dfg), - decompose_constrain(rhs, one, msg, dfg), - ] - .concat() - } - - Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Or }) - if constant.is_zero() => - { - // Replace an equality assertion on an OR - // - // v2 = or v0, v1 - // constrain v2 == u1 0 - // - // with a direct assertion that each value is equal to 0 - // - // v2 = or v0, v1 - // constrain v0 == 0 - // constrain v1 == 0 - // - // This is due to the fact that for `v2` to be 0 then both `v0` and `v1` are 0. - // - // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it - // will likely be removed through dead instruction elimination. - let zero = FieldElement::zero(); - let zero = dfg.make_constant(zero, dfg.type_of_value(lhs)); - - [ - decompose_constrain(lhs, zero, msg.clone(), dfg), - decompose_constrain(rhs, zero, msg, dfg), - ] - .concat() - } - - Instruction::Not(value) => { - // Replace an assertion that a not instruction is truthy - // - // v1 = not v0 - // constrain v1 == u1 1 - // - // with an assertion that the not instruction input is falsy - // - // v1 = not v0 - // constrain v0 == u1 0 - // - // Note that this doesn't remove the value `v1` as it may be used in other instructions, but it - // will likely be removed through dead instruction elimination. - let reversed_constant = FieldElement::from(!constant.is_one()); - let reversed_constant = dfg.make_constant(reversed_constant, Type::bool()); - decompose_constrain(value, reversed_constant, msg, dfg) - } - - _ => vec![Instruction::Constrain(lhs, rhs, msg)], - } - } - - _ => vec![Instruction::Constrain(lhs, rhs, msg)], - } - } -} - /// The possible return values for Instruction::return_types pub(crate) enum InstructionResultType { /// The result type of this instruction matches that of this operand @@ -848,350 +681,6 @@ impl TerminatorInstruction { } } -/// A binary instruction in the IR. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub(crate) struct Binary { - /// Left hand side of the binary operation - pub(crate) lhs: ValueId, - /// Right hand side of the binary operation - pub(crate) rhs: ValueId, - /// The binary operation to apply - pub(crate) operator: BinaryOp, -} - -impl Binary { - /// The type of this Binary instruction's result - pub(crate) fn result_type(&self) -> InstructionResultType { - match self.operator { - BinaryOp::Eq | BinaryOp::Lt => InstructionResultType::Known(Type::bool()), - _ => InstructionResultType::Operand(self.lhs), - } - } - - /// Try to simplify this binary instruction, returning the new value if possible. - fn simplify(&self, dfg: &mut DataFlowGraph) -> SimplifyResult { - let lhs = dfg.get_numeric_constant(self.lhs); - let rhs = dfg.get_numeric_constant(self.rhs); - let operand_type = dfg.type_of_value(self.lhs); - - if let (Some(lhs), Some(rhs)) = (lhs, rhs) { - return match eval_constant_binary_op(lhs, rhs, self.operator, operand_type) { - Some((result, result_type)) => { - let value = dfg.make_constant(result, result_type); - SimplifyResult::SimplifiedTo(value) - } - None => SimplifyResult::None, - }; - } - - let lhs_is_zero = lhs.map_or(false, |lhs| lhs.is_zero()); - let rhs_is_zero = rhs.map_or(false, |rhs| rhs.is_zero()); - - let lhs_is_one = lhs.map_or(false, |lhs| lhs.is_one()); - let rhs_is_one = rhs.map_or(false, |rhs| rhs.is_one()); - - match self.operator { - BinaryOp::Add => { - if lhs_is_zero { - return SimplifyResult::SimplifiedTo(self.rhs); - } - if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); - } - } - BinaryOp::Sub => { - if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); - } - } - BinaryOp::Mul => { - if lhs_is_one { - return SimplifyResult::SimplifiedTo(self.rhs); - } - if rhs_is_one { - return SimplifyResult::SimplifiedTo(self.lhs); - } - if lhs_is_zero || rhs_is_zero { - let zero = dfg.make_constant(FieldElement::zero(), operand_type); - return SimplifyResult::SimplifiedTo(zero); - } - } - BinaryOp::Div => { - if rhs_is_one { - return SimplifyResult::SimplifiedTo(self.lhs); - } - } - BinaryOp::Mod => { - if rhs_is_one { - let zero = dfg.make_constant(FieldElement::zero(), operand_type); - return SimplifyResult::SimplifiedTo(zero); - } - } - BinaryOp::Eq => { - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - let one = dfg.make_constant(FieldElement::one(), Type::bool()); - return SimplifyResult::SimplifiedTo(one); - } - if operand_type == Type::bool() { - // Simplify forms of `(boolean == true)` into `boolean` - if lhs_is_one { - return SimplifyResult::SimplifiedTo(self.rhs); - } - if rhs_is_one { - return SimplifyResult::SimplifiedTo(self.lhs); - } - // Simplify forms of `(boolean == false)` into `!boolean` - if lhs_is_zero { - return SimplifyResult::SimplifiedToInstruction(Instruction::Not(self.rhs)); - } - if rhs_is_zero { - return SimplifyResult::SimplifiedToInstruction(Instruction::Not(self.lhs)); - } - } - } - BinaryOp::Lt => { - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); - return SimplifyResult::SimplifiedTo(zero); - } - if operand_type.is_unsigned() { - if rhs_is_zero { - // Unsigned values cannot be less than zero. - let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); - return SimplifyResult::SimplifiedTo(zero); - } else if rhs_is_one { - let zero = dfg.make_constant(FieldElement::zero(), operand_type); - return SimplifyResult::SimplifiedToInstruction(Instruction::binary( - BinaryOp::Eq, - self.lhs, - zero, - )); - } - } - } - BinaryOp::And => { - if lhs_is_zero || rhs_is_zero { - let zero = dfg.make_constant(FieldElement::zero(), operand_type); - return SimplifyResult::SimplifiedTo(zero); - } - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - return SimplifyResult::SimplifiedTo(self.lhs); - } - if operand_type == Type::bool() { - // Boolean AND is equivalent to multiplication, which is a cheaper operation. - let instruction = Instruction::binary(BinaryOp::Mul, self.lhs, self.rhs); - return SimplifyResult::SimplifiedToInstruction(instruction); - } - } - BinaryOp::Or => { - if lhs_is_zero { - return SimplifyResult::SimplifiedTo(self.rhs); - } - if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); - } - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - return SimplifyResult::SimplifiedTo(self.lhs); - } - } - BinaryOp::Xor => { - if lhs_is_zero { - return SimplifyResult::SimplifiedTo(self.rhs); - } - if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); - } - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); - return SimplifyResult::SimplifiedTo(zero); - } - } - } - SimplifyResult::None - } -} - -/// Evaluate a binary operation with constant arguments. -fn eval_constant_binary_op( - lhs: FieldElement, - rhs: FieldElement, - operator: BinaryOp, - mut operand_type: Type, -) -> Option<(FieldElement, Type)> { - let value = match &operand_type { - Type::Numeric(NumericType::NativeField) => { - // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. - // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, - // and the operation should be handled by ACIR generation. - if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == FieldElement::zero() { - return None; - } - operator.get_field_function()?(lhs, rhs) - } - Type::Numeric(NumericType::Unsigned { bit_size }) => { - let function = operator.get_u128_function(); - - let lhs = truncate(lhs.try_into_u128()?, *bit_size); - let rhs = truncate(rhs.try_into_u128()?, *bit_size); - - // The divisor is being truncated into the type of the operand, which can potentially - // lead to the rhs being zero. - // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. - // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, - // and the operation should be handled by ACIR generation. - if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == 0 { - return None; - } - let result = function(lhs, rhs)?; - // Check for overflow - if result >= 2u128.pow(*bit_size) { - return None; - } - result.into() - } - Type::Numeric(NumericType::Signed { bit_size }) => { - let function = operator.get_i128_function(); - - let lhs = truncate(lhs.try_into_u128()?, *bit_size); - let rhs = truncate(rhs.try_into_u128()?, *bit_size); - let l_pos = lhs < 2u128.pow(bit_size - 1); - let r_pos = rhs < 2u128.pow(bit_size - 1); - let lhs = if l_pos { lhs as i128 } else { -((2u128.pow(*bit_size) - lhs) as i128) }; - let rhs = if r_pos { rhs as i128 } else { -((2u128.pow(*bit_size) - rhs) as i128) }; - // The divisor is being truncated into the type of the operand, which can potentially - // lead to the rhs being zero. - // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. - // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, - // and the operation should be handled by ACIR generation. - if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == 0 { - return None; - } - - let result = function(lhs, rhs)?; - // Check for overflow - if result >= 2i128.pow(*bit_size - 1) || result < -(2i128.pow(*bit_size - 1)) { - return None; - } - let result = - if result >= 0 { result as u128 } else { (2i128.pow(*bit_size) + result) as u128 }; - result.into() - } - _ => return None, - }; - - if matches!(operator, BinaryOp::Eq | BinaryOp::Lt) { - operand_type = Type::bool(); - } - - Some((value, operand_type)) -} - -fn truncate(int: u128, bit_size: u32) -> u128 { - let max = 2u128.pow(bit_size); - int % max -} - -impl BinaryOp { - fn get_field_function(self) -> Option FieldElement> { - match self { - BinaryOp::Add => Some(std::ops::Add::add), - BinaryOp::Sub => Some(std::ops::Sub::sub), - BinaryOp::Mul => Some(std::ops::Mul::mul), - BinaryOp::Div => Some(std::ops::Div::div), - BinaryOp::Eq => Some(|x, y| (x == y).into()), - BinaryOp::Lt => Some(|x, y| (x < y).into()), - // Bitwise operators are unsupported for Fields - BinaryOp::Mod => None, - BinaryOp::And => None, - BinaryOp::Or => None, - BinaryOp::Xor => None, - } - } - - fn get_u128_function(self) -> fn(u128, u128) -> Option { - match self { - BinaryOp::Add => u128::checked_add, - BinaryOp::Sub => u128::checked_sub, - BinaryOp::Mul => u128::checked_mul, - BinaryOp::Div => u128::checked_div, - BinaryOp::Mod => u128::checked_rem, - BinaryOp::And => |x, y| Some(x & y), - BinaryOp::Or => |x, y| Some(x | y), - BinaryOp::Xor => |x, y| Some(x ^ y), - BinaryOp::Eq => |x, y| Some((x == y) as u128), - BinaryOp::Lt => |x, y| Some((x < y) as u128), - } - } - - fn get_i128_function(self) -> fn(i128, i128) -> Option { - match self { - BinaryOp::Add => i128::checked_add, - BinaryOp::Sub => i128::checked_sub, - BinaryOp::Mul => i128::checked_mul, - BinaryOp::Div => i128::checked_div, - BinaryOp::Mod => i128::checked_rem, - BinaryOp::And => |x, y| Some(x & y), - BinaryOp::Or => |x, y| Some(x | y), - BinaryOp::Xor => |x, y| Some(x ^ y), - BinaryOp::Eq => |x, y| Some((x == y) as i128), - BinaryOp::Lt => |x, y| Some((x < y) as i128), - } - } -} - -/// Binary Operations allowed in the IR. -/// Aside from the comparison operators (Eq and Lt), all operators -/// will return the same type as their operands. -/// The operand types must match for all binary operators. -/// All binary operators are also only for numeric types. To implement -/// e.g. equality for a compound type like a struct, one must add a -/// separate Eq operation for each field and combine them later with And. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] -pub(crate) enum BinaryOp { - /// Addition of lhs + rhs. - Add, - /// Subtraction of lhs - rhs. - Sub, - /// Multiplication of lhs * rhs. - Mul, - /// Division of lhs / rhs. - Div, - /// Modulus of lhs % rhs. - Mod, - /// Checks whether two types are equal. - /// Returns true if the types were equal and - /// false otherwise. - Eq, - /// Checks whether the lhs is less than the rhs. - /// All other comparison operators should be translated - /// to less than. For example (a > b) = (b < a) = !(a >= b) = !(b <= a). - /// The result will always be a u1. - Lt, - /// Bitwise and (&) - And, - /// Bitwise or (|) - Or, - /// Bitwise xor (^) - Xor, -} - -impl std::fmt::Display for BinaryOp { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - BinaryOp::Add => write!(f, "add"), - BinaryOp::Sub => write!(f, "sub"), - BinaryOp::Mul => write!(f, "mul"), - BinaryOp::Div => write!(f, "div"), - BinaryOp::Eq => write!(f, "eq"), - BinaryOp::Mod => write!(f, "mod"), - BinaryOp::Lt => write!(f, "lt"), - BinaryOp::And => write!(f, "and"), - BinaryOp::Or => write!(f, "or"), - BinaryOp::Xor => write!(f, "xor"), - } - } -} - /// Contains the result to Instruction::simplify, specifying how the instruction /// should be simplified. pub(crate) enum SimplifyResult { diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs new file mode 100644 index 00000000000..1cb32d94148 --- /dev/null +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs @@ -0,0 +1,349 @@ +use acvm::FieldElement; + +use super::{ + DataFlowGraph, Instruction, InstructionResultType, NumericType, SimplifyResult, Type, ValueId, +}; + +/// Binary Operations allowed in the IR. +/// Aside from the comparison operators (Eq and Lt), all operators +/// will return the same type as their operands. +/// The operand types must match for all binary operators. +/// All binary operators are also only for numeric types. To implement +/// e.g. equality for a compound type like a struct, one must add a +/// separate Eq operation for each field and combine them later with And. +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +pub(crate) enum BinaryOp { + /// Addition of lhs + rhs. + Add, + /// Subtraction of lhs - rhs. + Sub, + /// Multiplication of lhs * rhs. + Mul, + /// Division of lhs / rhs. + Div, + /// Modulus of lhs % rhs. + Mod, + /// Checks whether two types are equal. + /// Returns true if the types were equal and + /// false otherwise. + Eq, + /// Checks whether the lhs is less than the rhs. + /// All other comparison operators should be translated + /// to less than. For example (a > b) = (b < a) = !(a >= b) = !(b <= a). + /// The result will always be a u1. + Lt, + /// Bitwise and (&) + And, + /// Bitwise or (|) + Or, + /// Bitwise xor (^) + Xor, +} + +impl std::fmt::Display for BinaryOp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BinaryOp::Add => write!(f, "add"), + BinaryOp::Sub => write!(f, "sub"), + BinaryOp::Mul => write!(f, "mul"), + BinaryOp::Div => write!(f, "div"), + BinaryOp::Eq => write!(f, "eq"), + BinaryOp::Mod => write!(f, "mod"), + BinaryOp::Lt => write!(f, "lt"), + BinaryOp::And => write!(f, "and"), + BinaryOp::Or => write!(f, "or"), + BinaryOp::Xor => write!(f, "xor"), + } + } +} + +/// A binary instruction in the IR. +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub(crate) struct Binary { + /// Left hand side of the binary operation + pub(crate) lhs: ValueId, + /// Right hand side of the binary operation + pub(crate) rhs: ValueId, + /// The binary operation to apply + pub(crate) operator: BinaryOp, +} + +impl Binary { + /// The type of this Binary instruction's result + pub(crate) fn result_type(&self) -> InstructionResultType { + match self.operator { + BinaryOp::Eq | BinaryOp::Lt => InstructionResultType::Known(Type::bool()), + _ => InstructionResultType::Operand(self.lhs), + } + } + + /// Try to simplify this binary instruction, returning the new value if possible. + pub(super) fn simplify(&self, dfg: &mut DataFlowGraph) -> SimplifyResult { + let lhs = dfg.get_numeric_constant(self.lhs); + let rhs = dfg.get_numeric_constant(self.rhs); + let operand_type = dfg.type_of_value(self.lhs); + + if let (Some(lhs), Some(rhs)) = (lhs, rhs) { + return match eval_constant_binary_op(lhs, rhs, self.operator, operand_type) { + Some((result, result_type)) => { + let value = dfg.make_constant(result, result_type); + SimplifyResult::SimplifiedTo(value) + } + None => SimplifyResult::None, + }; + } + + let lhs_is_zero = lhs.map_or(false, |lhs| lhs.is_zero()); + let rhs_is_zero = rhs.map_or(false, |rhs| rhs.is_zero()); + + let lhs_is_one = lhs.map_or(false, |lhs| lhs.is_one()); + let rhs_is_one = rhs.map_or(false, |rhs| rhs.is_one()); + + match self.operator { + BinaryOp::Add => { + if lhs_is_zero { + return SimplifyResult::SimplifiedTo(self.rhs); + } + if rhs_is_zero { + return SimplifyResult::SimplifiedTo(self.lhs); + } + } + BinaryOp::Sub => { + if rhs_is_zero { + return SimplifyResult::SimplifiedTo(self.lhs); + } + } + BinaryOp::Mul => { + if lhs_is_one { + return SimplifyResult::SimplifiedTo(self.rhs); + } + if rhs_is_one { + return SimplifyResult::SimplifiedTo(self.lhs); + } + if lhs_is_zero || rhs_is_zero { + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedTo(zero); + } + } + BinaryOp::Div => { + if rhs_is_one { + return SimplifyResult::SimplifiedTo(self.lhs); + } + } + BinaryOp::Mod => { + if rhs_is_one { + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedTo(zero); + } + } + BinaryOp::Eq => { + if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + let one = dfg.make_constant(FieldElement::one(), Type::bool()); + return SimplifyResult::SimplifiedTo(one); + } + if operand_type == Type::bool() { + // Simplify forms of `(boolean == true)` into `boolean` + if lhs_is_one { + return SimplifyResult::SimplifiedTo(self.rhs); + } + if rhs_is_one { + return SimplifyResult::SimplifiedTo(self.lhs); + } + // Simplify forms of `(boolean == false)` into `!boolean` + if lhs_is_zero { + return SimplifyResult::SimplifiedToInstruction(Instruction::Not(self.rhs)); + } + if rhs_is_zero { + return SimplifyResult::SimplifiedToInstruction(Instruction::Not(self.lhs)); + } + } + } + BinaryOp::Lt => { + if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); + return SimplifyResult::SimplifiedTo(zero); + } + if operand_type.is_unsigned() { + if rhs_is_zero { + // Unsigned values cannot be less than zero. + let zero = dfg.make_constant(FieldElement::zero(), Type::bool()); + return SimplifyResult::SimplifiedTo(zero); + } else if rhs_is_one { + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedToInstruction(Instruction::binary( + BinaryOp::Eq, + self.lhs, + zero, + )); + } + } + } + BinaryOp::And => { + if lhs_is_zero || rhs_is_zero { + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedTo(zero); + } + if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + return SimplifyResult::SimplifiedTo(self.lhs); + } + if operand_type == Type::bool() { + // Boolean AND is equivalent to multiplication, which is a cheaper operation. + let instruction = Instruction::binary(BinaryOp::Mul, self.lhs, self.rhs); + return SimplifyResult::SimplifiedToInstruction(instruction); + } + } + BinaryOp::Or => { + if lhs_is_zero { + return SimplifyResult::SimplifiedTo(self.rhs); + } + if rhs_is_zero { + return SimplifyResult::SimplifiedTo(self.lhs); + } + if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + return SimplifyResult::SimplifiedTo(self.lhs); + } + } + BinaryOp::Xor => { + if lhs_is_zero { + return SimplifyResult::SimplifiedTo(self.rhs); + } + if rhs_is_zero { + return SimplifyResult::SimplifiedTo(self.lhs); + } + if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + let zero = dfg.make_constant(FieldElement::zero(), operand_type); + return SimplifyResult::SimplifiedTo(zero); + } + } + } + SimplifyResult::None + } +} + +/// Evaluate a binary operation with constant arguments. +fn eval_constant_binary_op( + lhs: FieldElement, + rhs: FieldElement, + operator: BinaryOp, + mut operand_type: Type, +) -> Option<(FieldElement, Type)> { + let value = match &operand_type { + Type::Numeric(NumericType::NativeField) => { + // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. + // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, + // and the operation should be handled by ACIR generation. + if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == FieldElement::zero() { + return None; + } + operator.get_field_function()?(lhs, rhs) + } + Type::Numeric(NumericType::Unsigned { bit_size }) => { + let function = operator.get_u128_function(); + + let lhs = truncate(lhs.try_into_u128()?, *bit_size); + let rhs = truncate(rhs.try_into_u128()?, *bit_size); + + // The divisor is being truncated into the type of the operand, which can potentially + // lead to the rhs being zero. + // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. + // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, + // and the operation should be handled by ACIR generation. + if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == 0 { + return None; + } + let result = function(lhs, rhs)?; + // Check for overflow + if result >= 2u128.pow(*bit_size) { + return None; + } + result.into() + } + Type::Numeric(NumericType::Signed { bit_size }) => { + let function = operator.get_i128_function(); + + let lhs = truncate(lhs.try_into_u128()?, *bit_size); + let rhs = truncate(rhs.try_into_u128()?, *bit_size); + let l_pos = lhs < 2u128.pow(bit_size - 1); + let r_pos = rhs < 2u128.pow(bit_size - 1); + let lhs = if l_pos { lhs as i128 } else { -((2u128.pow(*bit_size) - lhs) as i128) }; + let rhs = if r_pos { rhs as i128 } else { -((2u128.pow(*bit_size) - rhs) as i128) }; + // The divisor is being truncated into the type of the operand, which can potentially + // lead to the rhs being zero. + // If the rhs of a division is zero, attempting to evaluate the division will cause a compiler panic. + // Thus, we do not evaluate the division in this method, as we want to avoid triggering a panic, + // and the operation should be handled by ACIR generation. + if matches!(operator, BinaryOp::Div | BinaryOp::Mod) && rhs == 0 { + return None; + } + + let result = function(lhs, rhs)?; + // Check for overflow + if result >= 2i128.pow(*bit_size - 1) || result < -(2i128.pow(*bit_size - 1)) { + return None; + } + let result = + if result >= 0 { result as u128 } else { (2i128.pow(*bit_size) + result) as u128 }; + result.into() + } + _ => return None, + }; + + if matches!(operator, BinaryOp::Eq | BinaryOp::Lt) { + operand_type = Type::bool(); + } + + Some((value, operand_type)) +} + +fn truncate(int: u128, bit_size: u32) -> u128 { + let max = 2u128.pow(bit_size); + int % max +} + +impl BinaryOp { + fn get_field_function(self) -> Option FieldElement> { + match self { + BinaryOp::Add => Some(std::ops::Add::add), + BinaryOp::Sub => Some(std::ops::Sub::sub), + BinaryOp::Mul => Some(std::ops::Mul::mul), + BinaryOp::Div => Some(std::ops::Div::div), + BinaryOp::Eq => Some(|x, y| (x == y).into()), + BinaryOp::Lt => Some(|x, y| (x < y).into()), + // Bitwise operators are unsupported for Fields + BinaryOp::Mod => None, + BinaryOp::And => None, + BinaryOp::Or => None, + BinaryOp::Xor => None, + } + } + + fn get_u128_function(self) -> fn(u128, u128) -> Option { + match self { + BinaryOp::Add => u128::checked_add, + BinaryOp::Sub => u128::checked_sub, + BinaryOp::Mul => u128::checked_mul, + BinaryOp::Div => u128::checked_div, + BinaryOp::Mod => u128::checked_rem, + BinaryOp::And => |x, y| Some(x & y), + BinaryOp::Or => |x, y| Some(x | y), + BinaryOp::Xor => |x, y| Some(x ^ y), + BinaryOp::Eq => |x, y| Some((x == y) as u128), + BinaryOp::Lt => |x, y| Some((x < y) as u128), + } + } + + fn get_i128_function(self) -> fn(i128, i128) -> Option { + match self { + BinaryOp::Add => i128::checked_add, + BinaryOp::Sub => i128::checked_sub, + BinaryOp::Mul => i128::checked_mul, + BinaryOp::Div => i128::checked_div, + BinaryOp::Mod => i128::checked_rem, + BinaryOp::And => |x, y| Some(x & y), + BinaryOp::Or => |x, y| Some(x | y), + BinaryOp::Xor => |x, y| Some(x ^ y), + BinaryOp::Eq => |x, y| Some((x == y) as i128), + BinaryOp::Lt => |x, y| Some((x < y) as i128), + } + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index eab839d9569..0178ae9dba1 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -452,6 +452,7 @@ fn simplify_black_box_func( "ICE: `BlackBoxFunc::RANGE` calls should be transformed into a `Instruction::Cast`" ) } + BlackBoxFunc::Sha256Compression => SimplifyResult::None, //TODO(Guillaume) } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs new file mode 100644 index 00000000000..671820e801d --- /dev/null +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs @@ -0,0 +1,58 @@ +use acvm::FieldElement; +use num_bigint::BigUint; + +use super::{DataFlowGraph, Instruction, NumericType, SimplifyResult, Type, Value, ValueId}; + +/// Try to simplify this cast instruction. If the instruction can be simplified to a known value, +/// that value is returned. Otherwise None is returned. +pub(super) fn simplify_cast( + value: ValueId, + dst_typ: &Type, + dfg: &mut DataFlowGraph, +) -> SimplifyResult { + use SimplifyResult::*; + let value = dfg.resolve(value); + + if let Value::Instruction { instruction, .. } = &dfg[value] { + if let Instruction::Cast(original_value, _) = &dfg[*instruction] { + return SimplifiedToInstruction(Instruction::Cast(*original_value, dst_typ.clone())); + } + } + + if let Some(constant) = dfg.get_numeric_constant(value) { + let src_typ = dfg.type_of_value(value); + match (src_typ, dst_typ) { + (Type::Numeric(NumericType::NativeField), Type::Numeric(NumericType::NativeField)) => { + // Field -> Field: use src value + SimplifiedTo(value) + } + ( + Type::Numeric(NumericType::Unsigned { .. }), + Type::Numeric(NumericType::NativeField), + ) => { + // Unsigned -> Field: redefine same constant as Field + SimplifiedTo(dfg.make_constant(constant, dst_typ.clone())) + } + ( + Type::Numeric( + NumericType::NativeField + | NumericType::Unsigned { .. } + | NumericType::Signed { .. }, + ), + Type::Numeric(NumericType::Unsigned { bit_size }), + ) => { + // Field/Unsigned -> unsigned: truncate + let integer_modulus = BigUint::from(2u128).pow(*bit_size); + let constant: BigUint = BigUint::from_bytes_be(&constant.to_be_bytes()); + let truncated = constant % integer_modulus; + let truncated = FieldElement::from_be_bytes_reduce(&truncated.to_bytes_be()); + SimplifiedTo(dfg.make_constant(truncated, dst_typ.clone())) + } + _ => None, + } + } else if *dst_typ == dfg.type_of_value(value) { + SimplifiedTo(value) + } else { + None + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs new file mode 100644 index 00000000000..7fb0970c834 --- /dev/null +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs @@ -0,0 +1,126 @@ +use acvm::FieldElement; + +use super::{Binary, BinaryOp, DataFlowGraph, Instruction, Type, Value, ValueId}; + +/// Try to decompose this constrain instruction. This constraint will be broken down such that it instead constrains +/// all the values which are used to compute the values which were being constrained. +pub(super) fn decompose_constrain( + lhs: ValueId, + rhs: ValueId, + msg: Option, + dfg: &mut DataFlowGraph, +) -> Vec { + let lhs = dfg.resolve(lhs); + let rhs = dfg.resolve(rhs); + + if lhs == rhs { + // Remove trivial case `assert_eq(x, x)` + Vec::new() + } else { + match (&dfg[lhs], &dfg[rhs]) { + (Value::NumericConstant { constant, typ }, Value::Instruction { instruction, .. }) + | (Value::Instruction { instruction, .. }, Value::NumericConstant { constant, typ }) + if *typ == Type::bool() => + { + match dfg[*instruction] { + Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Eq }) + if constant.is_one() => + { + // Replace an explicit two step equality assertion + // + // v2 = eq v0, u32 v1 + // constrain v2 == u1 1 + // + // with a direct assertion of equality between the two values + // + // v2 = eq v0, u32 v1 + // constrain v0 == v1 + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + + vec![Instruction::Constrain(lhs, rhs, msg)] + } + + Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Mul }) + if constant.is_one() && dfg.type_of_value(lhs) == Type::bool() => + { + // Replace an equality assertion on a boolean multiplication + // + // v2 = mul v0, v1 + // constrain v2 == u1 1 + // + // with a direct assertion that each value is equal to 1 + // + // v2 = mul v0, v1 + // constrain v0 == 1 + // constrain v1 == 1 + // + // This is due to the fact that for `v2` to be 1 then both `v0` and `v1` are 1. + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let one = FieldElement::one(); + let one = dfg.make_constant(one, Type::bool()); + + [ + decompose_constrain(lhs, one, msg.clone(), dfg), + decompose_constrain(rhs, one, msg, dfg), + ] + .concat() + } + + Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Or }) + if constant.is_zero() => + { + // Replace an equality assertion on an OR + // + // v2 = or v0, v1 + // constrain v2 == u1 0 + // + // with a direct assertion that each value is equal to 0 + // + // v2 = or v0, v1 + // constrain v0 == 0 + // constrain v1 == 0 + // + // This is due to the fact that for `v2` to be 0 then both `v0` and `v1` are 0. + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let zero = FieldElement::zero(); + let zero = dfg.make_constant(zero, dfg.type_of_value(lhs)); + + [ + decompose_constrain(lhs, zero, msg.clone(), dfg), + decompose_constrain(rhs, zero, msg, dfg), + ] + .concat() + } + + Instruction::Not(value) => { + // Replace an assertion that a not instruction is truthy + // + // v1 = not v0 + // constrain v1 == u1 1 + // + // with an assertion that the not instruction input is falsy + // + // v1 = not v0 + // constrain v0 == u1 0 + // + // Note that this doesn't remove the value `v1` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let reversed_constant = FieldElement::from(!constant.is_one()); + let reversed_constant = dfg.make_constant(reversed_constant, Type::bool()); + decompose_constrain(value, reversed_constant, msg, dfg) + } + + _ => vec![Instruction::Constrain(lhs, rhs, msg)], + } + } + + _ => vec![Instruction::Constrain(lhs, rhs, msg)], + } + } +} diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 6bdf2ab1c0a..1059994b9be 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -144,9 +144,9 @@ use crate::ssa::{ dfg::{CallStack, InsertInstructionResult}, function::Function, function_inserter::FunctionInserter, - instruction::{BinaryOp, Instruction, InstructionId, TerminatorInstruction}, + instruction::{BinaryOp, Instruction, InstructionId, Intrinsic, TerminatorInstruction}, types::Type, - value::ValueId, + value::{Value, ValueId}, }, ssa_gen::Ssa, }; @@ -683,6 +683,28 @@ impl<'f> Context<'f> { ); Instruction::RangeCheck { value, max_bit_size, assert_message } } + Instruction::Call { func, mut arguments } => match self.inserter.function.dfg[func] + { + Value::Intrinsic(Intrinsic::ToBits(_) | Intrinsic::ToRadix(_)) => { + let field = arguments[0]; + let argument_type = self.inserter.function.dfg.type_of_value(field); + + let casted_condition = self.insert_instruction( + Instruction::Cast(condition, argument_type), + call_stack.clone(), + ); + let field = self.insert_instruction( + Instruction::binary(BinaryOp::Mul, field, casted_condition), + call_stack.clone(), + ); + + arguments[0] = field; + + Instruction::Call { func, arguments } + } + + _ => Instruction::Call { func, arguments }, + }, other => other, } } else { diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index eb35ba9a65b..9d9635fed34 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -96,6 +96,9 @@ pub(crate) fn generate_ssa(program: Program) -> Result { _ => unreachable!("ICE - expect return on the last block"), } } + // we save the data bus inside the dfg + function_context.builder.current_function.dfg.data_bus = + DataBus::get_data_bus(call_data, return_data); // Main has now been compiled and any other functions referenced within have been added to the // function queue as they were found in codegen_ident. This queueing will happen each time a @@ -106,9 +109,6 @@ pub(crate) fn generate_ssa(program: Program) -> Result { function_context.new_function(dest_id, function); function_context.codegen_function_body(&function.body)?; } - // we save the data bus inside the dfg - function_context.builder.current_function.dfg.data_bus = - DataBus::get_data_bus(call_data, return_data); Ok(function_context.builder.finish()) } diff --git a/noir/compiler/noirc_frontend/src/ast/function.rs b/noir/compiler/noirc_frontend/src/ast/function.rs index b8f385f52d3..f20fc54b101 100644 --- a/noir/compiler/noirc_frontend/src/ast/function.rs +++ b/noir/compiler/noirc_frontend/src/ast/function.rs @@ -72,7 +72,7 @@ impl NoirFunction { pub fn function_attribute(&self) -> Option<&FunctionAttribute> { self.def.attributes.function.as_ref() } - pub fn secondary_attributes(&self) -> &Vec { + pub fn secondary_attributes(&self) -> &[SecondaryAttribute] { self.def.attributes.secondary.as_ref() } pub fn def(&self) -> &FunctionDefinition { diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index c768ea96f8f..a6ab6b1d825 100644 --- a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -460,7 +460,7 @@ fn type_check_functions( #[allow(clippy::too_many_arguments)] pub(crate) fn check_methods_signatures( resolver: &mut Resolver, - impl_methods: &Vec<(FileId, FuncId)>, + impl_methods: &[(FileId, FuncId)], trait_id: TraitId, trait_name_span: Span, // These are the generics on the trait itself from the impl. diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 1d4f60ffd51..df533f6a4ae 100644 --- a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -449,7 +449,7 @@ impl<'a> Resolver<'a> { fn resolve_type_inner(&mut self, typ: UnresolvedType, new_variables: &mut Generics) -> Type { use UnresolvedTypeData::*; - match typ.typ { + let resolved_type = match typ.typ { FieldElement => Type::FieldElement, Array(size, elem) => { let elem = Box::new(self.resolve_type_inner(*elem, new_variables)); @@ -510,7 +510,18 @@ impl<'a> Resolver<'a> { Type::MutableReference(Box::new(self.resolve_type_inner(*element, new_variables))) } Parenthesized(typ) => self.resolve_type_inner(*typ, new_variables), + }; + + if let Type::Struct(_, _) = resolved_type { + if let Some(unresolved_span) = typ.span { + // Record the location of the type reference + self.interner.push_type_ref_location( + resolved_type.clone(), + Location::new(unresolved_span, self.file), + ); + } } + resolved_type } fn find_generic(&self, target_name: &str) -> Option<&(Rc, TypeVariable, Span)> { @@ -714,6 +725,7 @@ impl<'a> Resolver<'a> { if resolved_type.is_nested_slice() { self.errors.push(ResolverError::NestedSlices { span: span.unwrap() }); } + resolved_type } @@ -1438,6 +1450,8 @@ impl<'a> Resolver<'a> { HirExpression::MemberAccess(HirMemberAccess { lhs: self.resolve_expression(access.lhs), rhs: access.rhs, + // This is only used when lhs is a reference and we want to return a reference to rhs + is_offset: false, }) } ExpressionKind::Error => HirExpression::Error, @@ -1734,7 +1748,8 @@ impl<'a> Resolver<'a> { // This resolves a static trait method T::trait_method by iterating over the where clause // - // Returns the trait method, object type, and the trait generics. + // Returns the trait method, trait constraint, and whether the impl is assumed from a where + // clause. This is always true since this helper searches where clauses for a generic constraint. // E.g. `t.method()` with `where T: Foo` in scope will return `(Foo::method, T, vec![Bar])` fn resolve_trait_method_by_named_generic( &mut self, @@ -1777,7 +1792,7 @@ impl<'a> Resolver<'a> { // Try to resolve the given trait method path. // - // Returns the trait method, object type, and the trait generics. + // Returns the trait method, trait constraint, and whether the impl is assumed to exist by a where clause or not // E.g. `t.method()` with `where T: Foo` in scope will return `(Foo::method, T, vec![Bar])` fn resolve_trait_generic_path( &mut self, diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs b/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs index 58cf4e7b289..5885707a9b7 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -5,8 +5,8 @@ use crate::{ hir::{resolution::resolver::verify_mutable_reference, type_check::errors::Source}, hir_def::{ expr::{ - self, HirArrayLiteral, HirBinaryOp, HirExpression, HirLiteral, HirMethodCallExpression, - HirMethodReference, HirPrefixExpression, ImplKind, + self, HirArrayLiteral, HirBinaryOp, HirExpression, HirIdent, HirLiteral, + HirMethodCallExpression, HirMethodReference, HirPrefixExpression, ImplKind, }, types::Type, }, @@ -46,50 +46,7 @@ impl<'interner> TypeChecker<'interner> { /// function `foo` to refer to. pub(crate) fn check_expression(&mut self, expr_id: &ExprId) -> Type { let typ = match self.interner.expression(expr_id) { - HirExpression::Ident(ident) => { - // An identifiers type may be forall-quantified in the case of generic functions. - // E.g. `fn foo(t: T, field: Field) -> T` has type `forall T. fn(T, Field) -> T`. - // We must instantiate identifiers at every call site to replace this T with a new type - // variable to handle generic functions. - let t = self.interner.id_type_substitute_trait_as_type(ident.id); - - // This instantiate's a trait's generics as well which need to be set - // when the constraint below is later solved for when the function is - // finished. How to link the two? - let (typ, bindings) = t.instantiate(self.interner); - - // Push any trait constraints required by this definition to the context - // to be checked later when the type of this variable is further constrained. - if let Some(definition) = self.interner.try_definition(ident.id) { - if let DefinitionKind::Function(function) = definition.kind { - let function = self.interner.function_meta(&function); - - for mut constraint in function.trait_constraints.clone() { - constraint.apply_bindings(&bindings); - self.trait_constraints.push((constraint, *expr_id)); - } - } - } - - if let ImplKind::TraitMethod(_, mut constraint, assumed) = ident.impl_kind { - constraint.apply_bindings(&bindings); - if assumed { - let trait_impl = TraitImplKind::Assumed { - object_type: constraint.typ, - trait_generics: constraint.trait_generics, - }; - self.interner.select_impl_for_expression(*expr_id, trait_impl); - } else { - // Currently only one impl can be selected per expr_id, so this - // constraint needs to be pushed after any other constraints so - // that monomorphization can resolve this trait method to the correct impl. - self.trait_constraints.push((constraint, *expr_id)); - } - } - - self.interner.store_instantiation_bindings(*expr_id, bindings); - typ - } + HirExpression::Ident(ident) => self.check_ident(ident, expr_id), HirExpression::Literal(literal) => { match literal { HirLiteral::Array(HirArrayLiteral::Standard(arr)) => { @@ -194,74 +151,42 @@ impl<'interner> TypeChecker<'interner> { self.bind_function_type(function, args, span) } HirExpression::MethodCall(mut method_call) => { - let object_type = self.check_expression(&method_call.object).follow_bindings(); + let mut object_type = self.check_expression(&method_call.object).follow_bindings(); let method_name = method_call.method.0.contents.as_str(); match self.lookup_method(&object_type, method_name, expr_id) { Some(method_ref) => { - let mut args = vec![( - object_type.clone(), - method_call.object, - self.interner.expr_span(&method_call.object), - )]; - - for arg in &method_call.arguments { - let typ = self.check_expression(arg); - args.push((typ, *arg, self.interner.expr_span(arg))); - } - // Desugar the method call into a normal, resolved function call // so that the backend doesn't need to worry about methods let location = method_call.location; - let trait_id = match &method_ref { - HirMethodReference::FuncId(func_id) => { - // Automatically add `&mut` if the method expects a mutable reference and - // the object is not already one. - if *func_id != FuncId::dummy_id() { - let function_type = - self.interner.function_meta(func_id).typ.clone(); - self.try_add_mutable_reference_to_object( - &mut method_call, - &function_type, - &mut args, - ); - } - - let meta = self.interner.function_meta(func_id); - meta.trait_impl.map(|impl_id| { - self.interner - .get_trait_implementation(impl_id) - .borrow() - .trait_id - }) + // Automatically add `&mut` if the method expects a mutable reference and + // the object is not already one. + if let HirMethodReference::FuncId(func_id) = &method_ref { + if *func_id != FuncId::dummy_id() { + let function_type = + self.interner.function_meta(func_id).typ.clone(); + + self.try_add_mutable_reference_to_object( + &mut method_call, + &function_type, + &mut object_type, + ); } - HirMethodReference::TraitMethodId(method, _) => Some(method.trait_id), - }; + } - let (function_id, function_call) = method_call.into_function_call( + // TODO: update object_type here? + let function_call = method_call.into_function_call( &method_ref, - object_type.clone(), + object_type, location, self.interner, ); - let span = self.interner.expr_span(expr_id); - let ret = self.check_method_call(&function_id, method_ref, args, span); - - if let Some(trait_id) = trait_id { - // Assume no trait generics were specified - // TODO: Fill in type variables - self.verify_trait_constraint( - &object_type, - trait_id, - &[], - function_id, - span, - ); - } - self.interner.replace_expr(expr_id, function_call); - ret + + // Type check the new call now that it has been changed from a method call + // to a function call. This way we avoid duplicating code. + self.check_expression(expr_id) } None => Type::Error, } @@ -341,6 +266,67 @@ impl<'interner> TypeChecker<'interner> { typ } + /// Returns the type of the given identifier + fn check_ident(&mut self, ident: HirIdent, expr_id: &ExprId) -> Type { + let mut bindings = TypeBindings::new(); + + // Add type bindings from any constraints that were used. + // We need to do this first since otherwise instantiating the type below + // will replace each trait generic with a fresh type variable, rather than + // the type used in the trait constraint (if it exists). See #4088. + if let ImplKind::TraitMethod(_, constraint, _) = &ident.impl_kind { + let the_trait = self.interner.get_trait(constraint.trait_id); + assert_eq!(the_trait.generics.len(), constraint.trait_generics.len()); + + for (param, arg) in the_trait.generics.iter().zip(&constraint.trait_generics) { + bindings.insert(param.id(), (param.clone(), arg.clone())); + } + } + + // An identifiers type may be forall-quantified in the case of generic functions. + // E.g. `fn foo(t: T, field: Field) -> T` has type `forall T. fn(T, Field) -> T`. + // We must instantiate identifiers at every call site to replace this T with a new type + // variable to handle generic functions. + let t = self.interner.id_type_substitute_trait_as_type(ident.id); + + // This instantiates a trait's generics as well which need to be set + // when the constraint below is later solved for when the function is + // finished. How to link the two? + let (typ, bindings) = t.instantiate_with_bindings(bindings, self.interner); + + // Push any trait constraints required by this definition to the context + // to be checked later when the type of this variable is further constrained. + if let Some(definition) = self.interner.try_definition(ident.id) { + if let DefinitionKind::Function(function) = definition.kind { + let function = self.interner.function_meta(&function); + + for mut constraint in function.trait_constraints.clone() { + constraint.apply_bindings(&bindings); + self.trait_constraints.push((constraint, *expr_id)); + } + } + } + + if let ImplKind::TraitMethod(_, mut constraint, assumed) = ident.impl_kind { + constraint.apply_bindings(&bindings); + if assumed { + let trait_impl = TraitImplKind::Assumed { + object_type: constraint.typ, + trait_generics: constraint.trait_generics, + }; + self.interner.select_impl_for_expression(*expr_id, trait_impl); + } else { + // Currently only one impl can be selected per expr_id, so this + // constraint needs to be pushed after any other constraints so + // that monomorphization can resolve this trait method to the correct impl. + self.trait_constraints.push((constraint, *expr_id)); + } + } + + self.interner.store_instantiation_bindings(*expr_id, bindings); + typ + } + pub fn verify_trait_constraint( &mut self, object_type: &Type, @@ -390,7 +376,7 @@ impl<'interner> TypeChecker<'interner> { &mut self, method_call: &mut HirMethodCallExpression, function_type: &Type, - argument_types: &mut [(Type, ExprId, noirc_errors::Span)], + object_type: &mut Type, ) { let expected_object_type = match function_type { Type::Function(args, _, _) => args.first(), @@ -402,7 +388,7 @@ impl<'interner> TypeChecker<'interner> { }; if let Some(expected_object_type) = expected_object_type { - let actual_type = argument_types[0].0.follow_bindings(); + let actual_type = object_type.follow_bindings(); if matches!(expected_object_type.follow_bindings(), Type::MutableReference(_)) { if !matches!(actual_type, Type::MutableReference(_)) { @@ -412,34 +398,33 @@ impl<'interner> TypeChecker<'interner> { } let new_type = Type::MutableReference(Box::new(actual_type)); - argument_types[0].0 = new_type.clone(); + *object_type = new_type.clone(); // First try to remove a dereference operator that may have been implicitly // inserted by a field access expression `foo.bar` on a mutable reference `foo`. - if self.try_remove_implicit_dereference(method_call.object).is_none() { - // If that didn't work, then wrap the whole expression in an `&mut` + let new_object = self.try_remove_implicit_dereference(method_call.object); + + // If that didn't work, then wrap the whole expression in an `&mut` + method_call.object = new_object.unwrap_or_else(|| { let location = self.interner.id_location(method_call.object); - method_call.object = + let new_object = self.interner.push_expr(HirExpression::Prefix(HirPrefixExpression { operator: UnaryOp::MutableReference, rhs: method_call.object, })); - self.interner.push_expr_type(&method_call.object, new_type); - self.interner.push_expr_location( - method_call.object, - location.span, - location.file, - ); - } + self.interner.push_expr_type(&new_object, new_type); + self.interner.push_expr_location(new_object, location.span, location.file); + new_object + }); } // Otherwise if the object type is a mutable reference and the method is not, insert as // many dereferences as needed. } else if matches!(actual_type, Type::MutableReference(_)) { let (object, new_type) = self.insert_auto_dereferences(method_call.object, actual_type); + *object_type = new_type; method_call.object = object; - argument_types[0].0 = new_type; } } } @@ -467,29 +452,22 @@ impl<'interner> TypeChecker<'interner> { /// Given a method object: `(*foo).bar` of a method call `(*foo).bar.baz()`, remove the /// implicitly added dereference operator if one is found. /// - /// Returns Some(()) if a dereference was removed and None otherwise. - fn try_remove_implicit_dereference(&mut self, object: ExprId) -> Option<()> { + /// Returns Some(new_expr_id) if a dereference was removed and None otherwise. + fn try_remove_implicit_dereference(&mut self, object: ExprId) -> Option { match self.interner.expression(&object) { - HirExpression::MemberAccess(access) => { - self.try_remove_implicit_dereference(access.lhs)?; - - // Since we removed a dereference, instead of returning the field directly, - // we expect to be returning a reference to the field, so update the type accordingly. - let current_type = self.interner.id_type(object); - let reference_type = Type::MutableReference(Box::new(current_type)); - self.interner.push_expr_type(&object, reference_type); - Some(()) + HirExpression::MemberAccess(mut access) => { + let new_lhs = self.try_remove_implicit_dereference(access.lhs)?; + access.lhs = new_lhs; + access.is_offset = true; + + // `object` will have a different type now, which will be filled in + // later when type checking the method call as a function call. + self.interner.replace_expr(&object, HirExpression::MemberAccess(access)); + Some(object) } HirExpression::Prefix(prefix) => match prefix.operator { - UnaryOp::Dereference { implicitly_added: true } => { - // Found a dereference we can remove. Now just replace it with its rhs to remove it. - let rhs = self.interner.expression(&prefix.rhs); - self.interner.replace_expr(&object, rhs); - - let rhs_type = self.interner.id_type(prefix.rhs); - self.interner.push_expr_type(&object, rhs_type); - Some(()) - } + // Found a dereference we can remove. Now just replace it with its rhs to remove it. + UnaryOp::Dereference { implicitly_added: true } => Some(prefix.rhs), _ => None, }, _ => None, @@ -566,60 +544,6 @@ impl<'interner> TypeChecker<'interner> { } } - // We need a special function to type check method calls since the method - // is not a Expression::Ident it must be manually instantiated here - fn check_method_call( - &mut self, - function_ident_id: &ExprId, - method_ref: HirMethodReference, - arguments: Vec<(Type, ExprId, Span)>, - span: Span, - ) -> Type { - let (fn_typ, param_len, generic_bindings) = match method_ref { - HirMethodReference::FuncId(func_id) => { - if func_id == FuncId::dummy_id() { - return Type::Error; - } - - let func_meta = self.interner.function_meta(&func_id); - let param_len = func_meta.parameters.len(); - (func_meta.typ.clone(), param_len, TypeBindings::new()) - } - HirMethodReference::TraitMethodId(method, generics) => { - let the_trait = self.interner.get_trait(method.trait_id); - let method = &the_trait.methods[method.method_index]; - - // These are any bindings from the trait's generics itself, - // rather than an impl or method's generics. - let generic_bindings = the_trait - .generics - .iter() - .zip(generics) - .map(|(var, arg)| (var.id(), (var.clone(), arg))) - .collect(); - - (method.typ.clone(), method.arguments().len(), generic_bindings) - } - }; - - let arg_len = arguments.len(); - - if param_len != arg_len { - self.errors.push(TypeCheckError::ArityMisMatch { - expected: param_len as u16, - found: arg_len as u16, - span, - }); - } - - let (function_type, instantiation_bindings) = - fn_typ.instantiate_with_bindings(generic_bindings, self.interner); - - self.interner.store_instantiation_bindings(*function_ident_id, instantiation_bindings); - self.interner.push_expr_type(function_ident_id, function_type.clone()); - self.bind_function_type(function_type.clone(), arguments, span) - } - fn check_if_expr(&mut self, if_expr: &expr::HirIfExpression, expr_id: &ExprId) -> Type { let cond_type = self.check_expression(&if_expr.condition); let then_type = self.check_expression(&if_expr.consequence); @@ -718,6 +642,9 @@ impl<'interner> TypeChecker<'interner> { this.interner.push_expr_location(*access_lhs, span, old_location.file); }; + // If this access is just a field offset, we want to avoid dereferencing + let dereference_lhs = (!access.is_offset).then_some(dereference_lhs); + match self.check_field_access(&lhs_type, &access.rhs.0.contents, span, dereference_lhs) { Some((element_type, index)) => { self.interner.set_field_index(expr_id, index); @@ -742,12 +669,16 @@ impl<'interner> TypeChecker<'interner> { /// expression. The second parameter of this function represents the lhs_type (which should /// always be a Type::MutableReference if `dereference_lhs` is called) and the third /// represents the element type. + /// + /// If `dereference_lhs` is None, this will assume we're taking the offset of a struct field + /// rather than dereferencing it. So the result of `foo.bar` with a `foo : &mut Foo` will + /// be a `&mut Bar` rather than just a `Bar`. pub(super) fn check_field_access( &mut self, lhs_type: &Type, field_name: &str, span: Span, - mut dereference_lhs: impl FnMut(&mut Self, Type, Type), + dereference_lhs: Option, ) -> Option<(Type, usize)> { let lhs_type = lhs_type.follow_bindings(); @@ -777,8 +708,19 @@ impl<'interner> TypeChecker<'interner> { // If the lhs is a mutable reference we automatically transform // lhs.field into (*lhs).field Type::MutableReference(element) => { - dereference_lhs(self, lhs_type.clone(), element.as_ref().clone()); - return self.check_field_access(element, field_name, span, dereference_lhs); + if let Some(mut dereference_lhs) = dereference_lhs { + dereference_lhs(self, lhs_type.clone(), element.as_ref().clone()); + return self.check_field_access( + element, + field_name, + span, + Some(dereference_lhs), + ); + } else { + let (element, index) = + self.check_field_access(element, field_name, span, dereference_lhs)?; + return Some((Type::MutableReference(Box::new(element)), index)); + } } _ => (), } @@ -1010,9 +952,9 @@ impl<'interner> TypeChecker<'interner> { fn bind_function_type_impl( &mut self, - fn_params: &Vec, + fn_params: &[Type], fn_ret: &Type, - callsite_args: &Vec<(Type, ExprId, Span)>, + callsite_args: &[(Type, ExprId, Span)], span: Span, ) -> Type { if fn_params.len() != callsite_args.len() { diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs index c4e72f48c50..fd8ae62d34e 100644 --- a/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs +++ b/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs @@ -206,24 +206,22 @@ impl<'interner> TypeChecker<'interner> { let object_ref = &mut object; let mutable_ref = &mut mutable; + let dereference_lhs = move |_: &mut Self, _, element_type| { + // We must create a temporary value first to move out of object_ref before + // we eventually reassign to it. + let id = DefinitionId::dummy_id(); + let location = Location::new(span, fm::FileId::dummy()); + let ident = HirIdent::non_trait_method(id, location); + let tmp_value = HirLValue::Ident(ident, Type::Error); + + let lvalue = std::mem::replace(object_ref, Box::new(tmp_value)); + *object_ref = Box::new(HirLValue::Dereference { lvalue, element_type }); + *mutable_ref = true; + }; + + let name = &field_name.0.contents; let (object_type, field_index) = self - .check_field_access( - &lhs_type, - &field_name.0.contents, - span, - move |_, _, element_type| { - // We must create a temporary value first to move out of object_ref before - // we eventually reassign to it. - let id = DefinitionId::dummy_id(); - let location = Location::new(span, fm::FileId::dummy()); - let ident = HirIdent::non_trait_method(id, location); - let tmp_value = HirLValue::Ident(ident, Type::Error); - - let lvalue = std::mem::replace(object_ref, Box::new(tmp_value)); - *object_ref = Box::new(HirLValue::Dereference { lvalue, element_type }); - *mutable_ref = true; - }, - ) + .check_field_access(&lhs_type, name, span, Some(dereference_lhs)) .unwrap_or((Type::Error, 0)); let field_index = Some(field_index); @@ -325,6 +323,7 @@ impl<'interner> TypeChecker<'interner> { // Now check if LHS is the same type as the RHS // Importantly, we do not coerce any types implicitly let expr_span = self.interner.expr_span(&rhs_expr); + self.unify_with_coercions(&expr_type, &annotated_type, rhs_expr, || { TypeCheckError::TypeMismatch { expected_typ: annotated_type.to_string(), @@ -335,10 +334,8 @@ impl<'interner> TypeChecker<'interner> { if annotated_type.is_unsigned() { self.lint_overflowing_uint(&rhs_expr, &annotated_type); } - annotated_type - } else { - expr_type } + expr_type } /// Check if an assignment is overflowing with respect to `annotated_type` diff --git a/noir/compiler/noirc_frontend/src/hir_def/expr.rs b/noir/compiler/noirc_frontend/src/hir_def/expr.rs index fe1cd78b5ed..75ed68af0f6 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/expr.rs @@ -152,6 +152,12 @@ pub struct HirMemberAccess { // This field is not an IdentId since the rhs of a field // access has no corresponding definition pub rhs: Ident, + + /// True if we should return an offset of the field rather than the field itself. + /// For most cases this is false, corresponding to `foo.bar` in source code. + /// This is true when calling methods or when we have an lvalue we want to preserve such + /// that if `foo : &mut Foo` has a field `bar : Bar`, we can return an `&mut Bar`. + pub is_offset: bool, } #[derive(Debug, Clone)] @@ -201,13 +207,14 @@ pub enum HirMethodReference { } impl HirMethodCallExpression { + /// Converts a method call into a function call pub fn into_function_call( mut self, method: &HirMethodReference, object_type: Type, location: Location, interner: &mut NodeInterner, - ) -> (ExprId, HirExpression) { + ) -> HirExpression { let mut arguments = vec![self.object]; arguments.append(&mut self.arguments); @@ -225,9 +232,10 @@ impl HirMethodCallExpression { (id, ImplKind::TraitMethod(*method_id, constraint, false)) } }; - let expr = HirExpression::Ident(HirIdent { location, id, impl_kind }); - let func = interner.push_expr(expr); - (func, HirExpression::Call(HirCallExpression { func, arguments, location })) + let func = HirExpression::Ident(HirIdent { location, id, impl_kind }); + let func = interner.push_expr(func); + interner.push_expr_location(func, location.span, location.file); + HirExpression::Call(HirCallExpression { func, arguments, location }) } } diff --git a/noir/compiler/noirc_frontend/src/hir_def/types.rs b/noir/compiler/noirc_frontend/src/hir_def/types.rs index 8979d60c005..0ba4cb2da65 100644 --- a/noir/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/compiler/noirc_frontend/src/hir_def/types.rs @@ -17,7 +17,7 @@ use crate::{node_interner::StructId, Ident, Signedness}; use super::expr::{HirCallExpression, HirExpression, HirIdent}; -#[derive(Debug, PartialEq, Eq, Clone, Hash)] +#[derive(PartialEq, Eq, Clone, Hash)] pub enum Type { /// A primitive Field type FieldElement, @@ -64,7 +64,7 @@ pub enum Type { TypeVariable(TypeVariable, TypeVariableKind), /// `impl Trait` when used in a type position. - /// These are only matched based on the TraitId. The trait name paramer is only + /// These are only matched based on the TraitId. The trait name parameter is only /// used for displaying error messages using the name of the trait. TraitAsType(TraitId, /*name:*/ Rc, /*generics:*/ Vec), @@ -190,7 +190,7 @@ pub type TypeBindings = HashMap; /// Represents a struct type in the type system. Each instance of this /// rust struct will be shared across all Type::Struct variants that represent /// the same struct type. -#[derive(Debug, Eq)] +#[derive(Eq)] pub struct StructType { /// A unique id representing this struct type. Used to check if two /// struct types are equal. @@ -449,7 +449,7 @@ pub enum TypeVariableKind { /// A TypeVariable is a mutable reference that is either /// bound to some type, or unbound with a given TypeVariableId. -#[derive(Debug, PartialEq, Eq, Clone, Hash)] +#[derive(PartialEq, Eq, Clone, Hash)] pub struct TypeVariable(TypeVariableId, Shared); impl TypeVariable { @@ -516,7 +516,7 @@ impl TypeVariable { /// TypeBindings are the mutable insides of a TypeVariable. /// They are either bound to some type, or are unbound. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash)] pub enum TypeBinding { Bound(Type), Unbound(TypeVariableId), @@ -529,7 +529,7 @@ impl TypeBinding { } /// A unique ID used to differentiate different type variables -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct TypeVariableId(pub usize); impl Type { @@ -804,7 +804,7 @@ impl std::fmt::Display for Type { Type::Function(args, ret, env) => { let closure_env_text = match **env { Type::Unit => "".to_string(), - _ => format!(" with closure environment {env}"), + _ => format!(" with env {env}"), }; let args = vecmap(args.iter(), ToString::to_string); @@ -1661,3 +1661,101 @@ impl From<&Type> for PrintableType { } } } + +impl std::fmt::Debug for Type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Type::FieldElement => { + write!(f, "Field") + } + Type::Array(len, typ) => { + if matches!(len.follow_bindings(), Type::NotConstant) { + write!(f, "[{typ:?}]") + } else { + write!(f, "[{typ:?}; {len:?}]") + } + } + Type::Integer(sign, num_bits) => match sign { + Signedness::Signed => write!(f, "i{num_bits}"), + Signedness::Unsigned => write!(f, "u{num_bits}"), + }, + Type::TypeVariable(var, TypeVariableKind::Normal) => write!(f, "{:?}", var), + Type::TypeVariable(binding, TypeVariableKind::IntegerOrField) => { + write!(f, "IntOrField{:?}", binding) + } + Type::TypeVariable(binding, TypeVariableKind::Constant(n)) => { + write!(f, "{}{:?}", n, binding) + } + Type::Struct(s, args) => { + let args = vecmap(args, |arg| format!("{:?}", arg)); + if args.is_empty() { + write!(f, "{:?}", s.borrow()) + } else { + write!(f, "{:?}<{}>", s.borrow(), args.join(", ")) + } + } + Type::TraitAsType(_id, name, generics) => { + write!(f, "impl {}", name)?; + if !generics.is_empty() { + let generics = vecmap(generics, |arg| format!("{:?}", arg)).join(", "); + write!(f, "<{generics}>")?; + } + Ok(()) + } + Type::Tuple(elements) => { + let elements = vecmap(elements, |arg| format!("{:?}", arg)); + write!(f, "({})", elements.join(", ")) + } + Type::Bool => write!(f, "bool"), + Type::String(len) => write!(f, "str<{len:?}>"), + Type::FmtString(len, elements) => { + write!(f, "fmtstr<{len:?}, {elements:?}>") + } + Type::Unit => write!(f, "()"), + Type::Error => write!(f, "error"), + Type::NamedGeneric(binding, name) => write!(f, "{}{:?}", name, binding), + Type::Constant(x) => x.fmt(f), + Type::Forall(typevars, typ) => { + let typevars = vecmap(typevars, |var| format!("{:?}", var)); + write!(f, "forall {}. {:?}", typevars.join(" "), typ) + } + Type::Function(args, ret, env) => { + let closure_env_text = match **env { + Type::Unit => "".to_string(), + _ => format!(" with env {env:?}"), + }; + + let args = vecmap(args.iter(), |arg| format!("{:?}", arg)); + + write!(f, "fn({}) -> {ret:?}{closure_env_text}", args.join(", ")) + } + Type::MutableReference(element) => { + write!(f, "&mut {element:?}") + } + Type::NotConstant => write!(f, "NotConstant"), + } + } +} + +impl std::fmt::Debug for TypeVariableId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "'{}", self.0) + } +} + +impl std::fmt::Debug for TypeVariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.id())?; + + if let TypeBinding::Bound(typ) = &*self.borrow() { + write!(f, " -> {typ:?}")?; + } + Ok(()) + } +} + +impl std::fmt::Debug for StructType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} diff --git a/noir/compiler/noirc_frontend/src/monomorphization/printer.rs b/noir/compiler/noirc_frontend/src/monomorphization/printer.rs index e79330de6f8..7aec2193494 100644 --- a/noir/compiler/noirc_frontend/src/monomorphization/printer.rs +++ b/noir/compiler/noirc_frontend/src/monomorphization/printer.rs @@ -30,7 +30,9 @@ impl AstPrinter { pub fn print_expr(&mut self, expr: &Expression, f: &mut Formatter) -> std::fmt::Result { match expr { - Expression::Ident(ident) => write!(f, "{}${}", ident.name, ident.definition), + Expression::Ident(ident) => { + write!(f, "{}${}", ident.name, ident.definition) + } Expression::Literal(literal) => self.print_literal(literal, f), Expression::Block(exprs) => self.print_block(exprs, f), Expression::Unary(unary) => self.print_unary(unary, f), diff --git a/noir/compiler/noirc_frontend/src/node_interner.rs b/noir/compiler/noirc_frontend/src/node_interner.rs index e734161e360..b856b54f6ca 100644 --- a/noir/compiler/noirc_frontend/src/node_interner.rs +++ b/noir/compiler/noirc_frontend/src/node_interner.rs @@ -146,6 +146,9 @@ pub struct NodeInterner { /// A list of all type aliases that are referenced in the program. /// Searched by LSP to resolve [Location]s of [TypeAliasType]s pub(crate) type_alias_ref: Vec<(TypeAliasId, Location)>, + + /// Stores the [Location] of a [Type] reference + pub(crate) type_ref_locations: Vec<(Type, Location)>, } /// A trait implementation is either a normal implementation that is present in the source @@ -455,6 +458,7 @@ impl Default for NodeInterner { struct_methods: HashMap::new(), primitive_methods: HashMap::new(), type_alias_ref: Vec::new(), + type_ref_locations: Vec::new(), }; // An empty block expression is used often, we add this into the `node` on startup @@ -607,6 +611,11 @@ impl NodeInterner { self.id_to_type.insert(definition_id.into(), typ); } + /// Store [Location] of [Type] reference + pub fn push_type_ref_location(&mut self, typ: Type, location: Location) { + self.type_ref_locations.push((typ, location)); + } + pub fn push_global(&mut self, stmt_id: StmtId, ident: Ident, local_id: LocalModuleId) { self.globals.insert(stmt_id, GlobalInfo { ident, local_id }); } @@ -1186,7 +1195,6 @@ impl NodeInterner { } /// Adds a trait implementation to the list of known implementations. - #[tracing::instrument(skip(self))] pub fn add_trait_implementation( &mut self, object_type: Type, diff --git a/noir/compiler/noirc_frontend/src/parser/parser.rs b/noir/compiler/noirc_frontend/src/parser/parser.rs index cdfdc570949..f82ce95c718 100644 --- a/noir/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/compiler/noirc_frontend/src/parser/parser.rs @@ -61,12 +61,12 @@ pub fn parse_program(source_program: &str) -> (ParsedModule, Vec) { parsing_errors.extend(lexing_errors.into_iter().map(Into::into)); - (module.unwrap(), parsing_errors) + (module.unwrap_or(ParsedModule { items: vec![] }), parsing_errors) } /// program: module EOF fn program() -> impl NoirParser { - module().then_ignore(force(just(Token::EOF))) + module().then_ignore(just(Token::EOF)) } /// module: top_level_statement module @@ -74,7 +74,7 @@ fn program() -> impl NoirParser { fn module() -> impl NoirParser { recursive(|module_parser| { empty() - .map(|_| ParsedModule::default()) + .to(ParsedModule::default()) .then(spanned(top_level_statement(module_parser)).repeated()) .foldl(|mut program, (statement, span)| { let mut push_item = |kind| program.items.push(Item { kind, span }); @@ -164,7 +164,6 @@ fn contract(module_parser: impl NoirParser) -> impl NoirParser impl NoirParser { attributes() - .or_not() .then(function_modifiers()) .then_ignore(keyword(Keyword::Fn)) .then(ident()) @@ -224,6 +223,7 @@ fn function_modifiers() -> impl NoirParser<(bool, bool, bool, bool, bool)> { ) }) } + fn is_pub_crate() -> impl NoirParser { (keyword(Keyword::Pub) .then_ignore(just(Token::LeftParen)) @@ -260,18 +260,14 @@ fn struct_definition() -> impl NoirParser { [(LeftParen, RightParen), (LeftBracket, RightBracket)], |_| vec![], )) - .or(just(Semicolon).map(|_| Vec::new())); + .or(just(Semicolon).to(Vec::new())); - attributes() - .or_not() - .then_ignore(keyword(Struct)) - .then(ident()) - .then(generics()) - .then(fields) - .validate(|(((raw_attributes, name), generics), fields), span, emit| { + attributes().then_ignore(keyword(Struct)).then(ident()).then(generics()).then(fields).validate( + |(((raw_attributes, name), generics), fields), span, emit| { let attributes = validate_struct_attributes(raw_attributes, span, emit); TopLevelStatement::Struct(NoirStruct { name, attributes, generics, fields, span }) - }) + }, + ) } fn type_alias_definition() -> impl NoirParser { @@ -448,7 +444,7 @@ fn trait_constant_declaration() -> impl NoirParser { /// trait_function_declaration: 'fn' ident generics '(' declaration_parameters ')' function_return_type fn trait_function_declaration() -> impl NoirParser { let trait_function_body_or_semicolon = - block(fresh_statement()).map(Option::from).or(just(Token::Semicolon).map(|_| Option::None)); + block(fresh_statement()).map(Option::from).or(just(Token::Semicolon).to(Option::None)); keyword(Keyword::Fn) .ignore_then(ident()) @@ -463,20 +459,14 @@ fn trait_function_declaration() -> impl NoirParser { } fn validate_attributes( - attributes: Option>, + attributes: Vec, span: Span, emit: &mut dyn FnMut(ParserError), ) -> Attributes { - if attributes.is_none() { - return Attributes::empty(); - } - - let attrs = attributes.unwrap(); - let mut primary = None; let mut secondary = Vec::new(); - for attribute in attrs { + for attribute in attributes { match attribute { Attribute::Function(attr) => { if primary.is_some() { @@ -495,14 +485,13 @@ fn validate_attributes( } fn validate_struct_attributes( - attributes: Option>, + attributes: Vec, span: Span, emit: &mut dyn FnMut(ParserError), ) -> Vec { - let attrs = attributes.unwrap_or_default(); let mut struct_attributes = vec![]; - for attribute in attrs { + for attribute in attributes { match attribute { Attribute::Function(..) => { emit(ParserError::with_reason( @@ -976,7 +965,7 @@ fn assign_operator() -> impl NoirParser { // Since >> is lexed as two separate "greater-than"s, >>= is lexed as > >=, so // we need to account for that case here as well. let right_shift_fix = - just(Token::Greater).then(just(Token::GreaterEqual)).map(|_| Token::ShiftRight); + just(Token::Greater).then(just(Token::GreaterEqual)).to(Token::ShiftRight); let shorthand_syntax = shorthand_syntax.or(right_shift_fix); just(Token::Assign).or(shorthand_syntax) @@ -1337,7 +1326,7 @@ fn create_infix_expression(lhs: Expression, (operator, rhs): (BinaryOp, Expressi // to parse nested generic types. For normal expressions however, it means we have to manually // parse two greater-than tokens as a single right-shift here. fn right_shift_operator() -> impl NoirParser { - just(Token::Greater).then(just(Token::Greater)).map(|_| Token::ShiftRight) + just(Token::Greater).then(just(Token::Greater)).to(Token::ShiftRight) } fn operator_with_precedence(precedence: Precedence) -> impl NoirParser> { diff --git a/noir/compiler/noirc_frontend/src/resolve_locations.rs b/noir/compiler/noirc_frontend/src/resolve_locations.rs index 02325de4da8..cfb88966b9d 100644 --- a/noir/compiler/noirc_frontend/src/resolve_locations.rs +++ b/noir/compiler/noirc_frontend/src/resolve_locations.rs @@ -42,6 +42,7 @@ impl NodeInterner { .and_then(|index| self.resolve_location(index, return_type_location_instead)) .or_else(|| self.try_resolve_trait_impl_location(location)) .or_else(|| self.try_resolve_trait_method_declaration(location)) + .or_else(|| self.try_resolve_type_ref(location)) .or_else(|| self.try_resolve_type_alias(location)) } @@ -196,7 +197,17 @@ impl NodeInterner { }) } - #[tracing::instrument(skip(self), ret)] + /// Attempts to resolve [Location] of [Type] based on [Location] of reference in code + pub(crate) fn try_resolve_type_ref(&self, location: Location) -> Option { + self.type_ref_locations + .iter() + .find(|(_typ, type_ref_location)| type_ref_location.contains(&location)) + .and_then(|(typ, _)| match typ { + Type::Struct(struct_typ, _) => Some(struct_typ.borrow().location), + _ => None, + }) + } + fn try_resolve_type_alias(&self, location: Location) -> Option { self.type_alias_ref .iter() diff --git a/noir/compiler/wasm/src/compile.rs b/noir/compiler/wasm/src/compile.rs index 498ffe447ce..b39a27a7931 100644 --- a/noir/compiler/wasm/src/compile.rs +++ b/noir/compiler/wasm/src/compile.rs @@ -190,7 +190,8 @@ pub fn compile( })? .0; - let optimized_contract = nargo::ops::optimize_contract(compiled_contract, expression_width); + let optimized_contract = + nargo::ops::transform_contract(compiled_contract, expression_width); let compile_output = generate_contract_artifact(optimized_contract); Ok(JsCompileResult::new(compile_output)) @@ -205,7 +206,7 @@ pub fn compile( })? .0; - let optimized_program = nargo::ops::optimize_program(compiled_program, expression_width); + let optimized_program = nargo::ops::transform_program(compiled_program, expression_width); let compile_output = generate_program_artifact(optimized_program); Ok(JsCompileResult::new(compile_output)) diff --git a/noir/compiler/wasm/src/compile_new.rs b/noir/compiler/wasm/src/compile_new.rs index 6476f6d29bc..4616004ae2b 100644 --- a/noir/compiler/wasm/src/compile_new.rs +++ b/noir/compiler/wasm/src/compile_new.rs @@ -109,7 +109,7 @@ impl CompilerContext { })? .0; - let optimized_program = nargo::ops::optimize_program(compiled_program, np_language); + let optimized_program = nargo::ops::transform_program(compiled_program, np_language); let compile_output = generate_program_artifact(optimized_program); Ok(JsCompileResult::new(compile_output)) @@ -134,7 +134,7 @@ impl CompilerContext { })? .0; - let optimized_contract = nargo::ops::optimize_contract(compiled_contract, np_language); + let optimized_contract = nargo::ops::transform_contract(compiled_contract, np_language); let compile_output = generate_contract_artifact(optimized_contract); Ok(JsCompileResult::new(compile_output)) diff --git a/noir/cspell.json b/noir/cspell.json index 0547b956d72..12b1e3f63d3 100644 --- a/noir/cspell.json +++ b/noir/cspell.json @@ -20,6 +20,8 @@ "bindgen", "bitand", "blackbox", + "boilerplate", + "boilerplates", "bridgekeeper", "brillig", "bytecount", @@ -56,6 +58,7 @@ "defunctionalized", "deque", "desugared", + "devcontainer", "direnv", "eddsa", "Elligator", @@ -96,6 +99,7 @@ "keccak", "keccakf", "krate", + "losslessly", "lvalue", "Maddiaa", "mathbb", @@ -121,6 +125,7 @@ "noirup", "nomicfoundation", "noncanonical", + "nouner", "pedersen", "peekable", "plonkc", @@ -172,9 +177,7 @@ "wasi", "wasmer", "Weierstraß", - "zshell", - "nouner", - "devcontainer" + "zshell" ], "ignorePaths": [ "./**/node_modules/**", diff --git a/noir/docs/.gitignore b/noir/docs/.gitignore index 4f6eee8284e..501e7e465ea 100644 --- a/noir/docs/.gitignore +++ b/noir/docs/.gitignore @@ -3,6 +3,8 @@ # Production /build +processed-docs +processed-docs-cache # Generated files .docusaurus diff --git a/noir/docs/README.md b/noir/docs/README.md index 92f6c5f41f7..c1d2bbd6d4e 100644 --- a/noir/docs/README.md +++ b/noir/docs/README.md @@ -2,7 +2,7 @@ This is the source code for the Noir documentation site at [noir-lang.org](https://noir-lang.org). -This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website +This website is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator. ## Contributing @@ -15,14 +15,20 @@ Check out the contributing guide [here](../CONTRIBUTING.md). ### Installation +This project requires recent versions of rust and cargo to be installed. +Any build errors should indicate dependencies that need installing, and at what version. + +On the root folder of the repository, run: + ``` yarn +yarn build ``` ### Local Development ``` -yarn start +yarn workspace docs start ``` This command starts a local development server and opens up a browser window. Most changes are @@ -31,8 +37,12 @@ reflected live without having to restart the server. ### Build ``` -yarn build +yarn workspace docs build ``` This command generates static content into the `build` directory and can be served using any static -contents hosting service. +contents hosting service. You can see a preview by running: + +``` +yarn workspace docs serve +``` diff --git a/noir/docs/docs/getting_started/hello_noir/_category_.json b/noir/docs/docs/getting_started/hello_noir/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/noir/docs/docs/getting_started/hello_noir/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/docs/getting_started/create_a_project.md b/noir/docs/docs/getting_started/hello_noir/index.md similarity index 92% rename from noir/docs/docs/getting_started/create_a_project.md rename to noir/docs/docs/getting_started/hello_noir/index.md index 26ff265c389..743c4d8d634 100644 --- a/noir/docs/docs/getting_started/create_a_project.md +++ b/noir/docs/docs/getting_started/hello_noir/index.md @@ -1,5 +1,5 @@ --- -title: Creating A Project +title: Creating a Project description: Learn how to create and verify your first Noir program using Nargo, a programming language for zero-knowledge proofs. @@ -48,7 +48,7 @@ nargo new hello_world > `test`). A `hello_world` folder would be created. Similar to Rust, the folder houses _src/main.nr_ and -_Nargo.toml_ that contains the source code and environmental options of your Noir program +_Nargo.toml_ which contain the source code and environmental options of your Noir program respectively. ### Intro to Noir Syntax @@ -69,7 +69,7 @@ x : Field, y : pub Field Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the keyword `pub` (e.g. `y`). To learn more about private and public values, check the -[Data Types](../noir/concepts/data_types/index.md) section. +[Data Types](../../noir/concepts/data_types/index.md) section. The next line of the program specifies its body: @@ -79,7 +79,7 @@ assert(x != y); The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. -For more Noir syntax, check the [Language Concepts](../noir/concepts/comments.md) chapter. +For more Noir syntax, check the [Language Concepts](../../noir/concepts/comments.md) chapter. ## Build In/Output Files @@ -96,7 +96,7 @@ _Prover.toml_ houses input values, and _Verifier.toml_ houses public values. ## Prove Our Noir Program -Now that the project is set up, we can create a proof of correct execution on our Noir program. +Now that the project is set up, we can create a proof of correct execution of our Noir program. Fill in input values for execution in the _Prover.toml_ file. For example: diff --git a/noir/docs/docs/getting_started/project_breakdown.md b/noir/docs/docs/getting_started/hello_noir/project_breakdown.md similarity index 86% rename from noir/docs/docs/getting_started/project_breakdown.md rename to noir/docs/docs/getting_started/hello_noir/project_breakdown.md index c4e2a9ae003..6160a102c6c 100644 --- a/noir/docs/docs/getting_started/project_breakdown.md +++ b/noir/docs/docs/getting_started/hello_noir/project_breakdown.md @@ -8,8 +8,8 @@ keywords: sidebar_position: 2 --- -This section breaks down our hello world program in section _1.2_. We elaborate on the project -structure and what the `prove` and `verify` commands did in the previous section. +This section breaks down our hello world program from the previous section. We elaborate on the project +structure and what the `prove` and `verify` commands did. ## Anatomy of a Nargo Project @@ -52,7 +52,7 @@ license = "MIT" ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"} ``` -Nargo.toml for a [workspace](../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: +Nargo.toml for a [workspace](../../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: ```toml [workspace] @@ -62,7 +62,7 @@ default-member = "crates/a" #### Package section -The package section requires a number of fields including: +The package section defines a number of fields including: - `name` (**required**) - the name of the package - `type` (**required**) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract @@ -75,7 +75,7 @@ The package section requires a number of fields including: #### Dependencies section -This is where you will specify any dependencies for your project. See the [Dependencies page](../noir/modules_packages_crates/dependencies.md) for more info. +This is where you will specify any dependencies for your project. See the [Dependencies page](../../noir/modules_packages_crates/dependencies.md) for more info. `./proofs/` and `./contract/` directories will not be immediately visible until you create a proof or verifier contract respectively. @@ -98,7 +98,7 @@ verifying the proof. The prover supplies the values for `x` and `y` in the _Prover.toml_ file. -As for the program body, `assert` ensures the satisfaction of the condition (e.g. `x != y`) is +As for the program body, `assert` ensures that the condition to be satisfied (e.g. `x != y`) is constrained by the proof of the execution of said program (i.e. if the condition was not met, the verifier would reject the proof as an invalid proof). @@ -116,8 +116,8 @@ y = "2" When the command `nargo prove` is executed, two processes happen: -1. Noir creates a proof that `x` which holds the value of `1` and `y` which holds the value of `2` - is not equal. This not equal constraint is due to the line `assert(x != y)`. +1. Noir creates a proof that `x`, which holds the value of `1`, and `y`, which holds the value of `2`, + is not equal. This inequality constraint is due to the line `assert(x != y)`. 2. Noir creates and stores the proof of this statement in the _proofs_ directory in a file called your-project.proof. So if your project is named "private_voting" (defined in the project Nargo.toml), the proof will be saved at `./proofs/private_voting.proof`. Opening this file will display the proof in hex format. @@ -183,12 +183,12 @@ When the command `nargo verify` is executed, two processes happen: In production, the prover and the verifier are usually two separate entities. A prover would retrieve the necessary inputs, execute the Noir program, generate a proof and pass it to the -verifier. The verifier would then retrieve the public inputs from usually external sources and -verifies the validity of the proof against it. +verifier. The verifier would then retrieve the public inputs, usually from external sources, and +verify the validity of the proof against it. Take a private asset transfer as an example: -A user on browser as the prover would retrieve private inputs (e.g. the user's private key) and +A person using a browser as the prover would retrieve private inputs locally (e.g. the user's private key) and public inputs (e.g. the user's encrypted balance on-chain), compute the transfer, generate a proof and submit it to the verifier smart contract. diff --git a/noir/docs/docs/getting_started/installation/index.md b/noir/docs/docs/getting_started/installation/index.md index 27eeeca88ed..4ef86aa5914 100644 --- a/noir/docs/docs/getting_started/installation/index.md +++ b/noir/docs/docs/getting_started/installation/index.md @@ -16,6 +16,7 @@ keywords: [ Branches Noirup Repository ] +pagination_next: getting_started/hello_noir/index --- `nargo` is the one-stop-shop for almost everything related with Noir. The name comes from our love for Rust and its package manager `cargo`. @@ -43,3 +44,5 @@ Done. That's it. You should have the latest version working. You can check with You can also install nightlies, specific versions or branches. Check out the [noirup repository](https://github.com/noir-lang/noirup) for more information. + +Now we're ready to start working on [our first Noir program!](../hello_noir/index.md) diff --git a/noir/docs/docs/getting_started/tooling/_category_.json b/noir/docs/docs/getting_started/tooling/_category_.json index dff520ebc41..55804c03a71 100644 --- a/noir/docs/docs/getting_started/tooling/_category_.json +++ b/noir/docs/docs/getting_started/tooling/_category_.json @@ -1,5 +1,5 @@ { - "position": 3, + "position": 2, "label": "Tooling", "collapsible": true, "collapsed": true diff --git a/noir/docs/docs/how_to/how-to-oracles.md b/noir/docs/docs/how_to/how-to-oracles.md index bdb2b1332ba..0d84d992320 100644 --- a/noir/docs/docs/how_to/how-to-oracles.md +++ b/noir/docs/docs/how_to/how-to-oracles.md @@ -18,7 +18,7 @@ This guide shows you how to use oracles in your Noir program. For the sake of cl - You understand the concept of a JSON-RPC server. Visit the [JSON-RPC website](https://www.jsonrpc.org/) if you need a refresher. - You are comfortable with server-side JavaScript (e.g. Node.js, managing packages, etc.). -For reference, you can find the snippets used in this tutorial on the [Aztec DevRel Repository](https://github.com/AztecProtocol/dev-rel/tree/main/how_to_oracles/code-snippets/how-to-oracles). +For reference, you can find the snippets used in this tutorial on the [Aztec DevRel Repository](https://github.com/AztecProtocol/dev-rel/tree/main/code-snippets/how-to-oracles). ## Rundown diff --git a/noir/docs/docs/how_to/how-to-recursion.md b/noir/docs/docs/how_to/how-to-recursion.md index f60aa3ff2d9..39db23f1f3a 100644 --- a/noir/docs/docs/how_to/how-to-recursion.md +++ b/noir/docs/docs/how_to/how-to-recursion.md @@ -47,7 +47,7 @@ In a standard recursive app, you're also dealing with at least two circuits. For - `main`: a circuit of type `assert(x != y)` - `recursive`: a circuit that verifies `main` -For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir/noir-examples) repository. We will *not* be using it as a reference for this guide. +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir-lang/noir-examples) repository. We will *not* be using it as a reference for this guide. ## Step 1: Setup diff --git a/noir/docs/docs/how_to/how-to-solidity-verifier.md b/noir/docs/docs/how_to/how-to-solidity-verifier.md new file mode 100644 index 00000000000..e3c7c1065da --- /dev/null +++ b/noir/docs/docs/how_to/how-to-solidity-verifier.md @@ -0,0 +1,231 @@ +--- +title: Generate a Solidity Verifier +description: + Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier + contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart + contract. Read more to find out +keywords: + [ + solidity verifier, + smart contract, + blockchain, + compiler, + plonk_vk.sol, + EVM blockchain, + verifying Noir programs, + proving backend, + Barretenberg, + ] +sidebar_position: 0 +pagination_next: tutorials/noirjs_app +--- + +Noir has the ability to generate a verifier contract in Solidity, which can be deployed in many EVM-compatible blockchains such as Ethereum. + +This allows for a powerful feature set, as one can make use of the conciseness and the privacy provided by Noir in an immutable ledger. Applications can range from simple P2P guessing games, to complex private DeFi interactions. + +This guide shows you how to generate a Solidity Verifier and deploy it on the [Remix IDE](https://remix.ethereum.org/). It is assumed that: + +- You are comfortable with the Solidity programming language and understand how contracts are deployed on the Ethereum network +- You have Noir installed and you have a Noir program. If you don't, [get started](../getting_started/installation/index.md) with Nargo and the example Hello Noir circuit +- You are comfortable navigating RemixIDE. If you aren't or you need a refresher, you can find some video tutorials [here](https://www.youtube.com/channel/UCjTUPyFEr2xDGN6Cg8nKDaA) that could help you. + +## Rundown + +Generating a Solidity Verifier contract is actually a one-command process. However, compiling it and deploying it can have some caveats. Here's the rundown of this guide: + +1. How to generate a solidity smart contract +2. How to compile the smart contract in the RemixIDE +3. How to deploy it to a testnet + +## Step 1 - Generate a contract + +This is by far the most straight-forward step. Just run: + +```sh +nargo codegen-verifier +``` + +A new `contract` folder would then be generated in your project directory, containing the Solidity +file `plonk_vk.sol`. It can be deployed to any EVM blockchain acting as a verifier smart contract. + +:::info + +It is possible to generate verifier contracts of Noir programs for other smart contract platforms as long as the proving backend supplies an implementation. + +Barretenberg, the default proving backend for Nargo, supports generation of verifier contracts, for the time being these are only in Solidity. +::: + +## Step 2 - Compiling + +We will mostly skip the details of RemixIDE, as the UI can change from version to version. For now, we can just open +Remix and create a blank workspace. + +![Create Workspace](@site/static/img/how-tos/solidity_verifier_1.png) + +We will create a new file to contain the contract Nargo generated, and copy-paste its content. + +:::warning + +You'll likely see a warning advising you to not trust pasted code. While it is an important warning, it is irrelevant in the context of this guide and can be ignored. We will not be deploying anywhere near a mainnet. + +::: + +To compile our the verifier, we can navigate to the compilation tab: + +![Compilation Tab](@site/static/img/how-tos/solidity_verifier_2.png) + +Remix should automatically match a suitable compiler version. However, hitting the "Compile" button will most likely generate a "Stack too deep" error: + +![Stack too deep](@site/static/img/how-tos/solidity_verifier_3.png) + +This is due to the verify function needing to put many variables on the stack, but enabling the optimizer resolves the issue. To do this, let's open the "Advanced Configurations" tab and enable optimization. The default 200 runs will suffice. + +:::info + +This time we will see a warning about an unused function parameter. This is expected, as the `verify` function doesn't use the `_proof` parameter inside a solidity block, it is loaded from calldata and used in assembly. + +::: + +![Compilation success](@site/static/img/how-tos/solidity_verifier_4.png) + +## Step 3 - Deploying + +At this point we should have a compiled contract read to deploy. If we navigate to the deploy section in Remix, we will see many different environments we can deploy to. The steps to deploy on each environment would be out-of-scope for this guide, so we will just use the default Remix VM. + +Looking closely, we will notice that our "Solidity Verifier" is actually three contracts working together: + +- An `UltraVerificationKey` library which simply stores the verification key for our circuit. +- An abstract contract `BaseUltraVerifier` containing most of the verifying logic. +- A main `UltraVerifier` contract that inherits from the Base and uses the Key contract. + +Remix will take care of the dependencies for us so we can simply deploy the UltraVerifier contract by selecting it and hitting "deploy": + +![Deploying UltraVerifier](@site/static/img/how-tos/solidity_verifier_5.png) + +A contract will show up in the "Deployed Contracts" section, where we can retrieve the Verification Key Hash. This is particularly useful for double-checking the deployer contract is the correct one. + +:::note + +Why "UltraVerifier"? + +To be precise, the Noir compiler (`nargo`) doesn't generate the verifier contract directly. It compiles the Noir code into an intermediate language (ACIR), which is then executed by the backend. So it is the backend that returns the verifier smart contract, not Noir. + +In this case, the Barretenberg Backend uses the UltraPlonk proving system, hence the "UltraVerifier" name. + +::: + +## Step 4 - Verifying + +To verify a proof using the Solidity verifier contract, we call the `verify` function in this extended contract: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +When using the default example in the [Hello Noir](../getting_started/hello_noir/index.md) guide, the easiest way to confirm that the verifier contract is doing its job is by calling the `verify` function via remix with the required parameters. For `_proof`, run `nargo prove` and use the string in `proof/.proof` (adding the hex `0x` prefix). We can also copy the public input from `Verifier.toml`, as it will be properly formatted as 32-byte strings: + +``` +0x...... , [0x0000.....02] +``` + +A programmatic example of how the `verify` function is called can be seen in the example zk voting application [here](https://github.com/noir-lang/noir-examples/blob/33e598c257e2402ea3a6b68dd4c5ad492bce1b0a/foundry-voting/src/zkVote.sol#L35): + +```solidity +function castVote(bytes calldata proof, uint proposalId, uint vote, bytes32 nullifierHash) public returns (bool) { + // ... + bytes32[] memory publicInputs = new bytes32[](4); + publicInputs[0] = merkleRoot; + publicInputs[1] = bytes32(proposalId); + publicInputs[2] = bytes32(vote); + publicInputs[3] = nullifierHash; + require(verifier.verify(proof, publicInputs), "Invalid proof"); +``` + +:::info[Return Values] + +A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in +Noir. + +Under the hood, the return value is passed as an input to the circuit and is checked at the end of +the circuit program. + +For example, if you have Noir program like this: + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +the `verify` function will expect the public inputs array (second function parameter) to be of length 3, the two inputs and the return value. Like before, these values are populated in Verifier.toml after running `nargo prove`. + +Passing only two inputs will result in an error such as `PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case, the inputs parameter to `verify` would be an array ordered as `[pubkey_x, pubkey_y, return]`. + +::: + +:::tip[Structs] + +You can pass structs to the verifier contract. They will be flattened so that the array of inputs is 1-dimensional array. + +For example, consider the following program: + +```rust +struct Type1 { + val1: Field, + val2: Field, +} + +struct Nested { + t1: Type1, + is_true: bool, +} + +fn main(x: pub Field, nested: pub Nested, y: pub Field) { + //... +} +``` + +The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +::: + +The other function you can call is our entrypoint `verify` function, as defined above. + +:::tip + +It's worth noticing that the `verify` function is actually a `view` function. A `view` function does not alter the blockchain state, so it doesn't need to be distributed (i.e. it will run only on the executing node), and therefore doesn't cost any gas. + +This can be particularly useful in some situations. If Alice generated a proof and wants Bob to verify its correctness, Bob doesn't need to run Nargo, NoirJS, or any Noir specific infrastructure. He can simply make a call to the blockchain with the proof and verify it is correct without paying any gas. + +It would be incorrect to say that a Noir proof verification costs any gas at all. However, most of the time the result of `verify` is used to modify state (for example, to update a balance, a game state, etc). In that case the whole network needs to execute it, which does incur gas costs (calldata and execution, but not storage). + +::: + +## A Note on EVM chains + +ZK-SNARK verification depends on some precompiled cryptographic primitives such as Elliptic Curve Pairings (if you like complex math, you can read about EC Pairings [here](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627)). Not all EVM chains support EC Pairings, notably some of the ZK-EVMs. This means that you won't be able to use the verifier contract in all of them. + +For example, chains like `zkSync ERA` and `Polygon zkEVM` do not currently support these precompiles, so proof verification via Solidity verifier contracts won't work. Here's a quick list of EVM chains that have been tested and are known to work: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. + +## What's next + +Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks, such as [hardhat](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) and [foundry](https://github.com/noir-lang/noir-starter/tree/main/with-foundry). + +You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. + +You should also be ready to write and deploy your first NoirJS app and start generating proofs on websites, phones, and NodeJS environments! Head on to the [NoirJS tutorial](../tutorials/noirjs_app.md) to learn how to do that. diff --git a/noir/docs/docs/how_to/solidity_verifier.md b/noir/docs/docs/how_to/solidity_verifier.md deleted file mode 100644 index 8022b0e5f20..00000000000 --- a/noir/docs/docs/how_to/solidity_verifier.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Generate a Solidity Verifier -description: - Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier - contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart - contract. Read more to find out -keywords: - [ - solidity verifier, - smart contract, - blockchain, - compiler, - plonk_vk.sol, - EVM blockchain, - verifying Noir programs, - proving backend, - Barretenberg, - ] -sidebar_position: 0 ---- - -For certain applications, it may be desirable to run the verifier as a smart contract instead of on -a local machine. - -Compile a Solidity verifier contract for your Noir program by running: - -```sh -nargo codegen-verifier -``` - -A new `contract` folder would then be generated in your project directory, containing the Solidity -file `plonk_vk.sol`. It can be deployed on any EVM blockchain acting as a verifier smart contract. - -> **Note:** It is possible to compile verifier contracts of Noir programs for other smart contract -> platforms as long as the proving backend supplies an implementation. -> -> Barretenberg, the default proving backend for Nargo, supports compilation of verifier contracts in -> Solidity only for the time being. - -## Verify - -To verify a proof using the Solidity verifier contract, call the `verify` function with the -following signature: - -```solidity -function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) -``` - -You can see an example of how the `verify` function is called in the example zk voting application [here](https://github.com/noir-lang/noir-examples/blob/33e598c257e2402ea3a6b68dd4c5ad492bce1b0a/foundry-voting/src/zkVote.sol#L35): - -```solidity -function castVote(bytes calldata proof, uint proposalId, uint vote, bytes32 nullifierHash) public returns (bool) { - // ... - bytes32[] memory publicInputs = new bytes32[](4); - publicInputs[0] = merkleRoot; - publicInputs[1] = bytes32(proposalId); - publicInputs[2] = bytes32(vote); - publicInputs[3] = nullifierHash; - require(verifier.verify(proof, publicInputs), "Invalid proof"); -``` - -### Public Inputs - -:::tip - -A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in -Noir. - -Under the hood, the return value is passed as an input to the circuit and is checked at the end of -the circuit program. - -::: - -The verifier contract uses the output (return) value of a Noir program as a public input. So if you -have the following function - -```rust -fn main( - // Public inputs - pubkey_x: pub Field, - pubkey_y: pub Field, - // Private inputs - priv_key: Field, -) -> pub Field -``` - -then `verify` in `plonk_vk.sol` will expect 3 public inputs. Passing two inputs will result in an -error like `Reason: PUBLIC_INPUT_COUNT_INVALID(3, 2)`. - -In this case the 3 inputs to `verify` would be ordered as `[pubkey_x, pubkey_y, return]`. - -#### Struct inputs - -Consider the following program: - -```rust -struct Type1 { - val1: Field, - val2: Field, -} - -struct Nested { - t1: Type1, - is_true: bool, -} - -fn main(x: pub Field, nested: pub Nested, y: pub Field) { - //... -} -``` - -Structs will be flattened so that the array of inputs is 1-dimensional array. The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` - -## Noir for EVM chains - -You can currently deploy the Solidity verifier contracts to most EVM compatible chains. EVM chains that have been tested and are known to work include: - -- Optimism -- Arbitrum -- Polygon PoS -- Scroll -- Celo - -Other EVM chains should work, but have not been tested directly by our team. If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. - -### Unsupported chains - -Unfortunately not all "EVM" chains are supported. - -**zkSync** and the **Polygon zkEVM** do _not_ currently support proof verification via Solidity verifier contracts. They are missing the bn256 precompile contract that the verifier contract requires. Once these chains support this precompile, they may work. diff --git a/noir/docs/docs/index.md b/noir/docs/docs/index.md deleted file mode 100644 index ab8c2f8acd2..00000000000 --- a/noir/docs/docs/index.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: Noir -description: - Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to - an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. -keywords: - [ - Noir, - Domain Specific Language, - Rust, - Intermediate Language, - Arithmetic Circuit, - Rank-1 Constraint System, - Ethereum Developers, - Protocol Developers, - Blockchain Developers, - Proving System, - Smart Contract Language, - ] -sidebar_position: 0 ---- - -## What's new about Noir? - -Noir, a domain-specific language crafted for SNARK proving systems, stands out with its simplicity, flexibility, -and robust capabilities. Unlike conventional approaches that compile directly to a fixed NP-complete language, -Noir takes a two-pronged path. First, Noir compiles to an adaptable intermediate language known as ACIR. - -From there, depending on a given project's needs, ACIR can be further compiled into an arithmetic circuit for integration with Aztec's -barretenberg backend, or transformed into a rank-1 constraint system suitable for R1CS backends like Arkworks' Marlin -backend (among others). - -This innovative design introduces unique challenges; however, this approach also strategically separates the programming language from the -backend. Noir's approach echoes the modular philosophy of LLVM, offering developers a versatile toolkit for cryptographic -programming. - -## Who is Noir for? - -### Solidity Developers - -Noir streamlines the creation of Solidity contracts that interface with SNARK systems. -[`Utilize the nargo codegen-verifier`](./reference/nargo_commands.md#nargo-codegen-verifier) command to construct verifier -contracts efficiently. While the current alpha version offers this as a direct feature, future updates aim -to modularize this process for even greater ease of use. - -Noir currently includes a command to create a Solidity contract which verifies your Noir program. This will be -modularized in the future; however, as of the alpha, you can use the `nargo codegen-verifier` command to create a verifier contract. - -### Protocol Developers - -Should the Aztec backend not align with your existing tech stack, or if you're inclined to integrate alternative -proving systems, Noir's agnostic compilation to a proof-agnostic intermediate language offers unmatched flexibility. -This allows protocol engineers the freedom to substitute the default PLONK-based system with an alternative of their -choice, tailoring the proving system to their specific needs. - -### Blockchain developers - -Blockchain developers often face environmental constraints, such as predetermined proving systems and smart contract -languages. Noir addresses this by enabling the implementation of custom proving system backends and smart contract -interfaces, ensuring seamless integration with your blockchain's architecture, and expanding the horizons for innovation -within your projects. - -## Libraries - -Noir does not currently have an official package manager. You can find a list of some of the available Noir libraries in the -[awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). - -Some libraries that are available today include: - -- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library -- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains - the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage - proof verification (or verification of any trie proof involving 32-byte long keys) -- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing - for computations on large unsigned integers -- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and - return the source Ethereum address -- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of - sparse Merkle trees -- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data - type, allowing access to negative numbers on Noir -- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, - allowing results that aren't whole numbers - -See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/noir/docs/docs/index.mdx b/noir/docs/docs/index.mdx new file mode 100644 index 00000000000..75086ddcdde --- /dev/null +++ b/noir/docs/docs/index.mdx @@ -0,0 +1,67 @@ +--- +title: Noir Lang +hide_title: true +description: + Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to + an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. +keywords: + [Noir, + Domain Specific Language, + Rust, + Intermediate Language, + Arithmetic Circuit, + Rank-1 Constraint System, + Ethereum Developers, + Protocol Developers, + Blockchain Developers, + Proving System, + Smart Contract Language] +sidebar_position: 0 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Noir Logo + +Noir is a Domain-Specific Language for SNARK proving systems developed by [Aztec Labs](https://aztec.network/). It allows you to generate complex Zero-Knowledge Programs (ZKP) by using simple and flexible syntax, requiring no previous knowledge on the underlying mathematics or cryptography. + +ZK programs are programs that can generate short proofs of a certain statement without revealing some details about it. You can read more about ZKPs [here](https://dev.to/spalladino/a-beginners-intro-to-coding-zero-knowledge-proofs-c56). + +## What's new about Noir? + +Noir works differently from most ZK languages by taking a two-pronged path. First, it compiles the program to an adaptable intermediate language known as ACIR. From there, depending on a given project's needs, ACIR can be further compiled into an arithmetic circuit for integration with the proving backend. + +:::info + +Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/developers/contracts/main), it defaults to Aztec's Barretenberg proving backend. + +However, the ACIR output can be transformed to be compatible with other PLONK-based backends, or into a [rank-1 constraint system](https://www.rareskills.io/post/rank-1-constraint-system) suitable for backends such as Arkwork's Marlin. + +::: + +## Who is Noir for? + +Noir can be used both in complex cloud-based backends and in user's smartphones, requiring no knowledge on the underlying math or cryptography. From authorization systems that keep a password in the user's device, to complex on-chain verification of recursive proofs, Noir is designed to abstract away complexity without any significant overhead. Here are some examples of situations where Noir can be used: + + + + Noir Logo + + Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/developers/contracts/main) library. + + + Soliditry Verifier Example + Noir can auto-generate Solidity verifier contracts that verify Noir proofs. This allows for non-interactive verification of proofs containing private information in an immutable system. This feature powers a multitude of use-case scenarios, from P2P chess tournaments, to [Aztec Layer-2 Blockchain](https://docs.aztec.network/) + + + Aztec Labs developed NoirJS, an easy interface to generate and verify Noir proofs in a Javascript environment. This allows for Noir to be used in webpages, mobile apps, games, and any other environment supporting JS execution in a standalone manner. + + + + +## Libraries + +Noir is meant to be easy to extend by simply importing Noir libraries just like in Rust. +The [awesome-noir repo](https://github.com/noir-lang/awesome-noir#libraries) is a collection of libraries developed by the Noir community. +Writing a new library is easy and makes code be composable and easy to reuse. See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/noir/docs/docs/noir/concepts/data_types/arrays.md b/noir/docs/docs/noir/concepts/data_types/arrays.md index 7f275a2d771..a8bd338e736 100644 --- a/noir/docs/docs/noir/concepts/data_types/arrays.md +++ b/noir/docs/docs/noir/concepts/data_types/arrays.md @@ -82,14 +82,16 @@ You can create arrays of primitive types or structs. There is not yet support fo ## Methods -For convenience, the STD provides some ready-to-use, common methods for arrays: +For convenience, the STD provides some ready-to-use, common methods for arrays. +Each of these functions are located within the generic impl `impl [T; N] {`. +So anywhere `self` appears, it refers to the variable `self: [T; N]`. ### len Returns the length of an array ```rust -fn len(_array: [T; N]) -> comptime Field +fn len(self) -> Field ``` example @@ -109,7 +111,7 @@ logic it uses internally is optimized specifically for these values. If you need sort any type, you should use the function `sort_via` described below. ```rust -fn sort(_array: [T; N]) -> [T; N] +fn sort(self) -> [T; N] ``` example @@ -127,7 +129,7 @@ fn main() { Sorts the array with a custom comparison function ```rust -fn sort_via(mut a: [T; N], ordering: fn(T, T) -> bool) -> [T; N] +fn sort_via(self, ordering: fn(T, T) -> bool) -> [T; N] ``` example @@ -148,7 +150,7 @@ fn main() { Applies a function to each element of the array, returning a new array containing the mapped elements. ```rust -fn map(f: fn(T) -> U) -> [U; N] +fn map(self, f: fn(T) -> U) -> [U; N] ``` example @@ -164,7 +166,7 @@ Applies a function to each element of the array, returning the final accumulated parameter is the initial value. ```rust -fn fold(mut accumulator: U, f: fn(U, T) -> U) -> U +fn fold(self, mut accumulator: U, f: fn(U, T) -> U) -> U ``` This is a left fold, so the given function will be applied to the accumulator and first element of @@ -198,7 +200,7 @@ fn main() { Same as fold, but uses the first element as starting element. ```rust -fn reduce(f: fn(T, T) -> T) -> T +fn reduce(self, f: fn(T, T) -> T) -> T ``` example: @@ -216,7 +218,7 @@ fn main() { Returns true if all the elements satisfy the given predicate ```rust -fn all(predicate: fn(T) -> bool) -> bool +fn all(self, predicate: fn(T) -> bool) -> bool ``` example: @@ -234,7 +236,7 @@ fn main() { Returns true if any of the elements satisfy the given predicate ```rust -fn any(predicate: fn(T) -> bool) -> bool +fn any(self, predicate: fn(T) -> bool) -> bool ``` example: diff --git a/noir/docs/docs/noir/standard_library/black_box_fns.md b/noir/docs/docs/noir/standard_library/black_box_fns.md index 4b1efbd17de..6b22d0e7466 100644 --- a/noir/docs/docs/noir/standard_library/black_box_fns.md +++ b/noir/docs/docs/noir/standard_library/black_box_fns.md @@ -6,40 +6,26 @@ keywords: [noir, black box functions] Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. -:::warning - -It is likely that not all backends will support a particular black box function. - -::: - -Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. - -Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: - -```rust -#[foreign(sha256)] -fn sha256(_input : [u8; N]) -> [u8; 32] {} -``` +The ACVM spec defines a set of blackbox functions which backends will be expected to implement. This allows backends to use optimized implementations of these constraints if they have them, however they may also fallback to less efficient naive implementations if not. ## Function list -Here is a list of the current black box functions that are supported by UltraPlonk: +Here is a list of the current black box functions: -- AES - [SHA256](./cryptographic_primitives/hashes#sha256) - [Schnorr signature verification](./cryptographic_primitives/schnorr) - [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Blake3](./cryptographic_primitives/hashes#blake2s) - [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) - [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) - [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) - [Fixed base scalar multiplication](./cryptographic_primitives/scalar) -- [Compute merkle root](./merkle_trees#compute_merkle_root) - AND - XOR - RANGE - [Keccak256](./cryptographic_primitives/hashes#keccak256) - [Recursive proof verification](./recursion) -Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. +Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/noir/blob/master/acvm-repo/acir/src/circuit/black_box_functions.rs). diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md index 8d573adb3be..d2b42d67b7c 100644 --- a/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -72,7 +72,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx index 1376c51dfde..d67a1ac94df 100644 --- a/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -13,9 +13,7 @@ Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 cur Verifier for ECDSA Secp256k1 signatures -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool -``` +#include_code ecdsa_secp256k1 noir_stdlib/src/ecdsa_secp256k1.nr rust example: @@ -30,9 +28,7 @@ fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], sign Verifier for ECDSA Secp256r1 signatures -```rust -fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool -``` +#include_code ecdsa_secp256r1 noir_stdlib/src/ecdsa_secp256r1.nr rust example: diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx index 3c5f7f79603..85706384eee 100644 --- a/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -14,9 +14,7 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Given an array of bytes, returns the resulting sha256 hash. -```rust -fn sha256(_input : [u8]) -> [u8; 32] -``` +#include_code sha256 noir_stdlib/src/hash.nr rust example: @@ -33,9 +31,7 @@ fn main() { Given an array of bytes, returns an array with the Blake2 hash -```rust -fn blake2s(_input : [u8]) -> [u8; 32] -``` +#include_code blake2s noir_stdlib/src/hash.nr rust example: @@ -48,43 +44,45 @@ fn main() { -## pedersen_hash +## blake3 -Given an array of Fields, returns the Pedersen hash. +Given an array of bytes, returns an array with the Blake3 hash -```rust -fn pedersen_hash(_input : [Field]) -> Field -``` +#include_code blake3 noir_stdlib/src/hash.nr rust example: ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::pedersen_hash(x); + let hash = std::hash::blake3(x); } ``` +## pedersen_hash + +Given an array of Fields, returns the Pedersen hash. + +#include_code pedersen_hash noir_stdlib/src/hash.nr rust + +example: + +#include_code pedersen-hash test_programs/execution_success/pedersen_hash/src/main.nr rust + + ## pedersen_commitment Given an array of Fields, returns the Pedersen commitment. -```rust -fn pedersen_commitment(_input : [Field]) -> [Field; 2] -``` +#include_code pedersen_commitment noir_stdlib/src/hash.nr rust example: -```rust -fn main() { - let x = [163, 117, 178, 149]; // some random bytes - let commitment = std::hash::pedersen_commitment(x); -} -``` +#include_code pedersen-commitment test_programs/execution_success/pedersen_commitment/src/main.nr rust @@ -94,19 +92,11 @@ Given an array of bytes (`u8`), returns the resulting keccak hash as an array of (`[u8; 32]`). Specify a message_size to hash only the first `message_size` bytes of the input. -```rust -fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] -``` +#include_code keccak256 noir_stdlib/src/hash.nr rust example: -```rust -fn main() { - let x = [163, 117, 178, 149]; // some random bytes - let message_size = 4; - let hash = std::hash::keccak256(x, message_size); -} -``` +#include_code keccak256 test_programs/execution_success/keccak256/src/main.nr rust @@ -122,13 +112,7 @@ fn hash_1(input: [Field; 1]) -> Field example: -```rust -fn main() -{ - let hash_2 = std::hash::poseidon::bn254::hash_2([1, 2]); - assert(hash2 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); -} -``` +#include_code poseidon test_programs/execution_success/poseidon_bn254_hash/src/main.nr rust ## mimc_bn254 and mimc diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx index aa4fb8cbaed..c2946b2b73b 100644 --- a/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -12,9 +12,7 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Performs scalar multiplication over the embedded curve whose coordinates are defined by the configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. -```rust -fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] -``` +#include_code fixed_base_embedded_curve noir_stdlib/src/scalar_mul.nr rust example diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx index 7a2c9c20226..0e0c358c6e1 100644 --- a/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx +++ b/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -11,9 +11,7 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). -```rust -fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool -``` +#include_code schnorr_verify noir_stdlib/src/schnorr.nr rust where `_signature` can be generated like so using the npm package [@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) diff --git a/noir/docs/docs/noir/standard_library/traits.md b/noir/docs/docs/noir/standard_library/traits.md index f2960ca5080..fb6d5ae1c48 100644 --- a/noir/docs/docs/noir/standard_library/traits.md +++ b/noir/docs/docs/noir/standard_library/traits.md @@ -8,11 +8,7 @@ keywords: [traits, trait, interface, protocol, default, add, eq] ### `std::default::Default` -```rust -trait Default { - fn default() -> Self; -} -``` +#include_code default-trait noir_stdlib/src/default.nr rust Constructs a default value of a type. @@ -52,15 +48,47 @@ impl Default for (A, B, C, D, E) For primitive integer types, the return value of `default` is `0`. Container types such as arrays are filled with default values of their element type. + +## `std::convert` + +### `std::convert::From` + +#include_code from-trait noir_stdlib/src/convert.nr rust + +The `From` trait defines how to convert from a given type `T` to the type on which the trait is implemented. + +The Noir standard library provides a number of implementations of `From` between primitive types. +#include_code from-impls noir_stdlib/src/convert.nr rust + +#### When to implement `From` + +As a general rule of thumb, `From` may be implemented in the [situations where it would be suitable in Rust](https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from): + +- The conversion is *infallible*: Noir does not provide an equivalent to Rust's `TryFrom`, if the conversion can fail then provide a named method instead. +- The conversion is *lossless*: semantically, it should not lose or discard information. For example, `u32: From` can losslessly convert any `u16` into a valid `u32` such that the original `u16` can be recovered. On the other hand, `u16: From` should not be implemented as `2**16` is a `u32` which cannot be losslessly converted into a `u16`. +- The conversion is *value-preserving*: the conceptual kind and meaning of the resulting value is the same, even though the Noir type and technical representation might be different. While it's possible to infallibly and losslessly convert a `u8` into a `str<2>` hex representation, `4u8` and `"04"` are too different for `str<2>: From` to be implemented. +- The conversion is *obvious*: it's the only reasonable conversion between the two types. If there's ambiguity on how to convert between them such that the same input could potentially map to two different values then a named method should be used. For instance rather than implementing `U128: From<[u8; 16]>`, the methods `U128::from_le_bytes` and `U128::from_be_bytes` are used as otherwise the endianness of the array would be ambiguous, resulting in two potential values of `U128` from the same byte array. + +One additional recommendation specific to Noir is: +- The conversion is *efficient*: it's relatively cheap to convert between the two types. Due to being a ZK DSL, it's more important to avoid unnecessary computation compared to Rust. If the implementation of `From` would encourage users to perform unnecessary conversion, resulting in additional proving time, then it may be preferable to expose functionality such that this conversion may be avoided. + +### `std::convert::Into` + +The `Into` trait is defined as the reciprocal of `From`. It should be easy to convince yourself that if we can convert to type `A` from type `B`, then it's possible to convert type `B` into type `A`. + +For this reason, implementing `From` on a type will automatically generate a matching `Into` implementation. One should always prefer implementing `From` over `Into` as implementing `Into` will not generate a matching `From` implementation. + +#include_code into-trait noir_stdlib/src/convert.nr rust + +`Into` is most useful when passing function arguments where the types don't quite match up with what the function expects. In this case, the compiler has enough type information to perform the necessary conversion by just appending `.into()` onto the arguments in question. + + ## `std::cmp` ### `std::cmp::Eq` -```rust -trait Eq { - fn eq(self, other: Self) -> bool; -} -``` +#include_code eq-trait noir_stdlib/src/cmp.nr rust + Returns `true` if `self` is equal to `other`. Implementing this trait on a type allows the type to be used with `==` and `!=`. @@ -97,13 +125,9 @@ impl Eq for (A, B, C, D, E) where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } ``` -### `std::cmp::Cmp` +### `std::cmp::Ord` -```rust -trait Cmp { - fn cmp(self, other: Self) -> Ordering; -} -``` +#include_code ord-trait noir_stdlib/src/cmp.nr rust `a.cmp(b)` compares two values returning `Ordering::less()` if `a < b`, `Ordering::equal()` if `a == b`, or `Ordering::greater()` if `a > b`. @@ -151,23 +175,10 @@ These traits abstract over addition, subtraction, multiplication, and division r Implementing these traits for a given type will also allow that type to be used with the corresponding operator for that trait (`+` for Add, etc) in addition to the normal method names. -```rust -trait Add { - fn add(self, other: Self) -> Self; -} - -trait Sub { - fn sub(self, other: Self) -> Self; -} - -trait Mul { - fn mul(self, other: Self) -> Self; -} - -trait Div { - fn div(self, other: Self) -> Self; -} -``` +#include_code add-trait noir_stdlib/src/ops.nr rust +#include_code sub-trait noir_stdlib/src/ops.nr rust +#include_code mul-trait noir_stdlib/src/ops.nr rust +#include_code div-trait noir_stdlib/src/ops.nr rust The implementations block below is given for the `Add` trait, but the same types that implement `Add` also implement `Sub`, `Mul`, and `Div`. @@ -189,11 +200,7 @@ impl Add for u64 { .. } ### `std::ops::Rem` -```rust -trait Rem { - fn rem(self, other: Self) -> Self; -} -``` +#include_code rem-trait noir_stdlib/src/ops.nr rust `Rem::rem(a, b)` is the remainder function returning the result of what is left after dividing `a` and `b`. Implementing `Rem` allows the `%` operator @@ -216,19 +223,9 @@ impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } ### `std::ops::{ BitOr, BitAnd, BitXor }` -```rust -trait BitOr { - fn bitor(self, other: Self) -> Self; -} - -trait BitAnd { - fn bitand(self, other: Self) -> Self; -} - -trait BitXor { - fn bitxor(self, other: Self) -> Self; -} -``` +#include_code bitor-trait noir_stdlib/src/ops.nr rust +#include_code bitand-trait noir_stdlib/src/ops.nr rust +#include_code bitxor-trait noir_stdlib/src/ops.nr rust Traits for the bitwise operations `|`, `&`, and `^`. @@ -255,15 +252,8 @@ impl BitOr for i64 { fn bitor(self, other: i64) -> i64 { self | other } } ### `std::ops::{ Shl, Shr }` -```rust -trait Shl { - fn shl(self, other: Self) -> Self; -} - -trait Shr { - fn shr(self, other: Self) -> Self; -} -``` +#include_code shl-trait noir_stdlib/src/ops.nr rust +#include_code shr-trait noir_stdlib/src/ops.nr rust Traits for a bit shift left and bit shift right. diff --git a/noir/docs/docs/tutorials/noirjs_app.md b/noir/docs/docs/tutorials/noirjs_app.md index 4293aa053fc..23534795dde 100644 --- a/noir/docs/docs/tutorials/noirjs_app.md +++ b/noir/docs/docs/tutorials/noirjs_app.md @@ -3,6 +3,7 @@ title: Building a web app with NoirJS description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment. keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs, app] sidebar_position: 0 +pagination_next: noir/concepts/data_types/index --- NoirJS is a set of packages meant to work both in a browser and a server environment. In this tutorial, we will build a simple web app using them. From here, you should get an idea on how to proceed with your own Noir projects! @@ -70,7 +71,7 @@ At this point in the tutorial, your folder structure should look like this: ### Node and Vite If you want to explore Nargo, feel free to go on a side-quest now and follow the steps in the -[getting started](../getting_started/create_a_project) guide. However, we want our app to run on the browser, so we need Vite. +[getting started](../getting_started/hello_noir/index.md) guide. However, we want our app to run on the browser, so we need Vite. Vite is a powerful tool to generate static websites. While it provides all kinds of features, let's just go barebones with some good old vanilla JS. @@ -205,7 +206,7 @@ We're starting with the good stuff now. If you've compiled the circuit as descri import circuit from '../circuit/target/circuit.json'; ``` -[Noir is backend-agnostic](../index.md#whats-new-about-noir). We write Noir, but we also need a proving backend. That's why we need to import and instantiate the two dependencies we installed above: `BarretenbergBackend` and `Noir`. Let's import them right below: +[Noir is backend-agnostic](../index.mdx#whats-new-about-noir). We write Noir, but we also need a proving backend. That's why we need to import and instantiate the two dependencies we installed above: `BarretenbergBackend` and `Noir`. Let's import them right below: ```js import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; @@ -273,6 +274,6 @@ You have successfully generated a client-side Noir web app! ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/docusaurus.config.ts b/noir/docs/docusaurus.config.ts index aacc318f5be..4e0d053f61e 100644 --- a/noir/docs/docusaurus.config.ts +++ b/noir/docs/docusaurus.config.ts @@ -26,6 +26,7 @@ export default { '@docusaurus/preset-classic', { docs: { + path: "processed-docs", sidebarPath: './sidebars.js', routeBasePath: '/docs', remarkPlugins: [math], diff --git a/noir/docs/package.json b/noir/docs/package.json index 1e3efcfe3d1..6c706e4f514 100644 --- a/noir/docs/package.json +++ b/noir/docs/package.json @@ -3,8 +3,9 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "docusaurus start", - "build": "yarn version::stables && docusaurus build", + "preprocess": "yarn node ./scripts/preprocess/index.js", + "start": "yarn preprocess && docusaurus start", + "build": "yarn preprocess && yarn version::stables && docusaurus build", "version::stables": "ts-node ./scripts/setStable.ts", "serve": "serve build" }, diff --git a/noir/docs/scripts/preprocess/include_code.js b/noir/docs/scripts/preprocess/include_code.js new file mode 100644 index 00000000000..ffe50065002 --- /dev/null +++ b/noir/docs/scripts/preprocess/include_code.js @@ -0,0 +1,312 @@ +const fs = require('fs'); +const path = require('path'); +const childProcess = require('child_process'); + +const getLineNumberFromIndex = (fileContent, index) => { + return fileContent.substring(0, index).split('\n').length; +}; + +/** + * Search for lines of the form + */ +function processHighlighting(codeSnippet, identifier) { + const lines = codeSnippet.split('\n'); + /** + * For an identifier = bar: + * + * Matches of the form: `highlight-next-line:foo:bar:baz` will be replaced with "highlight-next-line". + * Matches of the form: `highlight-next-line:foo:baz` will be replaced with "". + */ + const regex1 = /highlight-next-line:([a-zA-Z0-9-._:]+)/; + const replacement1 = 'highlight-next-line'; + const regex2 = /highlight-start:([a-zA-Z0-9-._:]+)/; + const replacement2 = 'highlight-start'; + const regex3 = /highlight-end:([a-zA-Z0-9-._:]+)/; + const replacement3 = 'highlight-end'; + const regex4 = /this-will-error:([a-zA-Z0-9-._:]+)/; + const replacement4 = 'this-will-error'; + + let result = ''; + let mutated = false; + + const processLine = (line, regex, replacement) => { + const match = line.match(regex); + if (match) { + mutated = true; + + const identifiers = match[1].split(':'); + if (identifiers.includes(identifier)) { + line = line.replace(match[0], replacement); + } else { + // Remove matched text completely + line = line.replace(match[0], ''); + } + } else { + // No match: it's an ordinary line of code. + } + return line.trim() == '//' || line.trim() == '#' ? '' : line; + }; + + for (let line of lines) { + mutated = false; + line = processLine(line, regex1, replacement1); + line = processLine(line, regex2, replacement2); + line = processLine(line, regex3, replacement3); + line = processLine(line, regex4, replacement4); + result += line === '' && mutated ? '' : line + '\n'; + } + + return result.trim(); +} + +let lastReleasedVersion; + +/** Returns the last released tag */ +function getLatestTag() { + if (!lastReleasedVersion) { + const manifest = path.resolve(__dirname, '../../../.release-please-manifest.json'); + lastReleasedVersion = JSON.parse(fs.readFileSync(manifest).toString())['.']; + } + return lastReleasedVersion ? `v${lastReleasedVersion}` : undefined; +} + +/** Returns whether to use the latest release or the current version of stuff. */ +function useLastRelease() { + return process.env.NETLIFY || process.env.INCLUDE_RELEASED_CODE; +} + +/** + * Returns the contents of a file. If the build is running for publishing, it will load the contents + * of the file in the last released version. + */ +function readFile(filePath, tag) { + if (tag && tag !== 'master') { + try { + const root = path.resolve(__dirname, '../../../'); + const relPath = path.relative(root, filePath); + const taggedPath = `${tag}:${relPath}`; + return childProcess.execSync('git show', taggedPath).toString(); + } catch (err) { + console.error(`Error reading file ${filePath} from version ${tag}. Falling back to current content.`); + } + } + return fs.readFileSync(filePath, 'utf-8'); +} + +/** Extracts a code snippet, trying with the last release if applicable, and falling back to current content. */ +function extractCodeSnippet(filePath, identifier, requesterFile) { + if (useLastRelease()) { + try { + return doExtractCodeSnippet(filePath, identifier, false); + } catch (err) { + console.error( + `Error extracting code snippet ${identifier} from ${path.basename( + filePath, + )} requested by ${requesterFile}: ${err}. Falling back to current content.`, + ); + } + } + + return doExtractCodeSnippet(filePath, identifier, true); +} + +/** + * Parse a code file, looking for identifiers of the form: + * `docs:start:${identifier}` and `docs:end:{identifier}`. + * Extract that section of code. + * + * It's complicated if code snippet identifiers overlap (i.e. the 'start' of one code snippet is in the + * middle of another code snippet). The extra logic in this function searches for all identifiers, and + * removes any which fall within the bounds of the code snippet for this particular `identifier` param. + * @returns the code snippet, and start and end line numbers which can later be used for creating a link to github source code. + */ +function doExtractCodeSnippet(filePath, identifier, useCurrent) { + const tag = useCurrent ? 'master' : getLatestTag(); + let fileContent = readFile(filePath, tag); + let lineRemovalCount = 0; + let linesToRemove = []; + + const startRegex = /(?:\/\/|#)\s+docs:start:([a-zA-Z0-9-._:]+)/g; // `g` will iterate through the regex.exec loop + const endRegex = /(?:\/\/|#)\s+docs:end:([a-zA-Z0-9-._:]+)/g; + + /** + * Search for one of the regex statements in the code file. If it's found, return the line as a string and the line number. + */ + const lookForMatch = (regex) => { + let match; + let matchFound = false; + let matchedLineNum = null; + let actualMatch = null; + let lines = fileContent.split('\n'); + while ((match = regex.exec(fileContent))) { + if (match !== null) { + const identifiers = match[1].split(':'); + let tempMatch = identifiers.includes(identifier) ? match : null; + + if (tempMatch === null) { + // If it's not a match, we'll make a note that we should remove the matched text, because it's from some other identifier and should not appear in the snippet for this identifier. + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + if (line.trim() == match[0].trim()) { + linesToRemove.push(i + 1); // lines are indexed from 1 + ++lineRemovalCount; + } + } + } else { + if (matchFound === true) { + throw new Error(`Duplicate for regex ${regex} and identifier ${identifier}`); + } + matchFound = true; + matchedLineNum = getLineNumberFromIndex(fileContent, tempMatch.index); + actualMatch = tempMatch; + } + } + } + + return [actualMatch, matchedLineNum]; + }; + + let [startMatch, startLineNum] = lookForMatch(startRegex); + let [endMatch, endLineNum] = lookForMatch(endRegex); + + // Double-check that the extracted line actually contains the required start and end identifier. + if (startMatch !== null) { + const startIdentifiers = startMatch[1].split(':'); + startMatch = startIdentifiers.includes(identifier) ? startMatch : null; + } + if (endMatch !== null) { + const endIdentifiers = endMatch[1].split(':'); + endMatch = endIdentifiers.includes(identifier) ? endMatch : null; + } + + if (startMatch === null || endMatch === null) { + if (startMatch === null && endMatch === null) { + throw new Error(`Identifier "${identifier}" not found in file "${filePath}"`); + } else if (startMatch === null) { + throw new Error(`Start line "docs:start:${identifier}" not found in file "${filePath}"`); + } else { + throw new Error(`End line "docs:end:${identifier}" not found in file "${filePath}"`); + } + } + + let lines = fileContent.split('\n'); + + // We only want to remove lines which actually fall within the bounds of our code snippet, so narrow down the list of lines that we actually want to remove. + linesToRemove = linesToRemove.filter((lineNum) => { + const removal_in_bounds = lineNum >= startLineNum && lineNum <= endLineNum; + return removal_in_bounds; + }); + + // Remove lines which contain `docs:` comments for unrelated identifiers: + lines = lines.filter((l, i) => { + return !linesToRemove.includes(i + 1); // lines are indexed from 1 + }); + + // Remove lines from the snippet which fall outside the `docs:start` and `docs:end` values. + lines = lines.filter((l, i) => { + return i + 1 > startLineNum && i + 1 < endLineNum - linesToRemove.length; // lines are indexed from 1 + }); + + // We have our code snippet! + let codeSnippet = lines.join('\n'); + + // The code snippet might contain some docusaurus highlighting comments for other identifiers. We should remove those. + codeSnippet = processHighlighting(codeSnippet, identifier); + + return [codeSnippet, startLineNum, endLineNum, tag]; +} + +/** + * Explaining this regex: + * + * E.g. `#include_code snippet_identifier /circuits/my_code.cpp cpp` + * + * #include_code\s+(\S+)\s+(\S+)\s+(\S+) + * - This is the main regex to match the above format. + * - \s+: one or more whitespace characters (space or tab) after `include_code` command. + * - (\S+): one or more non-whitespaced characters. Captures this as the first argument, which is a human-readable identifier for the code block. + * - etc. + * + * Lookaheads are needed to allow us to ignore commented-out lines: + * + * ^(?!}zZSqfN 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 literal 0 HcmV?d00001 diff --git a/noir/docs/static/img/how-tos/solidity_verifier_3.png b/noir/docs/static/img/how-tos/solidity_verifier_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e30186e32d621e5b78e0a7393790a4a39ac91cab GIT binary patch literal 63153 zcmd4219x5Vw>BEvY;0R?Y&K?N+qR7cO&Z&_8>g{t+iJ|a@;~Q&&l&fAftxY*$l7cD zG?yOCxg!+hBoN_n;Xpt@5TztVl|Vp1X+c21I$)rHJqfiWQXn93xfUWK3Q{5>#0rjf zrWV#FARv+viAm5Z%2L>ahaIcj|Q%&SE$ z6Ji1)iEbPz+`ew1IL*So2IC)>jh_Q%^_5Cw2nOy3I(&TGuQ{SklHRacrnvF_?!}Ko zgOMo+90ViSp7&c&LgrSzW0~#s;8i4^kXfl%^C#*qoLxVG8F9!@BDT{D$@!j#Y z-?Y?gx@o&;!noY;D{BU}(1$HE80F>ikICJ~&7>sSEG-ct8EoPk*wn0FY;DQ$7gPp9 zuRGmb2To=?W}H%I==_5j2&QBBPRoS8@oRJa?@k%r4~A0CtQrPRW209HnMR79;l`B^ zs0l2C*3++lc7EGO2t*9VADK~wh)pp~11Nw{j3p1NXIcqVzei8hSsK*GYRCcJFI(POYf1{>2 zQxgLd@a|il%nqna5z`H#f~BvQ(gMNSo3ML)XDJW;$ski1$o@A$9@!WCAk-cp?2S%+ zc@-K&p3lhO;r?KI0dP|w+}$WCV08M>8UA=z5S_#*!2#wq2=;<#lHjB@XceG%Lj2Sa zt38YgNcTZOIZ*hJgFnZfUa{%#f8leU9Rg#O#Aw8zngBnn91g1>TkMB)YM3LI1fp$JhDwaArG zbjCo(4389|$Pq1ZDFIWVDTAB$w-j^9v(1H4s8-CLR%geQ6-m#_oZ>&SXNT?p>p;>8 zW|UaWNuMG((mE2l{qoEc`cv_5iatIIy$l8=YCT#)EKNWDKt`{2?^+Ln5oL{f1?d8a zRqS1lxKTna*AnTOt~J>`Zxc38Fu~xqJuN4C1{)*F;DE`_jf0oHg#DqtPm94CRXc_* zx?RXa@8A~Xqqa9qC(>r<<=?Juc{F1fPY4NN;s9xN*(GsKQFDqlas+hBh&oa5JT{h} zDKcx4^kiRAm{5sOH>IVdETp+4A*HVize*-b5hVN}<)FSxC6{2OWRa>RXR)9wO>@q2 z&c4l(p*&4kA7a^)xlwaucp`m*eM(?gU6Dzn7*Et?(ji$VU#EHt70x+Q{PNr6xAk|L zeTaR^{YC^KalKHQzeyTY$|O#jMS7;%Nwiipc+}~XTI5<(UaGF5NL0m4hcttUqX|6J zZi=?yk$EQysVYb==yxc0XfEo6baup(@$yMbzXfPF83c-mi}mwSa%;Zl3U62R`jdWF z)caMKQr04S-Lj+8&-DG|I|4=43|1jjA%9`)2>kE$-yS27Bhe#nzq?ANRCraDR9s8g z%X!tr%5lq~%Bxh?i#?_8?!cZP<={Et;jr-at^^U)*wo+^M-_QW77D*sRpnk(GOBFm z`zpRQhUSH)i`R)qh^G&fP^!*~B~)wVdC2{vkPR5fDV!NGCum?{;9wwPs9gZ9w5^n~ z0YA4t*FG0NALJG#_#+o67a`X+ky2G;>wkf}?zs-_3BmVAH-5vmL#`wC8S44hbNXHS zodm*fM0KcTs5_`wgyGPtP&$Ni1Uo!~=p%6&aj$64p9V%+yX3oYyXllQ5t*=?#??}n z!ehc=A%P*P@Gr7bMF_L>v!1g;Y+`JF_1g8O_1_Nu9IzbljPZcS)ZG9Z2akeu8fXAoHWfI=hG^)@jo|RbzQY{y>}&TgKAUs z(s|*0`TpYjhnFv0SF~%#-@)EZ{nCD5yFNeDsA$(=P#{w#Qz_#lLmUf-eusg(!F)(# zHTB%P+oL<=0PXOme$>A_iEg!VDQyA zFWNGqW7{d$6j{=)3^*~3(c`flZFBm^WraVIOBtngTwS?LxV)YsIAyerwRP5hxDvNT z@)1r(R{td0W#($*s&27eL%X1!O#LzD^=m6bA%i*oD5HhVfqj^xl>L|^dzk64OZHxB zBm0$wg1L~}gqDM~kp(duE7?_(m`W1WxxlKR`uinj8qB{Ca60@SXPPXOH|PWt{;Wx+ z4aOs6h>FQe3a>%#%%c?Lq^GkZ;fYjg!&PV%Cz>|xo}(w&%eu>5dpS;=T<2B|3)b3f zElIWa-Q4CnuYd0ExKIBrAlqGSDAfOIVKLc_){a`+Swl`I{nmI;dT29*_uTUm_UwJ^ zt?2t>d{bPPUDQNreZFDZY_sWl z=Gt@L#-r^vhcSv}hK+oVu(YfqOh-fgRAcp2RbKeD@Wl`RZX)wL#bOd+(c`@4<)nrT;@f5$#*qOwdx026Q%2B*ISDZoJnH;~|ckS#xOf4+T5yr?5(Lr|DJVqYo{EiLH*?Ma^5Z25HD8J=Ys5$wlr zUsu~cOg2AwgDmD#U%SRXKq48zO0hrQjRDT8W}+@-Dk}>Duvicn5YR9S5C~uk6!_o* z9}p1m_)rjN;6EDh5zPVnKSx1nbHM-4Hdx1JLm_1mDS-WgC>uGNnAkd*+c`JqbDsi3 zEm)|iJFCmea2wg#Fd7)!8JaM<+t`100pWG$1~zR>oDGQGZLDpbxZU|k|I>mS*#6wj zL`wXhCeBuTr0TK?#3FW%Cd6MEnHiZ$`QeC(iFqB3O}Ujs#s9lI@Qshu+}YWln~BNI z&5hBGjnU50jERMdi;Ibwm5G&=0cgSC}-iY z$2Bmtb8+S)CHVa8|cdWxtCkP!rjDL zL)5|sI6c4|{NI>ac>mM>|8wMjX8d10)&Hj_D;MYg?)krt{J(puI+-|%*x3M6I`jX} zmHF?^|NG#7cjRUIjQoF{iT^sy|Je(iXMQ+drvH1*_~APJ<%2;$1VN-kg;d-@&vYR5 zF@B&E!eE7?29moA+rwW#G?PMVYUYS*!G*xNY%?{4{87pcX;R27RENg^E)aauR{R#$ z<6*jSY{w`?t2ED784~>E5?T+`6Rr)!B06&cF0_Iz9g+NDdu7DU3LF$aJ#hCtTim%*A0S- zE?oOX*44BZgdY5(N;^?J`gwvDAKR|$jqvS$b<+9v$beRX*ng#|BeuQ6=O~OwoIE@| z&Hw5O3xjYYp8w+&{Ez!}p0dV#<*L7CgSkknn*Oz4_nJ#(0S)>*W&rZPH-h ztDBpmEIy)qd47-VD(%)C6&zd*RC@^s$CffBlhLH&*QdARAmq@gO08z{RX#6QRQ@lb zs%0w0)A?P+B_;Wec8gU6&i@W%aTJJYhwe@nON|DrZeK3DhFoe5`%5K%334?*91i^w z5%wfz{xPy#Z)QFiV5T1eCw?sY0*{fH9Jl`TGYt zAJ0&<1tCH}aXIXyU>Xj_N<=`#QOOg+>UDTRa#$~k4#9$>;VuS3IvM+?p(oM(5E??p z)#{H_H6QrtH{P7U%cMje4u$CX7tO3clA^)&oVK+}r;Ra@MmY%#46MZa>3fpB^d3fr ze~RToMFO$Oe3?NKGs=8#$iFi~Gtn~LjwFguv2v}9R?m;qj> zpvkDJGBOD1_`1Tx?rrJ&C-dcwsZ_C4I-TCbj-#_|)ft;D4k9t%>^5==rLh&08IiBL zGo_zyJYY2h6PO`ZG}6Bk?A_e#j~afpU8<2A6DE^W8cazsf4=N$>vO$7vygTsBGMcA zMMjmNXR`qn%bL?NSBPtA6hVXyK5S?U>sHXtNL>_IKXN!U*)c1F_?7Y_2W~4 z)zD$!;f?Z_ur|1ynvOC&7U*9HgI2=z@kr~IKbG=xTo9gwv^AsMlNbw~;*J*27wTXhF1$#gP zTh^IRfyXxNlbFdBF=LhCdQ1k|X-BGe`9?ox!(q{rF9rk%&HZul(rmPBRmBw4tT&ZS zXm7IHG<0F=U}Q$EaXS2ZGFNKliJ5B6b#({amudcZ4Xj(?u)*Qs;KN1pFp+|$65S@a znEsDXhre!*^5tjBtC5nL`FasZ(|Ft{(Nn1SUe2Omu*PB7)TEOce_N3u434LN8yR#Y zd*7SLY)kv0^pN9X0Ckq>7OItZzSU~#qez_2|9fq2-lToD-bv7fw&hKR}* zP=%J#O1!JpY?wKM<`N`O>3Z&&ExvEKFAwi^^nNuR)r&yjBE;kDWn)mm3qMd5Al9%! zleuQsn6pXtuCn86~zjM%-yD+bVA67FkoC*_apnDmLJzn0; z)z#K{(<{EMOaRzBlAjKh*+j-GdS^(&7!NhIg6}`RVM$MAly1A-{4Q;hjSbzT?5d_@ zB47XM#lgW12E%{t)+?{e>Z-fvKDQ@^jOt1H7OT&%2Qu z`&};)Ma4n$y&;wcpTR1KYpaC{Ii}93Sa0w4eZn2G%}M?bwJLaQM#;<9OI2D;_90=< zU%wP@Z|E+`pHB;5;T&fDnYzAA2()Pjd-C2E%%O1ZhTZ!MIV$A{`r`7PSgkbKP$A+x z|Dy10v`j4BWQ%p`3}_cy*2d*{{xQnuMJ1cYo^uFwpD3$9WF!Mr^2IqKfAS9S?2FE9^;BOG28LLSEeTlc1p6JUoiUVYczG>luFP3?ibyeS}qj=J>5=80j7I_5)-Z>Y_7`A2cu2!FDeFRu-srK_F@0X>#+fhT7O0^XEYQ|wy!Cz(mu?` zsA^SErGLpvgN1E!NtVyOl;undsE4PaNYp92!A=+NP?2KPfvo$FtT1B*!w+GEHPp?Y z@fCXRokVs{dWu7hq7jC9u&@1TAl`PBTHnmhsftm+ps2?<%yzq;N1WPY4K32xJ!tPP z7bO}}svb5aGI<&kJiV{?ADU#1m1)C0Z(Fk8Gr1F18f^?(W9!nt+0ic!JroK}&iI2? zE6G)nHO%y0AK*01xoy4#Ph{~)2-G|wfhsP4Po2_d5xF*GHolI>6jm`A4V{WeC@$zc z%)h)xz7GkeG`(yUB=pJll^N?eo;AbMh+O7$9y&DyBYV48e-XuV?t5)C&ZCkdt#O(C zLw?zIVj9Xld#xZGL%?G@Pxy$vB~X`W*GWKuJ5SX0A(`*{8cF%e7dn!}AY!!a>?Eq| z>yd--Y%y!P61|ZGU7Y-bpH<+@l`IV`+xJA#@^4?A+oiAP<(s?(zg6gdi=67RipK@l z<9EhsY(4MERX>|zEbE#3(}&=K`|E48StyA6X$igQR;R<`>p?H2a<%Q-^X7bufw5Ky z(#wrX<;WecdOf7hRt~GLFdq8$xQ7uI1k8(az-a@Sy!MlC3VwSXC1Sr_k3A-BhWBOW z{9|C5i^%1;hf?>o$LOKK{o1hoy5jBa zD}}jt*ZX~PUk_2ii)o*PaFJc-9pT&U?Bz{G`*;-;<{~l3`0&OcN2}Ihd@gPxv=tM| z>bEr;PT{jx5Iu8qm~{878^PVM<{C_ui?!CiOZM?w%0^qmHOyBngZc8Bu3bIf-E4Uj zNZ&f&N!}hjPr|yCTzkU57=hiT@Mtebe@Psp-R&vA*=p-SE%1o&|Gq-R`#O3({tbHA zVM^LAs;R+w`8zJ(vz6sqNtW2EV4I%NKWGVaBW9n0*lgkODEYP~1`~TJ@z=rSM@i^$ zr_%+3crlDFl%Gzp%x@k|endEDKG_lF&Bs`oydG)yM4Z$@FH7E`lymg$zfv@(P?8yS zXdcw6HSFY)jyzm1v{w1Qk&5Jpcn{-l;@P!RGm)Wufj}qVcQpmcc5hEkxiTGZcRj~t z-M*o>@@2k!xD=4Yq)RfY?+V>3^kc;a!}+e_^^_Y1Q77`koQ@dk&PIaIC9{wpFVh(~4jS@8z<;Ts4Il@bNDUM1FJ``@sG zl6J-j^+@C)*dP!EVZH;Ru;Fm^jYQs8NIZ|b_VJRh#po|o*I)s&>-1Mt!s4;dBWOQg z5ohWlPNa$iiA5sdrZ(4rzmp&78e7|FB?^A8>rDikv-j=Mm?};O$(1*mdG9LmT z-g<4Kjb@X+B+Z_8mJyTi7Wj!iYhmZBjily7oMD1&kQzO)5Is&H*dR$lf>*-SitQyS zeP}2j#b%SxFrDHe8;aBz z{_ZopJeggNYE7mXhUVjTqD!jGIg}}M((`z?jet#vTZ?zx&VWR8nNPD`A9vdsa{8Vw zRMH$^$nbHt<8xpXWbUkKFVWlYk zJ79VC{ zHm6pPv!GupS7rO@L#3WC1R;Q8n)%1&oVp0VA$E6A9>ufld)Vz8vf2y3|Jv6#mEa|{=&C>a8ia~w7^3S;DR z78h$Fd8qGv+eD?OFq9&}mxi;GQ$zOSALx>XMG^JaHf$e8YY?e#f1^OY1O@x6`fgBe zF!PKj3au-c8U|`C^aO>CR&0(kA;+0ByVS}+FhOnEaP~T&FEZ;8om~g-MTHcoTk|*{ z;W;9b_CM3ZNID`Jg-gNFGW5xcv_fG{B3aW(s*%e$tr}kEPPXnLaY6ILt=y&b*x%nx-+SA$?VYbfiePD@3_ES^}8qWQx{RNgS(Vlk|4vW!nyOd`RGXZRx_uQ^6Wua+eLi;ay*fJED zvznkabF`4$JwysvTOZ7tF77I`xj7(nS29Iwqstd3$o%hAP=Z?Uhqq@!zDVS0?6e>% zYFHLf0g}Ofl5C4!(WE5yBCpW-Cx zQ-e_aNo)SENs>_$dA#}hD8kMEbF>JiAec^DT;a#&>gUi}Bp@*$KRD?a zU+#ii^wt{QJv7Yd@~;6&B#2rQ=0D0#>y>Ji@*jOw1qhxIOlnKQ&&i5DC!=XkYyF%I z42bAQPKn27L}{N96=1r2OvDiK z8GiHKA5ksU>pHX;jt_CYEGC~a(aV*R+D@Z%B1TbZ;3POCu&>s0yWr6TmGE`kF!*F6YUzpPu%MySs@g+fUgYcCxY1%K()RIBkJ$0{3}&m{x+Yzeoc$xOLoQ9Di1e%Jkr=EpN3 z4Gz1WH`mv>x*b_L!Xa?dnFhY|Wva3K&qq4atvY{r^+(KD4%xDwAN+)71b2gFC?VR7Oav|LFDP>5lw%q9no@jOtrTAj>H zh;baY%fY5)vv_r3$^a{Ku29--w`m_{7K;++;^X~=Y3IdarGe`(TYhJ6JYC*frR8Y0 zSm5dTdHVKPIk*Lv1CDBL8U?}p)LXFc$$aE@R|rggetuyGo2d*({1EDS*azGlM}fnx zJ-5?=Ggy4@Tb^~~ZnE4!>__HAw!mP^eGV8TSg@#|VfP@)R`6HhF&mZ(yg`1SXBO0# z8NZJ=k<}&}G=UU{YPHHgf#*biKXWg;KEA_@tl5(3I!aKK?V-%P-~@K}M`4?~#}S&_WB&P+tUrz*Lw|8@kd#2*i*OBcl8yaX-Zi{>Z+m~AVpLcGirj2Md%&h=(9wV!bok3s;3F|J4U_f~$)S*t+Y9s_ptbbE zBM|&F{~c6{(XG`QrT4kqPOfJ;vxf{QL$IO*08VPuWvNimz>YkPUS}R>?Do`vey9jG zn4|wDw44$C_9APa`XU4sy9~vn;@CTV%5T6#!rnxj>Hgj8@_iro+zUNM9)c}m4oA|YX_z$~*Q|w2$^M>Ppc>8MK-T7b;grd;eO@QbuJ%QEvN#1{q^njr@k) zne{j+HR~Vqr!h{U`C^`OF8q8lZ*>(o$N3>&rR_kuYV4Z#aPbC#i2oQr2aVfTraGEX zsilPK`|d%`vqzNke1}&r?jY{1Kjn}A%VxDnlDh%%V5P?31O4BkIh`qAtwN*C>I)1d zMK}vfz+}1Y`ZEM+AXcOMHCPYqbuxn%IVIDWF6V9lykakZPg>c_rC(eq!jnJ$t37qk zVn}}zQ~Oog9J0F60V>$d$;zG3F*xT*z}xekgJz+q{gr&vRvb61)sDVlbP@+jiCV{3 zg76le{WFQYC^Uf7>?JpAW2- zg1|_DYT?W34tDmggqS)%{YI;?BcD|kE_^{TCDdz2B$KZmv zWG;p(L{QX~B%?JpqJZes0(+)fUerZi2ZM>hX(tL=iC;7Bk%F`+UpP**G>qZ0aj--$ zHoJbjnwJjE(9$IFwA{40sHL{`grFtjIR~ndSP_Fb_EIqzpDv7B{Hk2tE3NmnoyEM+ z`n9yAm4rDmF^5*3_Df9+RgwX$OtBEFhd%E83y;|~9n6Gp&lmEL2HHqLOH{ygW(d?E z<|~>dcq&bz2MPJg5`>~K%M|3lXb5nyZU=xs;SYW{q6L^06bZnrgu1P2KbaLLz?ou< z3RynAYoJHo2=P{6cN@c}M2SUZ#QNz#Nq?Q@hX%?f~JamM(gCGM(Q$b9!3icwPkueG|EDl6FRyjb$V#snt_c_&Ym4QaAFo64x0HzzI3V{JS z2rSzXpDwx-XoM3CusSHv>V9B_{=0xr{ZR7y2Cj6sYdP_{f$F;J{&wf)?sew!3jXxL zxuF?ze0n-4!0y*mhZn9K!N$z$+ur5-CVu<=5>zUe`CO+n2Tg=9+>L879Vz%svc;O$ z%OprB;PCSsnT)qQi`RJX!@$o{qy(fUP+aySm*?Z+OW3vmW6I?& zzu3aer5PA4lu~Li4M@=BRNu!`O*1JtVzTIZ0SEYK!{K;HR`pt0XEhXS`d0hxwTdYf zn|#tZ5YS``6<9~PeE+E_$2!CZ;Jxdfej3;==E`Za($J%%3D5)+qkbT#Dy=?WHg6)a z27q?*A2&bs-YoYWoMm^^G*uwkdNP0NKs%yI;F`PMWaE@~V0^xEN6p&~Y4<%Mnu!U` zwS>=^I&h~~>&A7(LxYWXblYzl$PvQev39=RqyyAb91gym0(biLsosR{rbt$62y1W2 z#kD7}wJw#+H4PH7bxtpg-YD$w|X*{Ji(bsaC zvsi1Xji11mn8XYiiv*~A*)3R(RKkJt-jKmExdV_UlTib$tIb#Bm+V_z9cT0>xl8Rz?e@2M*jkmopZaz=!pD~qAkhTG7zRf)Z1XNw0+TQL!bYX8u)Ybj=`nlLV zvly{5XF|^VQ%orokJhv<(rx~YI1}J}`Hpgl;x(_t&rb8$Bd9MCJCOLzW(DJu zf0}De!5H*zKQGl%10FUlCJmb8;beC5t6HU|_!Jh&(?9GSTGg^)4<$b!w<6p{@YjEb8-&imBW;Z@Qd7^ zx3vjT;2#l7nwv;P#Kt10hm33Rz$cqe?bSp#MUvWA6UW`c*ypPmCc&ru1u}yD6|7~h z0I!BaVk9e?1iRS)QC(31x7}M8cSjL z0UpV8UcYrv{~#n98-z5K!aI-@|4Ga<*e3;XK)wRe!?gmxnOd1*_LeivV8-U&A6eKm zeXEJuLWMHKE~?t<$T3a-ncvricA18I1yc9B9OBWiqL4O_MR+jazL}wj=|lPwVCLLF z*+8yl<4KJM*5P3@%K34>L+LV;^J~e^I8!1~=w9hvc77@POX1a3>r&|J=p>iZWJaaJ{$Hb6H<)o>fumxf9VDjPnf!#u^|1;?AQE{|=(hq~YQlfE+J&eA-tV zRwiy8d1jJJAV&pcfbrIWbh+u<7LWAUlg;ql1Z>8;Is902O3IhiyZUG-bc}3JaH#3~ zbFIFJjkX7LcKa=9G|V(INv;37m$2}as2q6uBGlB%b<>eV*Y2u0fBhEz4?H_eSewmI zU}8%{<}lzKWZ7tQ9*h?x^SIfv)EXKY+2m8U+~4%x1ap4GJD?Y(0LGQMwRj4fL`6y% zx^G|jWM4*bJ`p;I6l{{f+8-BXcCkJYg01>`fS!09@re<$5yx4u)0*`JM9AZEpXv~ zliB^u-~ItmEb$`FD&P|}=>d3~AT9c|H;C6i!Pjl5QScKru>jOGL!Ev6M9qs&YlCM` z^V6*1i~>-zKHS0^Xe8+d3_C;M$e;i$Awvv6O^rVG&QAk_2N?DksTHdP0K^H>t-8zS zrx)mg6Y1d?Z}}@AC6Df!-b0yd+H?7Hw>VM&AY_TOm@1&z%L4^{G(^i)u;1{D-rJZ)f$o$CQNM;-ObB$jAd}aQ1_1G2n%=B*V1TbNu{YS$` z{*r~wl7|cgEX6IT2Kw9`OlI$voz2h#uB4G29=%gQ`nS#XvJL#I!$?6jk!}}+ZOS2o zS*SB=Hp9N+x+up~R+CbvL)*RmeFh#ny;jHNvZC`9mx7v_7FqsU@G+p8#N+|jso;km zfy|QU$RnhjbsLhh)8myJeY!;Z^T{eZV2wPDJ6gYG33PQC*ZO_vE`KNNGTW$J6{#Cn z4FCfLOmzbwTfwueM970@gvV&j98g*9`|*Z7jD4NUAeY9jJLBo@KExja)Lq=*T`pk} z;uQ(k=wLNL{mlwo3gNQb@D8r4J&oz|1N{VJt~|meHLIC|F8bAQDX3=&RC^-`)=V~n zHVT2)t9&&glxULWdM_B9y`f*qP30%c|5%o(L4$D9!wu_|M1Y5w1TR_cQ?tXZwz(b8 zthd;38BTTq?2+qEV0j$V8Km9u_0G zjrK$ojFkx4AGKm%W<nIp@R}`IP$MA69WE2a&N02SR6dfO5f?pgTKUd12Uf$aB?q&%YjVf=)#Ysh-DP(z~@mWf$)RibyMOcA{6p4fO``W-%~YE zVKeD&wJ09}Wm0)G2GYzhU$y&@IH%%W&sT(u24kAOBgrDBO90kNS`J6x(a*X{(vuL< zts!=*16tNN+U1Khs6kq?_ucw7AZ{6Lo8$#RX8 zkpcglIocYs2;)_X7~M}l#obeR1kcwQs1fOm~VHp$e4 z_5R~^o59s`>Tde3Fd2Ivv%xO`8L5U*6zhDG4O^>=HJsZik=U74yDlo1>~D5SDEX** zv6235WO2vgBRGOAHMz3-TSm}El7fOl3yeFjDoZ)e09|S@?4Kd8hx9mKu2&9+>&ym> zrJB&D=s&JLaX`TugXw${10F@JT;`vdr+;S0Kt&lwy!Ul~3qeXW*x6N%jwAaHk7KYa zbRau~DRqN@NR8Gl@OVpzMPcOw+Am`Hbz0(5^H(bB4`3-gq;bbG0%n5j_~U@)O$vZV zN0f6B*=h+z$Hj#$aKDasv|0N`Wbpn;Nv3)MYlE%`eMTf9hz2SF35*TH7{ZWVwXESW zYV4_?|7jrl)HwM-g78>`!)l?3D*Mb#6(Qs7%0*0^&_qd>@?nfqU2FkftQ!$^$QgJ3 zd=*xf4JF8+4o5;C5gjqzv&nWnt1%b1uK#5^KTPBA2!jqNmFMM#{8V=U(=f+O@1U_f zVExh82dEdDq^JUp8(J85Oz2n&OCq6n4Yq*;?U>kO=$H%Z&UT7=3s(%;Vaoc;!)65U z>Edr@vR0oLz~(3|Gr32L(${LTrrU!f+MLK-?bq9v+`t7MRcMGh$gnvn&KqTgddqpM z*?{m48c8V(H0`7&Yu)6$h8W5~y%AS!Qy^z ze{=dO5M2$^f(PKi#R3^k1#*&pg;q0nNGV4u>DC5Ji}eE2*Ly4`$QB-o3-kJ4P!_5H zTmi^}@Toio^J0ol%yiMpb3#9zc>ojhdM6uzz!~5^UH1P#3+wFUav;Yi=m7c*aN75& zm2l-h^%=saJ`2)?2P%_5B|h~T22FJFr#=e>^jWA-HRR`z`2ezUMgIOo$p8cqpnU0X z&SK!F%vAi8nPT4o+>R6s{gjyoQ&v5nOP~fKi6Je#29`s_Q`hsE%5%_j0cPGNcZ z`3V(<6WXoR1u{5gT3v*y6)F+0H!stPqshlBjaE`c(#Ntuxo6p84axpUW;z%gRzZB> z_vve+L8UaEKLvlCw$FD(%qBCWl5ZMN9)yV{G*ydb%&F(Aw2}eNW^sAJ=jdEe!Og2~ zx7H$*{>|2z{LkvZ_0?4lupp)Tv*n|yo}h?@dZk3#xh4^>R^*Bc=Gu@XI*I7CuZ4(K zi_<$H@aVGX@p#DmugsWC8i7@MU2==5FjjL_VjeepxzVSK#pFE6#lz`LM5-m~0j`%T zvdK(3@vlOAK!iE)EZC14E9Wukhq%HCpi(*= zjvJAZ#vZE4L_wL;DD6h+{%2p#qtit%nCY{oC4uO#hO?o7M=Ju zgXYv{xrRQk;`$$t1XH;Wd3(oXPfNZT>;QI>GB8lk;K|6s(GsP^5tTMw9ST~Wx0PHc zs_7hG9FCQdu^`Ip#Y;a0#szY18nM7Y@-|t#3(In7WPE!Q)QE#bG6|$VE~jdF4+(!j z8Jrel2&BZOy==n;fnro@_6GbnK;FLYaHW^w7QrfVm~3JYRv}u;X}7xvG=?JO5#TR1 zZbq!TgZU-O=I1!L7r&j7aR23%`SDheY-=sO8Iwzk1Mi7YK{0e z21M$vE`fB7<^9Sw<7v{BTAQ|lQeCp2X~AK$YZ~>XLJ0#9A7iqj24rIGLHR@iCs0P~p&hYwo58eZ9XomYOh;$tMkeI9^N^hO9NSXqGL{ z!ANJf(Y})aCPhUtG&nn(aDTR9BBpe}&K!Vfv0T)c5-jO-yd$>KX_H>~?)!5yU!GTv zu7z)Z*_u|RrDiMk`HjsXJ_8y5mUKU6G2{8xN7LI(d;^w~ zH^%(K^dcGS=Xir(@l0+w%*nH$+s*Y|V}Vfbh-$fl)BP|B(cWUMG`6n>=GOhWDYhWN z$VAaq_+(dHXPHtXt&ml)_Fju}OUxDDo#&ZiDNk>%;zp}adR|_h`OPMJ$z}c9@zJmR zHL8#8rj&Bx=e#vLuALX-{yLKeyGh;FOY^SeYK4H_!k^Oq#FOr3UK^7ky9nJ~RD--8D!C!DWEDYy&1by4wE*28K zmxLk%?5_kN=4}+RZ)#(Eox zLL-+alqX5M&*WCx`$Z~S+RKIic7Y__uLgZ&zv#u0HyXj|ULJN-AU zJ=Y!W9TY^bphza8$>`q6Od7PtkpD2A@Nlz|n`1-Fe+D0Y>l6AAY;W%nEw9=vArTW3 zpUJ>s3sE?kD<7o1pt&gL5^l(nK|vOn(VD5y=?LX0&UB19gmPJHVVrP-+QhsG_7^1b zs*7#sjIqz|{Vj&)uWWHa6%N#Y?VgGdw^_Z$XY?2CXQb8-1-%gXiX_gFprE6RL}4?< z$#{Ev!y4~j5`EKEimxB#pf&$CC3)o<<}cc0v)miAuX(eDTmSVAx3B-j=&U*^HN(g2 zK_S_8o&H?C&9aem5AW)4%r`Cwa4c|ia4go)amwEYFzmU|gudZKJMr2VYGmq!rU<-4 zLKCN@zHcQEFX1^ZIgDTQ{eBXR260`;{&9GNqA8YHuH%JI&Zd-4F)sy&nuV`!mr*TO zMJGaoBEsJm@cvi1*JarcXF1zRV1=W)zp_EJ2itR|s|3bC-Jq>O*+9(#jp~NDd*l4^ z9(cS1>6UqZ&?wUbEk&BAr2Zk0a-CW zzeAd+{xtFQJ3>6`PJs9KdRT~3)#4`apI)4#1RED$jGNfJnE4V&%Swjw<1u9x3LuQ( zmOK90zBwQ&Rco|0nFo~=qf$~``w0ei_bGz5in!WtnkE{r9xwzKQcl1x^ym)pzrIuysx`GmXXP z7uEvkJB}h*2cdG9KVRMRMH^G*z*3>8YNMyiv~bS#7K1h2m6UeNq8B*l_fLu6(xuKvcPyJd|ZFP+siR~^uKAS zpP;o5Rtvw^0li7oHy3My{x6(Tunj~Fn7DZCHGSj~NXV@&r%5ip;vU^A-PfVAcs8{% z6$oT&R}uRL|JLa}c>kp^oo5{mp@txa|H{H@lk}2C%?7HkC6mmIPEN0C$*%OOQKK4^CK4yhs3%9kuP|6F8g*668A5jAf zic~6ZvN6ux-hqTS-b$v`(acyK2$XEsK_m+MMHpj6|0QG-1eu#~VEnpXjoC;a7qIA1 z$^;5zmK7G*EpdhkxD9K`iY{36$8ZVJ{_fHL=xjIll2|4(lxOa)o$ID&){9Rl8KS0D zYyYCUC6?7xuQ|mF76kSr>nB-Ps!$uBNE6klMhuGJs>MLs>WJQk91RBMWdD}d7%%V) zj$5t)R1S=(YrNon@3S&GaBn)qr27$1JZ6r|>E+>}g_>vp2W_wSAlM<~xYIlcyuHGbas-39I(yGuUvLPP#{} zoHRT;xyO9s`QaR`Ml>~h2Jn5WTOaiRab zhkM1&=pugygbaf|dTxOSFd^(c4xz`6f(&X>#K}9dK3#Ufvf10W|HbFVaEOcGPkIyW z?_+`-N4N8iL%lhhyYqGU3NGUJ6~{m+og-;)MEc?#(bvDmnWVxL(et8Ei1kT<*SEJP z18d^Cg+rgf{obLxqA1Lcj*CUcit`P7T#xw8Li%V3FAa&3S}?r3+qLP-xp+4FfmrQE zg~6_vT5>jl`M_z506yle##1C_e`zdlWFj@=3YRH^suGYoi~oMi3JLs<#YHgX^H%K|NZJ=~C?Q@vbDqbmoSlG><(7D}d4!%-`-!pCiqb~RUXe$& z`(l+!-SHjzPA94fi?LMPVKn?)McMQlIB+H<+7^zVh9k_Y_CJtz5!7?iKq6 zVKPoH+RV>=zY zW7|f@wmPaWAO{W+&F=Z-U;?fxKk0Cg0X1SZ&=>%eZP|5M6rexKrY?|xjYSILp5drm2w?C zop|V0Li)RZL#tPmvmx+~=&RHwKLnYcdrYBnveKO<+_8=OG-BSVRI6yn2v0!?&>Qmq z{cCsb2NM+b$!73`eYs7P0~aHfa}TH_OIAz}lKBsydVv*JRUs6I;(<}4XO;H#3A#w~BG=5HwY95O|Dfs$tCa=~bi+Ot7&=rT#`nR~9ADgn zDV626jeY=t+vxw3nNWm9ea~2{=XC*IK40sB%SVIui;(ym_CYN$OQhFX5kqh3keP?5 z-r)-nzVXgLSPNkj#bM{@W2;EiPXcIb3dXZB%O=zy>CgZ;IKw{UC8;A;G&oU`Q|>^OXxi;f zq9tUgWn$3=z}g?c)L@rcoU*Plw=Rwy##zJ(T=TIKRGu%Vl8P~emGmz!+(hTMjHC2_^rT<56%=Sd*hLOt*9x-eE zT&DbAji4q_z~xZ}JS&LUD@9E-O<+Vhk)K`@04E8!UIkkGf(Y zM5^L)P`4nf#LDDJIk671Is}02{b)g;TlzwztoHV}4n&OU+2Q{S0l*&tl)^#fS*5;_ zJuP4Zss@!Dzl#Jc-x?=)fkm3{B0(cye_PSzCS?HAp8Hl~u>h&mD+5+w`MVII$-~MH zI9(hROtFiJ7oN(o+E`<>9@Q^|t`6!dFtg%qgdsNf!+bL@DQb5G?@vwdNS zvPDbB-(1PyX+f7ys-7HPY$yqTzs-#1V9|N4m4wu3;Gn1F9A5J8 zSl!L>ba5}!PU7T*!vbnc`bWGv#Oe;2Eg#|lnpw2}!}we~ZCOFfz+b-Xg<=ziKW$#o zRNlPvR5`70vhqFGlu2vEd*lwOxIDj}Tk=WN*sHZUkLTcreVpg;)?BNXB*Mpj@kT=8 z`lM@}Q+#g;=1L%C<_#ZgEQ9tN05+3SuVT@34QBo;ju4F8KRX zU2+`ZPl{7ywuN9Gc*n_;3}mV8AEqRJIXa>##MJYK22b(3v3rwwN#&a}tRKAxWMqbI zi)io*v3CNT`Ae6@>_;}WI2$8($r_o*mDdr<1LKKR!$Wh`IEae;iC5IEE;uik&cdET znE5B|`A}qKkeRcbU+kM@2*5nEjBht~Wts!A4!4optCi{*4Id?Dlg)X2_0p$U#giUK zV-iPII;n4m9va3a7_#3C3>KqD)NR_Vvp?MzTTzG~PAhbMj!D2k%x1H~uDV>#pz=Z!!)FlQS%B34=sJlzpS-bKOkm0R(2d(l3%fm> zAd(_C;aN@c+RP-``PFfY#L~W;p^Q{X$#h7?J3@A)hG#KDspA0b$WEwhGrGpJM;R{T zTf{#X!~hF(;ke_UxX|o^l}^b!9{65w+%ChoCmYQpwyvfmZoF6PxX^7w!P{>Hjp_)~ zJRkqR%MtN*SorBIWbVDd`D%FA3uZj+{ugTzYD|uwA)b!gNpj@De~i?ur{TeA=T#=1 z$6ULN5Rb=KV!~tF-^2Z2O0YBi`8$O{Q8{IlZpM{-9{M=Hi#OXGB!+&;b!H7P?Cw2w zZwOho7Su}-3dCCNfZ^pjx!it-5&iOwRg9^X{)xTJB)swBj@EmRB@1_g%D{1eu1`% zE^hI30(*-h;6r~K^^h2HtPh$!kWbxbk5NS`dKhs`q7whuLfXXI%d z)+|MC1%if`7T^OfmMF&N?fX3_g-aNa-2Z&@uW0~6bXNSNCf>sGj0tbOQ?5kP9JH)Q zLEVS$PSUW8_H8juxszrH!8EVv+x2D;#oaSoszM6!&!kPYXFthzz05+{vAZ{3_4v7p zf^~#pyWXI^#?81q`Pc=Buefuxd(XOI1J@?&DZMVFs21@|M#p6~!&K#}T0JUvG3DK< z>;T+xaOlg8_7nT?F8W_PCXV~*EGHlV$?6~9`Pct%hu6h0=$SHRm2uHSh5FY9b#mPM zHll;bc4Ti`>9A!|(Up7U0>oo!8aS+goOXvO_j5TH!wwb3V{-KcAp!)(M6YxFlKI5R zA5Pyk7bx%6pEh$qhlngO1Gq<+1Dw2l&jMX$ zy24~QH9x@l1fGxZ%M=s%cA>$ASCipUWUN2^QR_nBcCKSf0ktmDvZS39E2@h4fK$Xi zCQAZ4z3!P@T=+dK_VwZZSS%7TFioj`f}>d~mx$`Kt&l$>!@ugO21sUUS{PI)j)kca za>yonWG*&>RQcv3KIq>5QC<>F{hpBbPJl7(YKc_u$`~g&iNcV6E7S@WX;R?Fd z$Z$}vEz}rSwEtz3g&N4Np^?U@dSPLePwSd13w8y;eIa^LKCi-=OcKt7FJ5u|s*_ipp)}lj2SDQ8_>@&LY1bcI5rd-bf z!RZ7EGdRAko=-a1ybZI-t-ZBCl#;AnKC@vv*N1wWe|n&d;Ej{z2KSL%jAN5PK?SgE zT?c_eL4g?jezUUFSegxc!+5IA$_J+(VcpL!37!?CY))$kqWlS_(JV?ErNvk3$qcKnAP)xTFZt35K; z=&ScZ?RJUq7n|HtJ*#ZzSyv#}&VPc^={&-pDT3N;Jz6Fm3FYLM`E=KED;Z(NZoikz zbp|3_S|qhMY>?1bBf0|7&E=4arGe>ZYtA>sFmXQ#TNWNY4PH!Bu9=WCX;eBp9f|2l zqKLhvawo$rl-c|W?osM>;;h~g$HuM)xu2z4A@`+59wIQ1d}s9^Rjf@DO_w(Jz{KjP zNooZR_q|^oR=p*#GC+$C@X!_pb-dvw2WGu+!%eGk#pX!ShvS=mB24rY4Dh(eDf4ui zMgy8gtoW2&0hE5R8rPXhO0K`ghHSKHc%MHpeI67u(vub@?`nc$d2AL-~j8 zzNC#IPq-j$+jrS#iq>&I?XCcwE9a|+(k5}_mLot)+ji8Zj8g!$?)eRGJiW_k6~QjQ z{{dXK(k((zf;`~^F88F9V-fko-xC4wWAm(%Y7~s<=?wKlS?pXcUj6xNJ6o9WKqUAo zJdMQj9YbD5(4!0h3nBzSz)S+Tbi%O#$`}w0bYMHM zmOe?VmVr~9_g`b(LjB;Ioc;XG*hmx_FWNj(&n1A%{MTRGMsn!EmTDCpWNme12{w~MfmZ8ZF7XmjR8AOXYm~HQ906ai1n)7yXIQ!&su&b%)B6_ z%pZ!nU5DSz#0Y^pz$%f##)|?ljenFVAn(uj6c`84Yy6Fn?b2h*^zwcx*C|uDyODGm z+SN7A0z50wMG4v1QVVTQ7h z9jnMU&jwHI5!n$-VP#rJ7yv5%3j<)bFf8x*Jub`lxY58%=idaK2S7lD_`;Kd-*^M_ z8*f0U*MA4J@J;FQfMbRHKHU(op>vpelRAKJ{cn1(fcxF9jQ-~L82Yh#enZ%i%;iLf zeY+L*eWt(As>UW|DMm*GN3i8O*{6$@lEJVTxg#Tq4f=bsFY1j{fpnT|)ndTFFXrz- z8j68ka?ZuXVsbO*oa4+Tq7oQuHGvI zO@z&+)A=%1CDX`uq}6+W45E{z%+b{F%sY5Fa|@ffk{5t>U1B;NdIIpq0PyFxW&t9( zxuRUB3D$We6}uCI`^z}s_rjxdr%+$gYjj`#dTDWJ7+cNE(QS@S{&%r9uNMn0q12j^ zY{ceb9(M<=urmAn4C$gvDP@_=g`%ZAHjTUEn6-$7|13(Z|;saRZ zxMC>)CNKj_=zMR78#Gu=A!&AQ3uqE_aOmCckN)z` z@$j=)F3UO;;8g6HHY|#ZjZGz1U{=Y((0PxeyY2}ANL)f!o6JQv+ME6gPV);*Bfe57 zH6E-s;@rQroczG^o-OroZKKaBQ>DzL46`_z`U9ruf4<&2Ug|=I)(Rk*08Ay!mr7#g z0h$UxUk@&s?so(XI$Un4QZZ>V%i?D3rQenCl2^0`pT{7Gpa zutE{&w9)`(W8+Us$Knhbz7l`|3@f4Tl9f#jBI(av3h&z!diz6Ia*w@6@=}p-0RYD~ zU@~K@qR_b5a9D1hTev&l$D1G*z}Qr%%Hlj;D0RGl=7LXHFP(yxJ5-F}>EBwlhU9Foi@&wDj~98c!-(eVpz46UO)Tz z7j?|zd{$POr6jIoo!xyoMkdo`R*m>G?wK?Ka_;R4zCfcsMakMm4*79oqs#l-RK{Tb z+>`HUtIiZSWX2B!6qJJPk?n%tPGom<^2d8GK0ZS){EPcSdxPN-@at~*Ruo}xn^8F7 zDgU)MG%DN^9$8v!p0Si7!ly>!-7Lm&r#?SaN=i@>>h?q5T_;6%4&oI~f{c#1(&ryr zA{>5xTaSlA@@IJ6G?_oRw^{GZ&P0=Gtw}Qk!LTp$qC?a?9c;$aDFD~1cNrnxp9rFJ zVma^95I&BF6}cAcPa}}exLmlTPlmRGb0q{JlD_$x-7#2njhXDeXdjH1{7Nz#dkq5q zAj-7{;H7Y{_&67^C*|&Oc(z?tx#HSnrC;UTAnCvsbWKvoAWmjK3L$^xfJ+{ zKZ0OaiKRh+;LX&wX#oN%*<>C#tePV}_;Eg>PSR9UYL#_nh;m6TKdnYv_Rt4w;NQQp z;aeqVAGD+%Rodr~de-$y!*+mv%Ma_L?L2W9XiC|SoD(AZj?TN;8dpdd3IE)b>VG3t zo{VK9*7m9bZfPVv6>~ep9qvXQJ?uwkme!Bx*H4Xo!VGZbg!BVHAcrdw)ucntACI} z@`tIantHpB*vb6-=W$Z070q$YkfNse6>d0u4-@j^7izj5S$%GHJ>50#<2F*yp#)zf zK|y|u{GIf+FGN>9^tPJNZ|<0A^r{0WTO95OjngZ#{N$;4E4DWb+{rg_u`dt0#FBr9 zH#@nY^t&DpG0+J{{XxY_eY^3syX99KUTi+1q`N*%vVKtu{abIPHb1BDFR?g~Cn6=@ zG{+aW?RZGmmNl6_Z)PNrUztI1*!b)I+nm75^ZG{6$J81~Gme<)w*5=vuVA@9t|=|R zBu7lE506*ytK)iZ*y+JyU8~DzlyJ!cWjE?wKx8I?p&k|`fJUcoO6YXb?I(CptKBU2 z>q#o51A(;|cK!S78%w0_JgyC2_h8UM^Ve^lkk4xVWLm8Vp@2x#TR3>y(JoA1PWEEQ z=DU&-!yl-q{q)f-_IoxDQs&+jo-Bo}1^QfZAow;Ne-cri39eO}{{(CHATox*C|y7( z_qF;o4GYhdD-Su``zihUA z36;@r?D`=l`eBsrkL({i^Ak7TT^eDiVrxP}>ZBdnc3!KR|Cih&UV@Q>CoF>P zz*A`aOcQ;S-QM%=cn*UCd%h@qzmW_^N`8e#dvdP%txYq^MT$%gj=8-^4yhW%?#2KL zT%vZj&+jUSe`cmd6doBdP)0C+HQQ}6pGkG_?>XSV?2^!U(&$3vcBgNcp$mc@R87o# zBN>Pu8_*ni#HM!6{0Yd&4iiLd#{wZ%CxKo5t)appnYoAP-I!`Db$#mTh7%Xj%z@W` zk)Hme^!TWxC&e+7P**>VI$!Y&!>b@#2qDM%eDzEr3D$+>V>1Pxf1OcO2!(8GZjxR$ z{GC}H+f2&c!GSxwL<5b&*&C^M+7NsTymXDDZ;ioHW4-n?%2m@;iGwoHz5wMFYtoC& zJd)z(DmW3`!WWu@OdnN2VK=em>uYMUQrD_-=XfwSxaxdcg;g#hs{@#4-#N?#8BNRE z=UOk*ne(A^1BXJn8Z|vL)7?M!uBbl)m;$=qpKTQo)dP`OmNhGos36S7RdI6s9_c3a z(7_rdMKTuQqO5B}_Y7nH;UL9qS>5fAA~W4QI1j7Tax+Ic9YS9 zw5R`wv{%8DU_X%6Nd!h<5qvA^10YUHmQ1Sg?Gn0QR+U)1hfrK}Y!g%EdjnpK*)ZsV zpUW9aXX<`=gTxCc4gSVpMOq+^J!r9+&?uGwnjp8Dlyi@{=}9thES4W+Mo zGgmmylxbGIiG_uZi#w4hq(Y+tQ1OOybWP{*+d@m7jJDYO)^Td9dIbSAjz+X!6abcM zD8L;it}OkR*l8kV7!15W*@IPgXbB8=d}i=+eAA9~B;@^Dyl*7^UMk~PoM|?Xaj?)`m1 zEaN0DK!)(@S2|A;AKN1MHy1hg$~jev`~$ym7*HX7<9T1+$90V}zDoHv_SsAdw&~mY zokIpTW0ArAT+>3AypWgOfc?sKg z-!x1-{zP)4)533Fnrh-FiGP<+N8~v7|CKX*m5Mpbhyk5Q4N-ONZICX^`WUH?1>0a@ zxH7om#r#=e@N1%MNak-Y8z5Ou7)+-mEd%gl#<&2kk3i)^`d9luw*k4NZWV5N8uN)iOj(6qV*0E zAQL?U%N(nEk>6FnJ8f?6w)x(zXU1agP+-Ks=AW+zF}r?>&Hanq>wgGIH#wWH!(b=X zXNb=GC5U66oZDS{3AYdIP)8mXXv@G6Q5+AMLe#_l+9Czd9ia0q4AeN+Nfv#Ud`VY-(2Y#DvEGvsS0?q{lLIfyIKr_yMe`v=Hh<3d~ zxPj~YbR@voL1|`T03K}%)^|Z**ECE3Uux9|HFN%db{Y;X zZG7N7bqYJUD-`rfdTeT@RWIN7NRjY1!t(Q&_20zi%b68*ZBBYR(lQjzdIcY{GHUJA z`C1Xm@`StSnIGTF)CDD=KRW0e!N|XF2!1#sbClj|4CoERkf2RYoOrRWV;EJY19q-e^0(lC+^}18&T@NG+mITOK0T-`Y=8;PH{)A%#G>mvEGEECYC{y7 z6aYRl4+i`IG>OVzzB|j~-}{Y~lo9_O)ORJ$Jh2F)v7keoqc){Fz%XNJyE>NTL-g`tUjMe)S-8x!lwpWM{Ac z0&3X_{FFRvbjkyNFJXBa)xM0KAXAA1gOa6=#htcNnZAB)LsK|-yv~i)WY0bQ1*7Tb zZhNDt>BKPS@JE##Q5B(Zw`)^XL?xh_8tt~2>lf_2JsG7Ml1i)J`@Qh633SG+?d#7~ z$3w3GJ68lC^Nx)I^yDb=yMJr0$AcPD=5M9-iWlpgJjZWu8MEB5YDx>iQgr5$<#D?U zYz@j0;inrW&gLuehAdw_3aJaj>C$Z~P=Nl4PJze)oQ1vpMnuV`jbUskB*n$#UgDuAz-i%ELHexqsN_LA zyn_CNiCeAYVF{+i3KIQJwNIUS)ZCr!GJEMH_GHB=^x#m?7|oMlL)S9|bPmYZ8k_d|~M6C`5 zJSWGfy{Up4&rX3XUd>)6VKzL7!*2eZ(AYr6H1z;v71CTGH~8X~m{WSQ_Be-m$vtBF z&XfNodGtgo$G6Jo8LmvO1gTYyg!M0Jw*o~NsEyaZNhJdEFtwa*oX}?2_6osRNuAu(yKP^gAf!e@FNjJeuk2L$El%~>m5kG8oGfp~?c@5mG1%0$o; zzfv`u4UeC8zd0CsAx=ogy>LU#c9X=+7*iVaoT6Pt96F=!4k%jhqDC56mxzw|H-0Q` zQmQ?Wgui^;<9V{>kTq4(w9;k%X3SVu{jAUkJ$nU_HES`>P~hc-+uWDO13ET~Csy=k zjqqPT@u!@~_?jbAI^=}G@qsw8@>GnU8c6m@0yFbz4gTR80{Go7*1uez3m^EJNjb5a zonw=0r6sNX!F<`+Y=^(zWr(o$B8_ra0l=O$N6aHssKzAV}qIX^L;SY~skNUM1 ziaWKJs2x-0b=clQgO-!C1QrPOIyxZhS9t7)eLNaGz@QZ9-K0^mPSSus+<0qY5ijGUNUj`Kko{v!;YxtRU z!G5X5{;pa>qj5H9!uvmrlXq^L9ekIK`g$Q($r~yb#pJ?7gO7fAf9e&=yPpsdt==l} z+yo-+kc~ohXU=9f@U_7!{AqJiSv?)MmDK9RLHvyQW7UP_5CkdY-{Br5bvdH--m{6$ zisiq)d@CBT3g>?Uxq{{!gk=Wj(7H1~V1_qi(BW|K_gZm~eX;n41@E@w)4h?=Woi4I9khi05t0GH{ zEbFO8A#U$hYElnL#;v?3BXBH(M6Z`WApuf2`(DOEuCRw09wCMoE>T&*siB!HL{;iP zI8a7`GyDA&DVnRg3WY!`xL)S7WbR92sCk5-1(Ho#KaO^}91K`OLfdsI991B`xIk$) zfWCusz#R*vmp*JP7#1`2X@Ax_3t-xzLDB`En~po*t(l zcNZkn`kO1V83KtxV0U-HreI_kr;w8jtkawEX_3lFIZDD23^%{qke|-8VwTw;C)8=k zijg6Q+jt-duM;oAas-os=5u=7>VF6dN_!mg1&#yr%~7A@Kbx&UD3wikT6};R>v7lU zSa2eGm3+wi-nayxTBp&68q&!t=`4dm+HeruENS34KUpVhFYY|~K|m0|v*49{#lWy6 zzx}I?X1W2|(+^Fb4=5gsF8pCP)-SeSlC;lGs_e4|%CBhwMy7@Af)FUc^cUKEr25j$|ebc!dLb>T{D{ zrH1P5E%5eA_N2r><>04izmaGMj&#&<|ME&R)cba~y|N#4);~A&IChfVb#QlNKJ>3B z9;NoWpz4??&o0H+^Ilt+xgKd3VLH?}mVtrSBZ;V? zCwBhNzfdp%@CphnY*A2bGojc~o#bCzu3Pm8j-lqo>z+sJ?HD=ZoTg*hyq1p@8lD#` zTaC?*wND*4bXq^&1?>q$7i?C1-L4C4L;`Z6m_A}f>%&~rk#c@6C6cKQDhUC5H<_}~ ztkXtjOSMcKnyxe)t`?huua)d%7sgZX8@j6>@jZ*okIj5xu5i>Anh!@`4g*0EdqBNS zF0t0OgjXdnG8*m!cU~k1!ufM#t(-w2Y|6b5Oq)N^sa+Yyq?m4@6o#`K= z@Ug7ezR_DbbjF&OISNJXEQSH~fK`lnPM+fnD6jf7-l_J&znz~h&E|7>pXOh3f8DH3 zxd%4ecZaLVz;t4$jsn=f#Smv{;I7b?P>DFwYWkgV1MJ>Qt@x-_~DVPJ^d=`*ReReY8DPQ@3?yb2Iu0q?s zpKzcCG1pW%%+=wqazNQpWP`x2L@HzzW<#T+mbGnMvDBIvdDj?XbEEAsCNOuoyDDC2 zJv|lv!9Zqjyt{}T`l`N3zA;s@O}bahq;44U&K2!quHTxFI0y0y{D!!gRsj(o z+fg`Mh;&$QOeSNdQ_2F;{7t1DLHNzWOyH-cY@;>3HGh=cD&xG+kK?06`m?(s-+S%I z$M(38vTR9%({YhO&@R=St;l5o&l#ZV>KP53V`z>!VZFnOPQjndNGRd>_0E zgO|Gp>}%|iYGB)v+p{s-6V`3k8By%(kh16>SBPhTqc~mAP5Fc6^kXKWHj8kVj07lf4)O$&mWoth56^*5!z^2B3U ztW08sJB%F4C!u2dlN$;YHOtTUz`G-5yGQ%Y#pt&H{?wH!lM{O+i=mLxQVjD%*)iEn zzxRU<@cJq11Dsb0Pk1b8`Ks`Yl2=r@M#|KrD(R#0>NsUEslY%?(rWwbNOYdj#!i`j z32+!nGOs*X@Q&_Sk>7YxAnGfcq2zFf=fhhAJAmL}Jbn%HZ^6D+*CoV!1%x4dK_Q^f z0`al4Qzc5K4}r4wko~F4u3#T|_>1qCF-h%~O`;6+gX8oN`e5T&QZVlQe7rgsU1KvI z&WEysZdlZ(#@*Msc?n(jgui!Q2)CN(2UNuaORIAIXWp+g9c!(WKu7=XY~>slleT2g zVO%e0)Cphii%}-}^`&C(5Pv80wF3>vkV7QrMzIaA<~_MuL~HB3Q)iuUfq18ELTy4- zKT(q^Ld?BH5zc5nzunXLMFb8L6z-hc)6&3}S2S}C;fK-$w;jxU?hw;pduam(X$;7iheS@)Vy@$q`)yd+k;XQ6G{qKk#5_i zR3$X$J_ieQt`0bbbn#R@@vGqdi7V^f_sF=l3L24E8=iV za0Zv_cVqy5>D6V0`i<0&*-O$ZKC6OHcZ?f`1GY^l=b5Gk6;AJmXaYT|9;?QN86*PJ z^8&bSaSzKjzx41%K?8!`?rjkIpjYWj%OO$nY_m z9pBa%Bm^_q1=E4mPFzsx2}mg}fMhno4ycCMlwf)B7Pn|I^!BzPkj2I4UVHWKDuh{i zs1ZT;2MilA1h3qX010T@#cEmE33+)Mt8Z!tc zuMeuV6W}@X;N;91+OpkVTQf9H&E-}9@LMe#PK>!R_GE4>{B7Vk5haqvN-roS(e%xj zaz#YbTStArVh~MBCuL}g-gW`FizO>h^7Jhc zGIU2j0b*eY{_Pl`w1Mg_l+?nQqHP==3u` ziIBL>`@XqXB!9wbZ7Qnsqw0Y<`cHOpOMsPV%^Fes-yGeru5_`OEepfY!lJWK?Z#!g zs`BZlhSwUt*nM!3L(1~_X7dtEm5jevUN>mG@Sv{3G4P~)(rcm4fVHHFaZzop;J2E8 z_|5Q#kX-_mDxRXaGr>E54JEVBY!0m#6v~t@+y>|4=vefT>NAOl49o-SyRGT^uOyOkuy<@tk*C#R)t?%zoS$oUaBu@PA!B9_MGDZ}e90hTq5 zKKa_9{c3l0Jogy$&L3u@eVIMfhQ$WbY~&i&y6$U8HV)dU#Rj$cuK_)dtvBP6T!jR; zKsurXRf0RP-L#WK3DV!=Ma0dYUwij8Z}FSfp5morea=$caxF(S8<} zM!czE(9(`g^o%!rL^hN()F8`^{%(zPrTXBE})QnPw(7 z^Ghnru$@8K=?&`f(`Hra;D;D(UPXs7UsV-yzRfR`Ha(+IvOT)rnx4H);?DQZH`wBH z0_~@-q<;!@F9DBEd0cqq`3Fn(e4oKqxGpjsP#w^RB|moMhoutw>F=lM<@ba3lIj86 z1KtgOK@0GpUDV3&;;9C%_HVNUJWbom7ch>$FJuevCahu`{d(I0(E)K<3(pkH}XTS*5^h zgtw!4u8A{LgnzK4IKV?AhISh)cc{fknZ(|HH^L-Ecfzsft#*7G zg+o}+;SaF9IgY@ZX4B#|zU=Tbrw`$?X{v+wd0!5(%m5# zL!m9J*bZll`iW46^J=9|=liY^Z(s_^e#y=9>_SO7GAwk%Ll*K6+yglSdN-OT_^u?E zFJXIoTJEslD)+sa|C5A6;-9{ryE#ZEwz8da6&gZ|Rm&1-its*TE#QKw;Y)lD#{X>mWGf zt>Nzbh&5cY)yM!~pQ|R%K!DMN>(V_F*)V(CkEwj@g3%5hXa+t7tT|WsqZgo|K${*V zup*}vquSE+6T~XRxHeyR&IOjSt+4V9Ig*)b)>+rNtmVKhKAw7>GyJjMT%C=;m$tmL z+^8&clY6{}kQ<@)cfcme`plMahP=ytE#5o7~#Rjd8#-7)Xkzhmyx(mms7_niYK)Et|$ zt3oL_SdqvEm-M1QUkeX(--dQXr)rU-L?4=~@Yi)J^sh^pU_Y#YBU_N^Y-Ouq3q_B{ zJN3$nrB|9Pv0s6^Az?61qUsCPCAD8}eZsxL^Ep#^Pa_6Ojup*(?5s&@V8#_6*4Ml z6%X+G;T7d;AG1$yvk6!hkiN zcA&7j7gNvnrxM)*;+RHlL-km0L}Un=DsW%D)A31i7)DP zHz-bIeo?21mxNeE&v37%TQzQQr`sxf+;>l~SzNM((U={u5El}Qfs*`@Y?qLR#$I(t zm=PyFJ89s1q_5OXjA$bayn747m;ib26ml2TBSP?#%jkaeix^AAZQVVHqmO^no8C=M z0ui zRx47{qHPZt{m3}Qc2cgU%GYZa`D+pOB#p$p|Ai&6cNJ?zZOV^bu^@^^byJyCOhXNKMz;?40!=)5HqkE&f9%nr z1zr3n_C?ix6pUi{YWm&p>C7|}zdq7D~&!U*t2 zS{z(|PyzZMA(ruyyrzp?zN<7=_UB*&h5r3u0|u)Cbi+{rkRw6)v?|))^LD#%V{f}> zzL4wB`V#ZN@**S>zN)ebo7UciIRnU}H{v1K__WvqcMCV~rZ#0*hTljp)(#%n>@6~A6H=|cL#MAeHZ zvwORoLaE$sL!Y61&vVptJikCwLn1_gjGT!0xAyL+k7J8)kJG`g+JcY~!r*EqI_l4#wG4hIMZn zA0|WUWL`ymK%aul4GzAEOz>5=OfXFe^HwEQQESqjv>lfvdi6&cH*(d~mCv?cWZt`H z8u)0#LMW3>`LLSTn~c{x`E{MZBw{42`+BkC1;K*&e~`n=+tJP@j!r{bU+((2+b=Zf zYWcAFk~A92NDd$35w%H$+BWH2pM_@AEJMXSU_QLGYCH?uER;jA$f9QV)O1cSn*EU5 z2DM2)79FqXo^r8|azF{)1>D6Y6i2uRBke}bc*)L24E!5mOJ9f5vj;BXFSfT?>{-37 znpiR%v4JcL>kGkAdG+IwLYRw0gD;~NLGMIPs93#Hs2%d6Ti*p0;2-i}wm0{sv29oE z;=`$Dzm!C4u0@Z>(&F}P*`2p+Hf__GS*HFao%YM~U%jPi|2-cY0iQQ%##T)Ryv zuU@sd^e!I5UygC9eRLj#AZLPIG zEfjDkelZZueE(W|Sp-cTSIl-&ycw@gB&vi6Jn`iTZg;gv4Ur6^0|j4;Uz;fzi`UHC z>v$?Mv@iJ(xE$n@e-3!}QuYWYa@5hCEj`?n=W+P$4yR71p}pIH)M*PGjWSi^aqgU9 zh@9sx8{ndF+nHh@T zot?#x1q8lywE2L-h^A=uMbm;P?y5~QMn32t^-ui_gn}QwW#0+i;2a>K8*IbxV*5T~ z1SE7+qLe=I-vyD{?^;Q1RcLke_fZs}RuZ8Qp}YT`&(VD6a}{ShmV1CBqG!&nIBzg3!yzBiJB+)9K#84>drodhP0WA;Z&~`++n03!Lr*7e#{MyPrn)rGprF=2 zRP5!Cf(tfR5~*j&BcAJLgL4NaH)X2r`1Bf_r+q%rY{&`=hK_Zf>+y66-#*n$4nAa> zLQppKwT&8SGrsF3&-I;o^_6b?y67H%|F-mT`XT9IvpW1+3J?GL7xVDY!THZIUKbZk zOf$GRQn9TkGiLg@OL}o*Jr`=2zR=JxK45em3R_fVXeHCM>r6F5)2_#Adc17%j_I&Q z&(_hyq1+5=c>-Uk->Pa`nakvyjevrtBmdcnB?_)`i=Lql zEs=6)L?Hrd6iy2Ok!?L0<)8NEZ%hKHDa|XaCsUg%j#g>AQui5n<|`J`3kbB?K*Ki>LJ_HP9X;&KO8x zb=AZrz_LW@nz${Ae>t(^;O1x+7MmrligS)%C7bm#O4evSk{(<{3VKhC9S%a>8Rbx2@b7FjlbvrZcus%=6=!r$*kT@GD| z%cX68%aB%BQLp&p(Od76n%3Eb6l-j!PmJW^dJIQ0hF4UOFLeiqOk7C2ka-lo%-s&u z?}=qDGZ)9Xz(EanALjqkbPel_J55SCW#`|X<~LxrEE4*Bv(dia3hV&#Wl=sCyCrDl z@Ll(3AY$DDt2t*kj>8Kv%ZKSv*{%|9vx{F_tTgJh2Z^g^Qm|)#7wx$082mh7+u++- zhR=?M_vPPTzIs^VXX%f)MmloWNJi(S&H)`9C-4{;k@Y6616f+Z=zR-3kQpw-JZL-A zH>R1v*IkmqH_5TIWt&Ir(bGGl zOCl+r5n4s#kb16L0PD1ZdnUu~q zt-61_kB-ELiq(r?G(hf!yA;gWCi#i7R!xbGTj9c^LRoK8(|+ zAk2-|PPY=rtcML(U8|w2IeHD1(tMBykm8B@dQQ=C4n}$H`@UbKzY7iR>-&PkBZ@~} z;8nbo*z!wYCSgl7zcKq0<$$M_W2^R)DFTmwHE5uQ89p@|wN?Dgick>;?egEOo!0Rt z5r1`vhLZtg_@2JiBaHqnA5OSpMz%}v1=|tN&5$pjZUHLLS#9Fhy?Q5x!P*6HCa~rS z;M~+2LoMKkwL5*FR|y~unBMdzq#YxDL+j?^@48#HM5=SgKeqRlPtzQ=Sb=BNMimq`1UU_odCAR6ZQtf4#px80 z!&|iR%R&WSh)46MH{$2>I6v7fD^Kv(oemIB zRmU-XfsBg-b@6|@0I+R-#++#h-gTOe;m-t>>`BD$wnx|X-(2WobsSb!Z&e+zgWe5$jyW1#g!dO6a}sMMj0AxLcv>O>&5QZ3 zL3!HTrWP*?b(j_3l~;LiF$lyCP=QzMC~nlUK<%&bjsU7ndeH`nb?&*!ChQelf^{eS+Ay3LeH~|jxb!x^r11eqe_)TSSsu2Z|JO=eQW#E zY_&@pnl|YxbGAC~*nfW&8R%bffUzOIou^4q&QpFD8~;NYg^RMfU!mP(Ka4s}VkE(1 zKFiJpzN94CnsI!L8h7)JWv(xlXN~$1xSHG#6?0z_Kxt;~{2m{Oza(%F|?jr-6T zvBdTW?1DIwbn-%!lHH<2r5&6Zyho#1R@%PU%TCE}c8;(RFzJU|xb1|whe7!`M8#nn z(sXijZCQqoL{%6&JIRN-&JlmSGEwx_b(tMwrS|<`C*0odT35iaV3-CLg+O~#KP%&! z*H74P!b-yQ;Gbv1d=czA+)?p_r^9xN{&aQM)aRW!?M9jVef*tTenNPJH74zg*Kaok%h&ntrjBWF?`$jrT>#8MyS3z-FwTxbR;?X9(I&iT1qz+w$lVZm`p?y4kMgk`|(Beb4%XWoVv z<^y)GOaovC)I+ExP4Il3)csw+xxSXN&@7n3LLcp<^kqIr2>n46oN!^=-x;JKc1YYc zvmIms>krVuLcvF6l@^HN-Rj(}g~V)cFU*yt!~^_Ji~$)=jFNHr}4h-2G6)*F9Jq&{g-?4bBGSu12X+ zbji8#Ym2G9QSd~@0*Mnt0ch)-w+zhn%39Q zaZcR!k4>KHwUaV|gp+_JLoQV41nHi~17+f`4T`fYstV1>K(nFE2qYvZh3Jol}uT5K?lPLgP?iX!5V<2Xg|9O!4 zWaDmnV}q|I^#QN;Jk$P@zS=~IYB^*%TPr&L^zv_gIHrMFA$>kN0AVEco5f+JKjHn# zf_WHv`&_XGW2=!hhxF|Yj18vr>t=Qpy)aRbE4Bd%T;I_kQkRyFrqVm}o_b2taq?S8 z+wCqT{aZpEVhCG~H2)u)L;Q2MJ?+HxGxLj4db@_9DQ^zEGT-mQ<^V2Ag2&zRe^2lQ zL#Q9J{|0GD6F{99^o+nszgtB(9cqeV^B-@MK97>kImf1F6|DzY>Sr%;NW9Ntp{g?J z^(Ci)DZe6ZZ&5T`1nm**$Jvux=p{aayy&VD^rPo)WnWRBI_kJGF2mtjM%%yF>@B~~ z$XT+@9K5@%ndioSHHbv8gR2WL;wY;*x%@hNug{Nk!=3HglIiYsNOXxInd04M{eGHQ zm|Fym3K^4lg9O`DA05Fp@6gJKVBxbaEx1IR!7@VTU9C2a5FQ}LKT~19X5iKM-7Es& z+;6B7@P#q*Cw8YEPBjA4*iDv@d%97j+*)(IlVcJiNv(*Gfs}#^%dLR0j*8{*;dQLU zw0h}wM=%@b&j(Y{s|2RGJHn0PN^jNjfTpr)LF*xv?+A?bzQ3cQ1U^<#rNT$`{HAc>EX{oA6K1S z-L@nIJ0nECRj?a0(tLM;V&im({~SMNm9Qi`iK3B*CFz)UpWU%g%7EP*+EbQZW} zjK7udpT7=Bjq228>ipX%4-7GJj{}FTf2iP)BKUV#R}$eDK7Cg zE=*rlSD)}I3U(OFxY+2fLvs)-IlSjb^vmk*bOdoiYmnuM)gz<9Zzm%bSzZS$O^r<) zmit1F;t>x^ew+6=u1)(PBOS}1alMXjobjf;375a(aMRd5qtuRJ5fmYGaO#Y3azGHg z@RQL{TOWh17efYOqTKXv+1@(Y}=9T1nmWeqT`SDaoK&Ho3ULb8{sN%L`+bL-B6yd8s>@tH{k1 ztXg+S$qfOF4~z9RyBy&V+^(RG+m3-;6x9f_u4l=Ft}j4r;2wCsLc8p>`r5~ikStp!5xE6-sQiC%^Pk3i2jIMx`#JgE`q-WqUqavKaTu=)PeCg1a?BQzP75p zFA|^UTkoauTHy;d8!K=-$fIH!M#K)`^P(U%VcG|C{(Ncu(I3;s&QM=?`(nP*-W)IF}_L4|_b)_9x-uUKwyX!E!l9l|vX&Lt6|QaBDqYXY3^NfUxmH(j-t zmS8z<8X_^FMj0qtUu~OtkGaKHjMjLKw`~XddZS>tjtTNqQSjMl!9*bEQAQMVY}MVm zav1h3@$~WbZ3kGMsU_Pl%~?&3tV`6S;kaP5&8HdM3Ns{d+m7|GOaHOvdl-N)$?W5S z`M4wBDP=G(2^3s%+%G+S2q5C`JV}gVFLS3EA;!M>UGn=h62_k>%hS$?vN(pMKsakp zo2&7bNyk$Q^pjwDqMP2#Z3AOg4a=gcNn7=_L)4W;r=9LOBCo@FuzUs>l(R84hhldzg90D)*IH@tokUel{Ldy7!=noR|)i`NvLFk;+*y5yL$-@YwXSvV+1fUnUd6!p(9T4<`=~ejLTuP^8=If}N z2UoNPQxwf+>v_uf?0xuy7dihV>>nEloiW^Yk1K+^hO`GMSq)4Ohrx?^Z_Y}k=W+5s zEA_$9kOEoLCU`gj8B3P+*jyLVCabm{&SgF>RxanMUEnYWq-w>xyfTLvb*? zt(hJ&+%Ju^#JGZ-ww9?SB?Oq2DP$?p4`TMBvROAcR@?6+>Dm?#?Ak90p#cTFFgutw z(0$7A=RK~cJAk6Au@%O!wCn-f!$ImBR*DXz%AGvnAF=HQPS9FjrBag^vXRK*DgD7+lFR4$4&%sSM}Pm|ncHry^I3 z63v=^N8w=#Tok-rb>&}eUd4$h$7%x{vt*toU(d@DGQlZCn*TB8$%f*_1}0i-k@U3j zKJ?HK<>SuM)FwvUu}>+ILhQb&X!I0Sl?5^=pJ>BKc~h*&NACp*QlBw%@fD~LW#DO1 zVaRstzZl<)WdM4cI=oC+)^&Y8L{b(^Z8|WRe;4$lc5-exPu$`E1hR|3l4DaSM;-dB z;>##V@y+iBE1{gl@JmOv!rU)M+t7e5<)kvadXU)f^H3%cX`j@1Ufp$R1IgMeI=tnq zXDU4hr%p6&^6NM0 zR^mbEV86(r*7jHG%*bWmGY^_4_TxUDDSg+;e%@X{3v9elYj`c(auvoSf`LBLV7FP6 z^x$B~dAzoaZl2_TGo6;)qIa`ue7)vFdhqCf?Cmq&-s5yrYeZN|kL`ZmjA;M+#{e%BdNYx^#y3cQXH6U?qP#i_cnjh4|=2sjY*>2wM5uTklLxg!E zlL;}RNE)%!p($oB&HBO0ER+u+{!K3RGFQ3Ji`p%T5`&nQDG2X(5k~O`-|O|I_fZbu zK)(eO_{0XI&7uW4P+=sl#k#VjB)|Qn=F_A^Znx{%!a%#_K}WjwJVQo)_8KD?zfBP_? zAJU>9d2jvx{Hm+h@8%L>ak^yV6;*(-ZRGAZpWHXClb8c1v>Y?@oe{H0X96>&*^|Cg z4DDnMy2r^V7XS?2Ml+Q+8{bq^4|5l^&8c0c#nXW#(u4avZ6#6_VKwHfXWN87IjB`- zjs4-ffpXykLI_JQFD4-+{s`gd2cCEAb{a#e8Z7GQJ>{qFvM0Y1v>leh5pS}laxDod zVd$@_pptEMd{IQqR4U-Oa#>=n;G0owWC;foPFdyZamTJO-=X2{hSS%v>Hbv2r}wun z);#@T{cp#+$_9#Go*R<{C+Gfeq(k`z$U|a@y7RRgQxMH`UvZY7O}Gh3a>g*#r6uoD zTym%=)8U#GB z=K=G{WgvTAc`kIod=Ce4BPU-~S96M&gdjiR7fh#X=LraYiG9MaMEdh75d8A{gkO-l ze7a86e$n}UR4QtSP*t=2OR zwz-@&+hTq*%iJ{dDtgt8TAkm?XaP9_a5;7ssTrG{i8XFq+wZzU;1D@==c4(`d<10z zG#0ek;Lzsamd!>!sE=O1pTiFBqm+ zOYsd>9m%TyyMX!f$x3ZmeI#r%jJnB4z|%#Y6v{_>)skDf9SX$WrOcAcBZf(uTpBME z_s0&+*xC`1!c+x-FPHYq7K@`=RJ#FwF^eHeY?WzP?KX z(Dvj8D$-_=MUF7~PxNde-1MgLO?V3G1%REum$?P|px2Xtm(X0~8qQRcML+kYL&A=7 z@wsu9#^=gRGjW?k-A1si`)v_Z5i>W(u`3oMoFc*RfXSoZFEtu;QfPBchE<&&fB%Qs zo9;^sL$>tO4Aa&4azgk=!B5Jtv0Q9WO7hr*2g~80`WF3TBVAmc-`EDB>YC*r<53ZG$yqq8N+Ocn z$&|DSk}kwl)B+?Z6&n+?ojC7=RAY3SBI?UJpUw4E?sZX`xVr@eGR1P6Q&b<%O>S_? z%z?x6F)Pd;s2rm-Da9P5Bh`bN8PXORXCMJESxC^ga4dD#*8}m6v4c@l7O;|s(;8!l zh9$0LtPVLe46Fv{I??FHM_PO++twXWo4UWENUJTZ_-hNU3*b?qUBWq_>yl}hf2_oU z?>_!e|6_qR;L>$lb_2Byj$h5|zJ3V=F=xoV@i5cKRP>{TJk=pC)sMVvz*53z-#29S zc&H>-^+DGBX>J{E{NI;q%y6zs;S_$`5N69c{ z$C6Z>X8{k!dcFsC1z>iBc{Kb#UJ>Llcf>_|+ih8;DQWyZL(_$OVAlz3($nIQJpLw!Pp| z3Gifti-%J}@kz26J&?378B{UT#?r;{{juQVPN*9DR&>T5frLA@*Rrs_UpVCNMobfn z|5T7+J17eYnR>ECe^6xjLTWJ|b}{srqCBn{`1v81h`HK3erd0mbM_gOllPEx#(= zF-15MX2ME)on{FU+$iKQRW;sGXbI4~S|;h@^wKN7nXGz)@6ei#jk$E6ZWVh;aiImW zfCuhs7+>WNDU}m3zLD`&N}32Eg~0I1m`BC>(5H`y?MTXw2jn?Ns#fN|3`-JZq`PQc zes?VnCp-mrQtrhVs+8ReQuLvZz?=B+dX!wLud!#D@2A<;Kg70HarBRK*TU26OgLng zI#S6y-Rn=Jq3-vFTGt;~`V#Z?XcGBq&Wg*a$I<`aOXBqvdW`7y9%hOW8Prr*KeAik zHs6Mv{cRjl;H|1#PEg;wW}v@s$JFe9n>F)=mUWnUv^8@&exFQQGMJ3Et=g`gQhCksjAU zOCepFLc|mUX840c)}Hh8ETs6;Y%MjGn~syUwWm`{s1v{d!v+-Y?8G^l%N2EdNA$r z6k84|%7QOAlGimF2GqwK32z$|QWe=7EMyL6(_xg$v1%R4;D02YHKz{CV6s-YuIIvj zqq@3ej`?}K*BO9ewX2n6cU31HWwzyNOk*XB1VI3Tw=i^-(~Xx3Oi+^l`w@fGk2SD+(6RMZIR_g{Hl}2J>U!1 zi3vV=#@0^j^!^{&s^ssfYKeT;nc}UcE69EAC<@ZJ7SO8!f~M7eFms>S&$-9b355Of zKe1n^>PAlel2E{B#tEiPuM+^me)6B#ufP0aYQ-|Qhkbji;8&~O_(%qIxan<_g|nXo z*e_@|=bp9+Feht$$ah%NvU*$kn3PLy^SkC*6B(^x#S^x6Qi_jeeedyi1Tl+h$*Xmo} z0hoPc5gAnxy1R&S+%eXr)pr4_ChXqXpva^@EKsyJJ$+6 z$lu)gmb%WurKI;#M2LM)ku6ez<6Ub&8_dxJb#e^fpdhRfzM7nkn;MY~g)pmmF&^`_ z3F1XajUFC|1!0-tU59!bj`7=5G4j+eeFp1x)C#&COWWIr0K2Fs$Aj!P?$?o8myI0D zPQnd2fI1!xGwU$5|D)ft5GPvl0Z33o5TX(h1atD7Ei|_#U96`6z7H(|3%wK?B#VR7 zvghMv-Q;>c#nWJm!NeD#90SYpp36_v^=dBvgXiZzBNNG4j*(R+5INT5Lr_4JICVq} zgFrafp9~=esZAl(-R_GuSbmW1ZjO(PHCpg%FNL&y1km#rqA%-P700@xwTg$UUlU%@ zKI#%2w8wC&WX}S`1$dQ6E> z2tz-?7>{Y&?y~e6K^%TBP{^_Ss~nx1MxqGO5lA;9!p&+mEu3LhHwmNKxMEf?>?fq5 zh>&Rl?Wm@;C;Dnp%5FXw(`e4z-zvXJwo$9Un6S*v-OCv!-sDmUxXfoM24GV2;f*Ws zj!?MPH)t|3l>7a_FJt$1Th4?ZE3o#v7DtoPG{omjbXJ${6RG)x0CLU{mh^H=-20wJf@j=Ch<0E~Jb)wEw| zm)(j7`ovuagBPeKk4Lm~Swmom@BvL;v_Uv)_1RUZ@dJld!D+JX{zhQi2|S$HsDt$1 z7WyT!V_A0Bn-f@aPoaj^BJYHZ&&Vq=X*0UZzR?)o7YSL**Bar^97uN6tKI1%UDD^* zuR@ZQ@+F&UCp37eFJX+|MkKW!ITqc2k)uH40rb0O>xAd|fmok!-aP%o6oZ?%V687q z2i|)?5`B(KN;Ci~9wReg8V8@MO|3L|lh&>!hSD;22yHytoC4MszxzT`tSMT5#y9usa_dhMoZ$A_0X^nUXf4xOSP|8n4~a2haX<}PX7O-iY9OB z?(U!7O?8)-#^q}I)hpZqcGUa;N1bn*gEFKtM`_M76%`Fr8mY&U2fJcX05^ZO{035S z&piJ@W5!=}eM~kypCX{?)n7_)9$_O40kBp`ib%9QVYs7REA;-Xsu^wpURowH`xuC< zb=x627-5%4FJ^;%}1n&f0TfG=- z#wKGpou(qh;1r39aHwLhACk23qoW$xAo5>$`gEcoimpWyI{urrSJ69jS7awxqD9I|adv&EEI92V zI?o#SxRX=yGQ&`8V3GpBcgm%$6R)|gAH1iTNkMcKwzW2Q9O~)PU!IR4V5*rih$v^c zP(aHSUN)l!0v$TmYDXqp)z(j~1k+^n6X4C#(jC-0UJ0Ebwltxs`2ch!i*xDUIcRrN z7fkULq$GMJi95>Z^;7V^8Amc)=QvFZ?R2|=F6?%)V81YMF+%ili*`)b>VBsp*RG)A z%^_XyW9Zv4e37e_u+?P01uNN<2*%R1FMZmbIN_QGEw_?nqFT4jILOjZiX zB=}$4X^Api_jIsCeq>%1lFCnw>i+J*6v#1+ zMqq{~0$uRBEwkw0laZV%eK*f+4B>02qo?Di((TzHj!BKd)?5kKt2OFA6}1=TGCB1R zXE4ju^2nE`B;e&flDAz~B@c#R@ONb)Edg^&SKG{Lbf5N)8;q$1qn<{Ae)dws($+Ua z#p^_$Q$z><4N+{WIN_pr<(yw*&WRP>rf1$PzmQ+=ej|cVBpVi&&CUk4=JreKW1*QK`WN0Q({V>v3Of`hP z#xz-K`0v)!h>IKVgaEk*3fy&VGK?Ry4lu z-aXS(zXLD#Y+62)zBWeLDEgA7QAW#5*|p-dmYX9{q$fe<{eHibhQ1j3=#+hv*FC^kF!!YlMUzeBwR(RuUht^ zDN@xGNUa1gKVX)8QDETOJYVm5r%(K;%+Ty!eYc1tLChhpT^o@k3C)NRjF{*5p>_*F zUE6EF`%(&+>4nI5?HS4m#%%?i=5Sur>bZHBBN4*HB$nlTb%X=6Eqf#>`fA%(tF3fBfB4yG z0Pec}!56QR)5)6Z`^E@57$kQ%#~BjsR7fHlEFdDRHAUb)(og|;Bu*N<^Sj*hji^wN z27d4wdO7)EuxaSeAY6oM%dYpgbr#7f=r})jyE(sDc-UPYQoJ)fJv_AlQPK&DvxiJD zCrPLYkHdEIrUgrI+V*X=%7Sm-C0t7=qO+zN8>Izz+~@NHY~g2`netv zXa#J)sC2%RwocQF=iewuLG#{QvnJx0{+7#BjhK>SXaEEW1tnHamlr9dDrh`v|Va_KUQ-)h~xyi zQGyVwpDuKx7fnt~Os}fU`MNeQ>hI%>(C%?Bpfe3ag$k_XK~RdOcFL=`Ky|v8<-uS`%ocj*;nE*^GYZt^^mS*#vbNp{ zqzFQN{MhgDB$pSXO$fb{@X+!r!CO#FS3+knMm*Ow)}o^)i=}QBw|sZxREvr>98{@h zbPQV`c6VuQmyo8Bz8CUS1x;oIGL*6b?f37nJt##F(a!USqv28f0$t|XtMbRrXo3Gc z@t#EGsO3JkcqdB|&Qo@rHYq5C#eJw^x>GSCH^qPuR{5FX!_Npxn5gXL@ZPOS#1CnM zlQC6iR=Cj_7_InAVR@Gw}ZPZqt$slWee{QH?oN>?~ z%Wkk;PovzFg1_H_)?YnYKXg7RP!+r=QqZ4~<_p1Ir{Z93pO8v~Z22=V{{v810r!*8 z8XK!W5o!192Igd|Vev5lGq0$s1o|yM-6dRTLj35HxHe!sKPeA` zoAvhvC!>@!+cg8XlTxP}jj({Kyf)bDxkyuR*=xs&q)uBu=`}Au%-ByqRTP`|Hf3-Z zaiX~7?G(j}UFj!kT>7Z2snFvC0zBqcP%LMC3GwfQV{NO2liop*SG?2ncGQv+yqdWj zC5wzLf;NjI5cGF9A382MMSz{`ODIX!l#w=8kGe&>tW?57I5Z)4e^YZQSbaCY)8|e< zV=|>v(~#>aKW^1Z@fG3^rlfNfz}u_o3A4t0Abi`F(O9PeAnVZD)o}m&4*rnjWcAM{ z_j}ScbQ5J4pGGr?JaqPUZEFEG9+6eGYoyrmmw}=T?q^M_U7*bK4wAAa?G$OVJ#uPZ zol7tsQx9+k9VB?<(J3ueQ|L5^3z$wZ+3c4usX09am(^CO=2?uDL+G@_Xox@t5!_iu zVcrj2f?7e$_&)E6U6;m}mMwGpK5u^&O`8u5-R+c+0bT+QVeRF17 zxElbOa(cJ4k3{7C$S&i8h`aMS5mCoLumN|6&ec3Y^oK5C)j2g!pO1wVi#HE*cRu`5 z7!;NrgsH^|{mrh*ld;pHkO)5Azx+F0=a%ZcDPc-|u*$%N92gI-qw$E9n0i!;%3 zHTHiv;KjEkEh4aFbBphMvl~2qXTBi~1cDS5NFNc2jQ)f;8ZJz4aupKim;HfMWin}R zhJW{sauW#F9(m8rRn3?UsEn<`7bF?Y-3tL9b*aafBP%% zn&7R#3C!j(dqQ|UQYwjW-avPf%9ANgF9tb!in93ZLd%;}>)+?j^$lrw6^sdr`K>k# zV8g$aBER4&ao;v1m41I#eZnkijgh1aws{CYByIA zXu7S9G9Pha|9bV;cwem;#KUJve)Ds~guz&=x|jf5RfAu_fUNSN8(XM^lt$N@(efnJ zltOofQay9&shDn%q&Xi=Qhc>lw(Xg?cp6gwSh!TqCrJf%N>P50YzX-zUY1A14!X03Z{tm)Fa1}%2 zM7Oq2m7ZolU`~3Hwk~@2P^c&>-gN&NY;~aLG+?o9_dr)PxC=jyENg-t31ttk_N}>9 zWQB`mP{gu%tXvjr9KDn4I>OuYsHit#&K)Yd2$Q}?Z`q%Z>SFHW_iRT@6!L@VYOG9qu84UUON?nLLY^1OBa zBn~&x#z#F_)A&?HIOd+#+?SEG%T>X&;zGu%o(06m?iRyeX zn80Yz;p$TvfIo{26v6Dk0Mv{~r5}=(!@uV`peOzWGwRQc4>*z^i>u=%6GzTvH!+rP zgCuQNMs*|?z}Vo}7b^l1mZ-rQPox|q@&t#EpP9A z5UY}UqVneFHi#d@=8H9smU| z^opqiBhXOB?x3HcfDoc6VP>?ZpJfibRuSWte=U7Mwr5?lf== z!H4EPSRM+Z1vuf-28F(JXTDVsYH~Y)j5A~|r!9Dk4ex^Jp#~)E_T1{fxkFC{?+POg+A=&* zj87BTA4XKSgwR8+)Us;mlz}c5P@F`ZM~-q=9!lxyWe;8TASXW9CdS08$FXnCr zN;pq%%6m{0&6FL!I;vs-ZVk2@LFpb2VF)dFFkC)6TPKmtjNsL5eBM`c?Lk1xsqrgQcU4%q4`T=27tEJft&Q zM>J~{)}iJ3_lA%?Y!tD~!LL&a+*c*so6YB@#$8wMKTGXM);g2r_()kBwkL`@NYGr6 zbc)p!NGQNBxO)iuU&s$INDM6{KDTsjjSY*Plp&UNcyP3m&vq2++iH#~ht;PQK!!N7 zLoJkFMl8`btC{O?C>0P1d?d)NBZ#dE;NvwyGV&;z~pt z+_!9_P%GXDrd8l24RCnH!+z($lSTmBYl-$Vok5Kxe8RSQY%sqhbw}_O1Sg*7EivV zf!wVif9t@fYa*h2ne@L$Dj>w6Tn_X0{+}tM>N9++HSiAh`KZwX1VA)6jvgL9p^4om zG})!Qhy4U9CCVV!k;D%705>bFCN$mqV>hOGe6KL$QFZ))KAc%Dh9{wYBU^PjI|YLt zn;LAZW~!>^>yD|0rp7NIs1WRQeG`^x(zOK1iznqttpt->xG!e^=ZcD7;)nF8l;HTXMIy@@Xv?C%=4j4)nZ!Ur~54n z`=FgU<>>!68?TTVAh&8WO?}z+8AmnrF0#@DIx!SIv^d8qKWy>68i4^|EPNMPDDl`I z_;l+FhC!SwmAW<|5_#a=DZ#plgNL1OUCs`Gi?WMJq#5j{qs#jNo+gV*nubTcKK*pUfjoUSmGv!huG0=fst#67G?$3*}pfVR$j=&1zxT#$t_Y) zO(OieL3}cTL@F){zyvu@`Tk=q|7{F9s8b8Dh7wJrucoOvU@rm1E?@?Knux|h6OL_t z8}v<<*H}2JyMC7-mSM=O#5uD;&Mfl|!}?xieu0E4Ie7+!yE@1qCFfxq^MYB@eahgl zc!8yy_;(0&x}L1Z2?ZtFd8j3f3T%&JtHEHsc}S@C&z7B5wD3XBUv0P`S$wL{S#Qm7 zpWG;x3O-;7PNAe~t0%p?^}*dM;03B*@OiTIN9{N=vw%eElniUY4y#F9l7Yw{HW{sJ zp7at#*}V!_lNMJ@J1TDF?a<@FH-&HZ%-wu4(%q}sbWP8e&lT*5W9A9Pur6hcExYzGu4qi&jJk&UWo#C!qJ}#8=6r7rZYN9U)HVfBV#bZZ#1%5wJ zC~TXBu&1!rHYg>5jxKtKd-B(MM-+}6kxzW_3n&2E;GZ5ZN^r!E<90}9sl~5_R-uh6 zcZfC#&P;*L5ii;ED1S8Z-lYE=lCOTPE8)P+9fWeqgTQO%8wXDAI_!Pl`{5EV|7B^F zslQyKXs+&{{!7MK!0Nw%sZLuhI{%5^2xLOnq5&0`l~oaVDhI@hoxVpL^LFbd>}CZ0 zwj8#I?z^qbZ6AN|6$5EbqBWAKVt>Ri`Q27+ct|jdbdBr`P4v1zY4kzVE)>KMn47+M z3={x<>UGj=YHhcdJN2i9uxeBiRU>`VZ^=t?s6Ig&^F+o6mW!ApP5co_s2exibjy{)};8SUg1uualNoRVf&%oNivP1nqI_3oIM@ZRo^iV3 zjCEuRj2Q^PkEu||ix?01prYzB!=hD+JVA$kY5{j+3M;0qh4;8t89Qu36wb+6hOH(* zE0+wYTM@XId^K=^b{kRY6RQ#nMW3O{w+w`>@uJl?&Sursd1Oiv#lB^hbJ0m7JJi() z+iN)7Xy#}xkP>+4c*uecqv4P_{}NMJdvkNPg|jwowIx(dAWC(vQ)9J)oBWYZ?}+?8 zXnL(l;Mjq8;CqkehgVOVWCoVC+rhsUXgNQB6tcOt3Mt%cC-<(MB8 zc1yL1pkb2m~XSx>bb^Z&NDEU|27 zw5p#P>PZ!C|4MNKyzWS_2Loof6BiJdO@{<^^9m#0_^tTPo7H{*1AFgffTO-bIxJ5~%MXL1QNYY%k+^tlRxvPJZB+>d; z;aB-&Dvcfft;mN$O>^$$m8JZu$37>{vp2cKRIUXn);j5CneF^GcM;Tn5YoJ-9GX?# z%HLi>-ibT=dqL5m-H6BT-V$LjgxCL$@5h1hXISy#U{3XxZtw}=S_Olt{MF1Gwc2lR zNr=1+q+O`|k9HyXpLPLK{|hm1#y+E}|KHjLi0LTP&~eq&*>Jzl7(ZA74*CT+>HV?r__&a+^7sK%D9euKwql*6o$_ z*HUSe-(O^qkMpkpOHiT0PK)IFV__XNah+A6DNOsKlj(x~V!xNqS%`Vbyp5 z`e1!$@lY2<2rWxDfA!yb(TiX@-ICdRZ1)h*i0UkABBNb|gkE^gl|KlIGjE`pMfwAx#sBrCY zzA=&=WS)I`LxuMB$<5AfMh162TW@+o{|L>#SaEDINiofQZYyYDlbgondSZEAX~^EC zC7EQpGIcErP1=w3I6B-3np61gjgSlA+b^f}OwjTsZjWj^!0~HS6+Staf7x%+{m>b7 z^$*Wp0Tf(Y-8(vDUn-cs^pbpd6t5BY_5p*wawgwtZ@tOdj_&`2;8u~qV0!&4-{;T5 z)K0XXPec8q89ruzdX0vMpg$>J)K&mZnA|(M6F8&AMbKWr#%|{>^q?HH2~QM3g2nuZ zP3BYs5L&fQ5d22O4yQMaqI%IPHC>QsaF)Nb#+!|IXk?_QIuiL|?dI)V&j2G?(4E;Vbb;yRAhZIxV?E)T&BGg*Jp`)}^KjrvcXqw4ZIFdJh@m_7J z5fM{VO~sK`dI=S0AD9^ECoX#pO#od#N{*PS)K^)Rj4PYD$EvTG8yKB^UBU*ouTX#C zyYPQ%`--?Yy5L*f-Ccsa1b5dE+(K}7cXtR5!GgPMa0Yh^kilWlz~C;y|C8^@^6lR2 zru+V?Z`Y!3b=5hin9kk3uUa}nAs>Bv@zWa2dlf>2a2&7%_##zt<>F^pBb>ifbiR5W zSvBDcNN*rPxH2wT7c_S*`~yTmS9i-81RW8-A{FNvfB)0o$gPkXj1%GhqF{}LM=1K_ zaVbo!mUZiYL@%p@ec^wSUvp&THzKNqaCdy}V^%Bt96A;bREp)6$Z$DjDG12d)<)%L z7>-TxgUV7P6fpS5%lYDAVhNP$2Rj1jDXLcXLyB0 zM92Aoem#9Sh%I9EfI`3XR=DnLwTblVCudak#WzFHNbgr<6q6hSnyt>+o-TRlgWv*^G&MzSIfjR@TwGGuBm z{`O8Emxtj^u@ewVd@aGbvqqw`nsKEchq3ZbMBGz$urT89+*g7U;-(`X6 zv3iOyT0-jHkF<;)Xeei=?-`B-5JvM!t);ra7y{|D`U_{O_Wot|QAJo8)^NKbHQ&@W z?9aeM`w*47vbfFb--Q+GOJX}#r-P_-Kug!>^Yp&y3aUG4#Y>>vLzKYIt~@2Uk|e7 z%j8a@>30BHE*7rrJ=KGJmKR3&a@cY&^Of&iD=m*L6e%5~?_mK+$!;|`)N(Q}7I*b| z;q7J8Q#1-9@P-(DLAf74U5-y2D?jkDs`H6Z5M9SimYonX#HC3RI+kg=Hvi#226yza ze_$Rr4O{c6fbeO8=b<%w_ZKBKu)nq=55kMS-w%ecN^EIoP9snsKA{^c`;u8U4(97< z=f_>~&|dQ?{jBclMIJ`F9(UlpP@_)O2l+>Sf=7Nf~P0 zyaX4!MC**iFoe8*;iKs@KwRg&j!@Fh9Z!-ycE2!&GB3En(lrS7%l!=?oS&x_afxg76Z>_5MwHV*|Sr7@D` z=O87;cA%}gV`be#u)q!OU-emOI;IPeC}=2*+<#`Z=-#_^O)Z2%-8f!1UPFlRK8&?x zm$1JLmlH3(c2}A(PKf#>nhMI1cQMX}d{FW91FfMzCWtKWroOVNmN>|0={NdkSL7#UO zXqzI&1s{`B2AIMTI&ykee{qSwT`!=TWplXXdfq?R$o=7TLjuv5xx`Oz0Ja*f65{WM z1)nBsEQX^8!s%^=?C*E-@-@F};hI}tJeVwCb)~p8b`Ff%wTwrklst$%Pv<>T_Wsmd z1rB0G!t;p?1jscK=}V21sbmvkQ2t3AgBn^p_Trrg{&6)8YF5aWfD!cecoQedtB#(7 z3=sz)A{c%m;+13Y3iMqJ*@DaZ>EW`UFWjxJG5G zsRaGpD;AT^SvZ6TZIcjQuTJ%nz;~oQ0qsEJ(eH7)dOoPmW3;$z&RQdc05&HlK(10` zXk@xJ_>uCk>#*o|rA8daH?LnUb+kO*U)JqUZYmLSb+d@lnUY=t=hX!bmURjU8me#q zZp6E92L6PFkePMj(4_^7LRxL$=+X9I7#FVa?Eh3TCVT$ z-Rze|0@K^a+;72uc-3kkot|p#aNhG-&8F1$R(p}$Ef567@vmqjZNz763qf&|{X=mq z-Q8QC@XjUwLmN_ay6T6{ zQ~Hk_y-k_0{5`ItQ^&E)@))8n%myejR1L+z9xY$^!spz2gJbLSmYF`mz3rZk5+ZWY zyr?`!-8J3SJ8ez6Qi2?3K8ApVL>Mo=rkDah7_O4{tp?0U9e(;X^`Kz%h^oH!zPHxJ zxxB>1XBlV|3{=thkLgE9ZLxACvHe% zP;qz1T}8+zkURcSVFeE%Pt*837F-}&p8?X>$xBAJAkye5Bvfpyox{cD&?hJe_&!-n zcoI<+$U|fVP;LyM?!%426OuDw&LL&bL|dGS@RqanldeHut?&p&)3zXwdeZHWfA>iz zlCSbQ-JV|^rRX90%`6G&fjJ>=g+}d1kB-s71F)uY!h_Agh+TLdLb=&yC*v}5p|7h7 zmljmwpR$E#=PBdmLrkG&rtpXxS;lQ2M0YDuwhivLOdL}X-!!d)yV2cV#(Zzu)o}BM zn)4EQbxp)??hE;|LiA0e#KEJb$2BtEA#50qP@#OC_FG0>w)wU{Vx5Jf#6p3Nn>_|L zir2aTen38@s!!#rT<*iu7bi^WjvbE#6ZTiHwY1OtrxM=aL*~1PjvTKyF&t{7i z>5|@pu}KA^QQ#ey41sqn)=QTn!Q9g52;Y34-O`HUxY^u!h{49`U#c~#5NP%B5NrSxarx*cZdsk1#?1ep-_Yx3LVyM36@yhprxGrOZvEjUlf`` zF~vJlvqEU@AG0f_2m|uKHx0glKmyUb>i{d|>(xel#5w6cv$WxVPiq?f)H&*HQm`*o zb^UVLE{TB59pW;s-jBqkRNC9CXxj0`+GM-9hjbq|Iz!-vw9iH(5Q#Ba$`!G5!ZQox ze|tdSI&0K&$IPD3iV5)Y)AjE8djy_25b4vxJCU6doZc&=*X3yFPgMCP3M2)>m@LAH z*}dP6p=oj%L|-b!Cm18)ofd{OjZyuOJKDaJu<$>9_zWy&3#M%d(?dft>{9d5U3dl{ z7Px@gZHuj!r0av9Mz+10hWKB-_{UO7X!7yLzeadyFU-Q_QSotxkT`2Z-tw&$lLEdkBI}*nY2I-=RZ2)8?IY}5E9UQznJd^TK9At2MSt8k4V=S_}a0NuB%7$QnZfE z*mVaIGH$C><>NVdPBC2NW7|s8j4jrFaw8Tn9>do8#svHhkm#gs%fBG#yem1!(|9D0 z6oK*rXD<@_XGG~}AEIa;FN}?4MWD_U>P2fnTFR%re{VX^Ysl55?~^(;A^pyMtJc3w z^lqPlV2YGj66~*6ny0$fRr++<7@!5Gfs5nYf9&jG8)S{Y?O;TZ<0sR%8MhcAFp6z{ z;a*kR|Mwd4D4Bso1BMJiUCf(8r|pbXjM2fNv?4#%$H6p6kRPA_HsM<8trkzsgZy07 zr@;!uc3-B9iyu>Fkik9QSnqvAAM2EPm%~24{Ql^DY89U24)RH|JddW$W--mt`}SaFI}wXY z*K`a#b_6u>hy`gFCN0OX$%WTbx-A-Ycle}}C)HC5_4n`DLWiS~GW~+p_nM$Hmw&Cz zJ+#&clpuY;h{Wxx@pryzwjoZq?RGH~$H9ZDPck!!rE&c!F-f}$WtI=Ul?G8iz<#s5 z8f2njZEUjDDl{r`U7HhIe=*<}MvsqY8D=E1n?1o!K0xJ2@~+?vTCYo)%^9Q-H1ILG z4NF;*Qgyq5sseJs@@q*1pzBgjk~eu>H1o@6hNtvMnHm|dp0FH z=}D_d9~TVbx*Xd?j&6`WuY3~1s9qLy4-ii&MU8&<`ew`~L!|v0%#zWDamcl%P#YqX zRG00DkK(-=)6jnU?(Vo#og>p_$W$H3u03VmZtw0~i6*T5#-9bYwgv8qQ4*x}73>1O z2D?$Dey$Z&*b!lt^F3rI?_KrV|J1_hS9m>z&DzRaB zaSE>^Bvs$Z?v}*XIL*zHcA@ec@3~9v@%V7ply*oiv^Bnvyj)%Uco;XeLI-H1Blp4p zzK;M%Y~oArHpdU2O(+}^h;|8n<~y<7=)*SOw9uy`DulG~=J3YpqFmovvYmM4GFfL4 z75QJ9E+$e;gZcgtc~q55koq*GN=A!|rih0!8j;huX!6*E%nLb9B}i>LrrY?~P1e0q`O?Y(!U z28aGJ`MG%rpor}(V>$|K*!q8!cF22*PVDs~7MgPzMv%BBL@%p-=%`r_w;?PZZ%php zrcP$$u!<9^PO&|Rf;L*ZB&{!p5w{GGqxahbVCatV>0yuys7}-XKW7tVB)-H;r1@c0 z%!k``Z$CDDB`82=YH}1d)R-cHSDju}d@{jc?1{%z3(J|q0SegG?wR|}eM}Fy8i=0p z81fV0-4tQ?6&+2CzZBdZcUw{KkeU*6J_HGddxE*dofErlY=g~Te0CPEuY7x`W20N??G0bHsF%VBHlZAvLW?kIMbhXQCUZU( zI_%Xs`_RpjVE=11mlh=C;mcpNCU97F)Z-vzfR#lhW480q4IwqCR21C$TXp*;eaMNoJ|F*&&HX|0w)Q> zlU8EHKM}5#jI8`NubDv*?2X#-2z1TuO3?E$kD7oqJU%rB`{a98b?OI!11x)m-{2OuO+o^)&wR7LVTUd zb!|p^f~knXv^_n=M^s9BY#aSQiLl<7+s_gq7QI3XGB~s$nVqscQDxtuLUZQ(ZFT}B zVHz~eQVSTrg@^tMsSR~Fsy^R_NXni3-A0A~A?)<>>J;Wi!m|ErUc3HwOZ$f}rWRJy zoey_od63uakfqo|*Q5`mH7HsC79Fbz{{wDK=KI$#%zVp;#17+Xu#WhhMt`8|*D=pK zX4OUgZ8nM1y0S+w6GDd3sC)@fS8|CA&UovQyc|`610e05$%#b7=VVv< zMTajy000$FzG?_{6Fyd`9FC<-tvGN|A-VFAd) zJ*ZmHAr}!dgJ1lGHVr5Ssi`N9V91M4+6q~1%VEsAK}bgA6gC<0VG}lVe_cQUO&9;5 z(gRl4VJ4!BA4G2FkYfs;jq||01QfI=udFTa6*d5 zDHQ$z>j`@ywcgkTbN6uvfp55p?dL266{S07Z)U50Z*Wa?HadVre>KR(y6xb5ojQU* z&~0jcbG$9&+ESPbbNQ3~$6`&YYI8kR!C^U9Q4OjRg5uuF`n~J)t;mbpz4d3(ssRB^ zqR*IzRt#bpqqbmr`F0-;^#SvpfxEJhm_JScNk8t@FRVNwT5Bkn6liXBisn^ut0(`K!ITj?C~v*jFDdxTM9MW)))G6!t2 zAe*nX0kuO!{K*||@3uFwvr}OEfw4-O?YgY1af21%bckq=d>@;H0YvYkMRsUN%?v28y~730Wg_vq^KhR83h zv_k)5FS!g|k_mIPYBic)lq0S%7zga@Jt|r*x<7_v3(#5u$wf2_drXgo!aU1oNbcJ5 z$JjOWBYCts-d)Z3y*$W6=k4@XGc2HU+4xaQ)QI9;G8w0pE{aD{s2AY&@W%+-?uBhl|x@ET<3+e zzhWThy8IEdFZXpXY{xd&OW5i+L;e&*9E(x&v-R?8w1QHqE|4%Pq{Uhh20vZL{~~ue zjW5>l^9r@&9Bm?0+_I=9XdvaJp=@RGcj6?8fsgPPy{!6zqg!J5tYs{8Y}gcwMhAmu zNQ4vh-a)K44vuMV*p~Vyu}5!m{hXZ~gtSbO%W8<)6-KXG({$NFM@2@F(SCRLMph=2 zOccg`Oz8K`Oix9A@wopOsW-cWlI$8VI3o%$cCHX^ZZbJkptedKZfd`CEoi-*vfpU| zrk4mSd%x*>V)|a1%KRNl+mda-!qSw9Nsx1$i4O@2tJfl`-65A;D=?fAu}t2KkB0O7 zCB+72YB*enOpy5@0!DvGoLV$9HHX9KI@`oK=Fi4O53V55;R7|?jF3k+IDYbMZpY%_ zEGpuj4CBO!09y_M3s?o<3?6BynG&MrE2q4-=J`xV3r_70RiO6I$S29}k2=8uIcgr=_t)K=4Gas?MT^bNS5bcK z%OiBFrA=AMS|RFm01*%JhRT5&v#x%DQBeMWdE+vKj6|pE4(=i#)rnTdh|!Pj z-|GRXZk$rCH0(NZ0_SE^-=6gAFzf^=<;)GFSdA8OEXUF(JU@3Y4Ug=andh(wV{Hmv zw6sPgzs4-n_*g^0-a=t5EYjK+sH2zfEJ{gdBlc7(uwW*0{@^;g0_G;RiwG`e;)iNk z`^6I8Bw&44P+gTkFzdg}1(Hxe1}?gk1TE%u{fB!h6#bW?+y{8RcKV{X;Qp(PeP%Be zM{fwduZ2|8)@~N>zz4i@pZ`Itg*%hqcmN1%KmTE_XLXkga+W28=R<;%n8zY5oCuv^ zKFXGq!RNQDMC8{pkx8jqvrv)A>KDzF(O9&^;uAje9Y=teaWL(#PfE& zB@tq5vdH=%V&KsUU3w$|p*Bge7jOk4iK=Ex%$7cLVmG4mvo5~GQla?Ft#uOXhC%=j zwKp@{^XHP$_jsq>)*rIx^gWUm`o4`2N0T4}<^LX9x9MlSNv|~@Cx4m@z6{ENu`P6o z`c_M?{`q!(aH!n1W)%?{gficx&GS86XpM7 zvxtnWzSC*ctbp4)pT=b6&RpX@0m9}VCq6)V(*rz-xFY}s&eW9uH91!vSp>tFZlE8Y z*WtE2Yg^_Q8UuI2j$CtXesLri%!mOaPO?f!5%TZ!y9AGfTtDs{hhO+eB5i#fk&S+I zmqbp3X^SMjfsOnjJFdbn@jQdqN3OV+IV85#1-5h2u=&0t_KBZG4&?PT&(A5$HYe0Tu(( zEmZHS70FNoi?)CLQx+qtF>(=wNyfyWG)|(J8N+}Bx1xDR#nCJ2ATSgtD5WU=ulxjM zcu|Cyf{ftM3#lhZd0}Px&9t?uuE~&8yqa81@-6a;KtSH-9U@RIahW;`kSPz$zd!=> z0nzvg{dMKgLv?cT1_{&>Cf4BtXQg+Vi^)MnIezJ%r-T^APlBnP5x75eeElmfBDwPy zN@-}%?^7cH+y23gzhFdQ@a5Xs(=cMAOk|koJb>Y1TZj8AmD`S-DUT^Sb$0`BJ#guX zaum~rGOY|dBv2X-5H2HF>FsSz7UVX&XQ?AR{Q=Gi8$=OyYhY9U4tNlEleBJcj(Vq` z4WwDo_YC<7e++*vjBAOVsG<>;pbcJxml}>cDch5WkMhTR$tZs?$S*ki<(`wjg^`iU zWud{&RnfTJsev#xlN`M)-$zS(``;9#L?4Hq|D^kq`krF!E}YDVzjIhE+69(zOyq-_r36h`yd4S z93j}yQ(uQ)K+4y5cJU1B(RmuxJvXIdN|Auv<5M{vTvEn4m!a`3Ah#>TIEv`A&UaC~ zQ|~1PL!ajQeuv=a64h|J-mCYGp|SfC46i!Hhye*CO#U^AR14R&9nmW+7`>Q8t~qeq z2R7=eO>$dbYIJQpwaiQda_^n(VxZbt`B%*=a*Lu}G^EY(6uXx~AIa`FDNrjQRmQmV z8QA@uGO@X;6pav*T48W{&VBYgbs zw)uV6K4>ztQYSpw^iM(y@0;Ndb_Z8;cR%eD5TmW}Ak%86u{v%L6kCW04F3v9tNM$W zodznEc6|quc6G}OBF~u9snT2t&Q0|N9ZqyqKU?zJ6}oU$ciij*W{PYacLc^tQ_Eu< zUH~vj@IdfR+;IGmSfkpux&Rsm8aXSO@9XG1ZVgS6N%iLpCl5Qa;_J|j%+G)f2ZHWL z#;F>5-a}7x%+$QK9#TD%W}St^le>t16*zTQ#m%@5oojxhbd|noIN?_A{8RCrl)-f@ zew`fAA!bs&Z= zowCpJ8PZ`xdpl5}%#J8UE^&-igI6DZ%-U=!1d9bJoiAY`^L>nDG^+sXnQiB608H`T zUp{4KjeI$8Z~`p990W;uiw1o;dpioWpEfK>fggU}_fE|2+%cfM8%*usIH@GW@tPjk z3?z~byu2@;?z$8Zm+ZEeW)L}G0Zv!;i|d(FP#{3CPpA6G_KD8=eNt`Ce*G4S2^w6s zUN$6lu=RwyZ=?yfrjg1H9Vn{E`xtG~YYw{cXhD*WQlvC|nRzZ3s9iV^Lf9ER?kRGN zfOV1Q8rMqLb!}e*tk4y||4;ps053t2w#<+df?uSzpksT}(CAPf2!JDiGSObtc+#^5 zHS7r2;12fH9wfJs7?JYHL6^5B&S5_x6lVCCDtQ(8nP@lMam1y$A^n7?&18G%^TGDF zE)yzR<1j=)W!S%YBuOl78!1b+V=ulY(;Yap~fr^}zPME1q z4KYAgtK3*~YsrBVkqMF7FB-MdR_w2XW7KkT6kJn*q4*$CbggFovzm5W2L_M1y^ZXQ z9vTz7P|dfpNnabsg#{WV-M}ExD=j1%@^F!bm0D)xj&z9iIyU)k#eQjsAqqPOopiVj zC5ZK5>&ezdUE=ea67GIBlmhfbzQp-4dF5Kx8OKVV}&Rryg!Ov6?A?V1TThL z>{%d-12%A_M(PW6-zN>fIQwYeRfUeiA~yJB;4x4uIBTzgpvIKRpTXMYfL7sU)NT)v}&$!)!Hd` zti!V>WA@2ulNfRMP`m37B+cs1KfkbidQ_ zj_%<`In0Q5#eLPK-UX=Tg1<7PvttE=>5zK^owl<>R6k&{V#QW? zr0#cjJ|1@8c7)J=u~IPG)KXNfCD?jo!C7S8YB3oyGRzEgMs*DG9_RM7q? zS1>aj+HS3-DKTL1csp`g%DyIhYCTV?w@EiRVTe^tN=dEynpxEuRD5~{pgNo3pJGAW zWJ;ojcPo?EhQi?JERYCzWWzD$R{l_6kYzypDsms>pC@yX&5^a^7-5cMAgnuRY;3zp zXe^|h>Ry2%QWCcGaL7DR`&TVre;cc~cWk}%T{(_URE$ zLl8WHG$u>+wV>C~ukWXk47?f@%9GNj2FKM>cJ_mu28aw%L-W<5v!YYoNZe23&Fw|& zbL_l~#(lv_YI?%Q(pJ-IxOx=*Un&>?h<~9h2wcOFDv4y*!HU};)KtAWs;mh|6@n30 zJEeq$mp>|ZE$lxKq+B%kRmQmpDD?lPbkp*->e%Ij=z1}u5x>(Ie`T$*ZPj@0ArD^; zjG}eQVVC2fw#8?r^|22fB1A}Red!%r&e}A%Q%0O|PeF%xWsPyk|E3i7J>o?ywuZ5{ zTuPf9ZJcI`z*0%240!z~QS{(hmR}`>?L^n2UeH$}X;N{GbxIuutKv3-x$5n8y<9@} zB0rO9E5=SjPP5sR(*{lbs(|9fHjzmqsV-Hk2W1WEL!=1KO-1(XeoU61LMY9}p4+B{ zhy3)-(Xq+qiAc6`2!%E~W-qBU++1C_9+9Xza*yk$r#`?ZjWnJhk51!&3vcDdy;>Qu zK84~n^qYbX#(`IBS|0^-4c(!Smrlu_RF6trjJS_}BuhAiy?2pJXnB(mo_)}E ze7}&;{ag?g9qF&>xi{@Z+vOi>{yvq%p?ZK*D4#wReldy!?Qxd+kwI}=+%WZrdgf8; z$kNQrLgSO}bJ_h-o<{3lW#SC!@4m;+$l|vX)1L3EQ|05g&R;%U)?d@nq;jeDgMw&Br$UkciK%y7I@i?*LlknK9KeIijceOt<`vf(n19sRX+ZP3 z3osPbxOt(tA%@jNsHgWa|M|OWnw5#=J100{{670{fH;3yB1j9 zZgo4#bHJOWdte4nDFSfxK49QEQ%Pu6lYb6stdLIql7yStWx0lqL`3ZVz=MB#HMy2itb&a+*yq%+(w^%tS3tEZbq_Oxu{0u-%`6~o}sNB73?vD7Ca z--9<#q3GilJG*)^o)g+ROuwOP5XjjQEvtS9~GZq^uTMb+Ok3dtd%o(6J= zC&WY%GN(Y5<7|5ed=e^=63o(M5rGOH@WAA`)~halbjJsgudt9h6W9sI;Q9Dat5*W% zCe14o|DGA$Up$PeE$XGiz^&Y|Kt*RNgupR}Lq%3|uZ8MB9*ajMQN;XzE{8ZuMHV2V z8{5@zGb^(Eua!Jzc;ZZCR<({&_)A;w5tUj)P&aUp-BLl@z_k>wSmdaA(*5Q(N+{I9 zUxxz}zyTzo)}RtXbntQLP36tvY%z@rA)&92U)!*dH?_b literal 0 HcmV?d00001 diff --git a/noir/docs/static/img/how-tos/solidity_verifier_4.png b/noir/docs/static/img/how-tos/solidity_verifier_4.png new file mode 100644 index 0000000000000000000000000000000000000000..aacb906f2891f45b6697bdbaf7bc9ea70a28416a GIT binary patch literal 79069 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 literal 0 HcmV?d00001 diff --git a/noir/docs/static/img/logo.png b/noir/docs/static/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..83d3a66f2b19c95b4a61503dfed64d9423fc6903 GIT binary patch literal 178782 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 z zowA(rdm7QeW*qJAh4}a)diD7ei5^SVtz)>xm{3pTb`Y0|gn8Gm;RYiLH zZog;yW3^F9P5QSbVD099n-@&pk9c$+FYCwtN17zr%5RCP+s(LKswQd`Y0_6HVUtGe zT++DBRNc*PlkW9eZCH>?ZAtV0Q}luhB0gL%r1DK!k33IxqpiPWq-S*qf;Ju-7A4ro z5a)4e7e09zGWTIlz9I5^w%wrG#DP%L)?9E7Hf<>c;Dn~?C*<^z?T?{3{KV^|eHU%k zczEXW09fj9SogQz+e^VADQ{3%huTiQW0#celTn ztMCz9u*j>#PWCV55u&%g)VrBX``TlZ)4d?+-Vdm4L~lC%y@`2D+YE6OhOh;FvH1{T z@N7c1Z|&|?`2hH*-1&WQFwjAvq?!!UmtD90K(95j|3>=Zr@AkJqbFj9rSG})Tx_N` z+oD5jHNN&V&fYvF^@>_Ak)ErF+xgX%@$oG}O~X6Cl8kPJRrp-?!63L<_$tA>IU@87P!)~!s5}%ZPR`&xj%19)U5>+y42lQ_ZryOF%!#$J4h5Mx5 z>P&F3Qwf@dQYCA<*Y?5u)k6{`l;3{eyA=#)T#vtALhF%eq;#g&ISs0eoPXe$hQ&*C zMUkM|Dw+{kx+@y{!EwF*C%7@F1tB$!1pmCcl>)zauyQfjQ0;PCtD39^hO>(8-EbHN zYzlmH^TcE+e%#p>G{aIMj860ZYvThOKqwnNG({`aMoY_y-bcb!t0BEPX2WU9864QN zZmly*fV3)txFyGBshku8F~5ShkMiORyu(2LnED5a$KimGA_u{jUdv^XeD805tVPiC zx*f6;1_G%)RLF5^eh8lvr2TE`&@iEjs^haQ*ApaRZXAJ27e$S-8_xX#o| z^Bx%<64==EIf?gOxe&gZ@lRcxATPhf4w2HhCw02(?%hluz?K*-3Lyf-!#=W-wx_|9 zl%3bCb%T!Nz9-MgG&=O~7VV7!TObTW8Y<#t2W~<1NMG>{i7v|jvz{S~cPc{FMKd$OFV`?jPy%q5v&8LN8fpoc$m*Pj) z%{Bx&1apu{dd=)xc6IonI?|g#x0t;?d|x5j3IDT`Z$5VaWJsBJD@jdBcHOW>ETX+( z$Q>`(B)XJ$x*jO4fZuAWkk9Dd9>k7AoGjcv*}Y?w7jp`Cu_*<+N_4pG$s9pn|0M>S z=;Pt1WAMbPwo_RVPqFI*{+J~sOlK|!_;1LzLV8XGl@-8w-q#jBApg`TF~svOqua-wtfLz8NWZQMTfwU+!yMPoWw?4_ z`mQCsKtgPScqJ0)R)Z~{u4N8N2ik1}Y8XKs50&294uMWXfv-Ot}QhwSxEl~n+B*Zap&SseF6y*suN`W- z06a#Bz2uPrFaz=pu!$oIoXyBau?NpfC*2*ah~m!if8s3k`IXi%6%Ar|zX{fRDpOOo z_%<>xrg4)sgZ@ul2o{RRrcD&bPufu7G_>rHbn(+K@kLb&HGBSxRKLt^@uJ}JwV1qP zr!Bl;@h>|liZ;$yf zcnf@qUJ}~=-7LyOZr0Vk^>oC(#`i{+KY8o2Syb`kl#j|5u9%gm`4QDemHJmAnf1x} zuS{6Amm#knRTK4hZZXtp-cMQo-ZYZ;)DUcS2Aid#E-nJeGtyZ5`(DONMhP~J0( zQ3|4Jp1|rwP=-(Tb&5Y34Et^#eDtgL4t;$3XLYo5<6x0%9JqkT^K2`J-e-Bndqsr3 z_y!u>dJOUqU=tM6=~MdFIR*V^Es$Z~y3 zk*4B$!xgdlAe9Z5){o_juo{Y3g^gD2Ya9QDJBodYnieTR$?At0ni7loxx12C^oYn# z;oG{sU<$2P?VrQG)gvyS3Na(tn-?%VNdR|kYx~iNi_?0<^u~kS69}T!96f_k+OYYE zUZ0xI!=X{@F5tL_e(jGmn*5G74wuht|FwV$XX}%x7T;3`(yEblV;-ow2-UMwMYYZ1 z7jL6Vw!U6H7Y*B|7@+_AiZ|)!mNxM`XTffz#~lx)YYee;eQADym7sL|M&3;XaL@(r zlWQ3LF!bSp&&3u~7*i&0+6I0s-@0hgU<6BJ^oI|I6N+D+|FkGfI}aOh5+?tzh#g;m z^Ejjm@cr9o(}g}X$DF5(VyY^@h&68n*!*insVkl^+I9hrBCo@kcC#Beo_KZrpt_h% zF@IRe0?a%tESt585_9q`@k8HJuZoZTDIQoSwDqhsaBM5ng-m~4}e_{qWbvwa$2S+2Hsvr@`MSoMlEi}>D# z>67%;;XsDeTP_T}6>(B|`xDjE-r0PDj?=lWIgy#Tf0Cai<##wGeijb|te!tW#f@KO zrJ+3dz7@-Fj1Sp@@W6d}y4axSdR))N@-FO}6MuW`sT@aqY~t#tm3@KPYM#ZJ2XTm{ zBsvjUzM7gCP%Wo+a9BNVL#R!%NQ>rw@msqgy)F9u@4@VGh62qXk37R5u=EumWB*eB zX6987`?57@y%VqYld2c|?ZB=Tv|>K!6F`@KmSc+m-V&fLh;Rf#R@fSVH$Kh%zH^%= zQ2*Z2zXVdM@NRm$yWK=y^FhRGO*qRb;n>?&}gH&2?$Y2LgMs_P|#} z-{z4_fJ)= z_b^{di#M8Yp_rr}qhbbVBN#;SdC1!1PLiN6a+gZxiySuz@`50^-mRe|YJdQSFWFemj&&0bS-6xm$nE_Q43x^vfG4p7X-HPW(L4<(d-Zv0n1Gfr- z-s3rHhC>Z+pRa^87=A7__o;TmrS|vM^&I#UZIY_hAZg zn@z@^Cf}Ks_Bnrq?-vGoJ$~)rZ!bBY{_v%^M-+N?+YEUgQEHqF)Jzzhj z)WhOdGiY1)u9C^N<V|pv3QmQ*ZHf4zh6T+~&_Rboyj!zS zIiZ1mKy{LUzdSoF8$oH2thlB%;LT&$)>?`Eo-IFCm!~@xJA=#`Eh=RH8Z;$0@CZ^_ zsfHqdFEAY#J;3lB3eb}>43>5wsG==Cpaoa%MX*APQ-B&0)7}?&Xe>!+i6+ zBwCW;pQD~!z-Wh^4+Hl3ga2^-Ebtgj1=?lclPGDecS}tuvw!QUsz2mIW~3ZBXERV= zIdyu}-|&iCwjD-hPk(>upcjc<_I%d=)Ub~2u%6b=M}GgdPIV>+&qC-m=H&3-e7NS~ zXna#ut)t7_S$^BJMeM9b2hIyqR+x6jJT}*av(K@FZYHs;HCV~&XnGys>RE~|Vk4vp z4OL@uHhFVntjs2qcmTX9tpQ3&h4;2|%)YmkEHg)5g?frbGU#%{?-hQ}sS}(YE5Vm6 z)T;HZ&MsVtVNkFlrYp|CYo&g1s><_MFhMZa`WbI5NTAF?jm@6;7;~DLGwrgQEO`xq z-v+J6GeR@j3aE9#$|`*+YQ)bwxAZ)P1y3bw`o{TR{0wr(cOeEXlGgJ+Rs}iN;`hkmpAto4~8Ewhr{kum4=1`e{`2gfhs#=n~|vY))=5Hdg6=l@kRXQCMN zFX*z_|Aacyy#8d_j)Lz+BvK^)7b{`Gu;UAJBk{u|RDcU77Ad3!LZKg8yhq)%Xuf(o zZ4xC}F1>z!%FRe4%}*H8g0Ax5RLyb0b`^u^y*J=X$0bhjZ+e31%(_b7)c40>nW(6H zKOct-3Lk_25*VnvXmez2tw=0z3$i)j#wBIn-#wnYpG>S0A}o+-gDLfk8m-;ii>eM= z`CED_a?32jHKR2$tNty5jR<7AFR*)tchWrv6C&;tBgLQ zb8=+vYs{eB8YBc}Ui^cqBeak)uSI^92@$erW0VM)mMsTzIPgeY^#YW$Td#& z1e#++c5$_48T6lQHQaYAej=`%!x&gv>sec~R(~ht>?a>8LfBtVZk;KB|ybe`yz4RFa7Wk?| zu%ahv##;a-#SmpQONjE)$6!tCWt+R(^Z&wj*6;MO53UrvNsf;4&iHqGY0}2l_CPXDv=v$2C+jMHYhjph4qlZPn zSjxqVqw6>5(&FF*6TV!+3qMSlWN9jC78ClBE5ENWkLcaTa2s6oeYVX;x$i@t^(?EA zXyDOl0)%jx)Wa`V>67ElQ#{BIj~5$!dpqBelU=K|AD4`@L_1Sa7BvLz@o)xD$;{==}Kek~?vNq#W=2 zO-W3Z3}+m8L5QMwoE%oVt40S&zfL!k=1sV1-Ls+_cKf|RU#nMhCeD-PU*0$4^LJMJ z!P&@t)Purt@K_o0>B%w^&Ibc3w(T&IPCbQzMX7>rIAy);utOAK-n+l@Y7VB1{QSDS z?NK-@hBKm;A~W(&nAt5EjrGKCAoKgmZ_CLYx3HBbj7Yx0&i|&L7gro~iYebQrHL1Q zZf-32=R^1gH@8~%B^{M<$C0;@B?AKM>Uh|%|0s(7WUNo#5W|W2j{&jQw?)NU=WD0> z0=rj!U8>mR=g6)shVIWRy}aRMqRE$9q<{KRjqFA;^|XXHjhp6LTr|Rx&uz?O&^jc} z;r*SgH2g`c<=gUiES(nN{(3tM!O2e>8{#aJaq&fR;<^#en-Ac^xo!ACDtva^Ixk2l zEgbpa41PXrdkFN`?QyPK8z{zotz}%RqX&r5B#}|&mxH%{z3MPLY~CmKXMi?HHpVPB zy7_bxsVTKGlvRA;#aVD^EN}aTx3Rgye!1i<5Tg^GR*C^{6TZnHk}isu?8Jx5u$Luo zBoc(*2FT^niMhiaHMUbIA|VJ6B^TkM|F;qqLqqX4zbY&E@9=!$34Y#1t0g>A6W}W0 z55h?Pr2CuPwY1c{`Si|Mcn`)v;AY_sPU*}Ci?_khH!m{Y*apCto|iL>dNEA2M%@~+ zz;*~SY2UqiBU0U5w5}tkG%TXTGg!4T&o_rRy50YphkwJ6Ad6S4fiMe^PjWP2z^SnA z+PguAG0@lSuCR8h;WJ7@|m$6CB1oV#VVl zpk)wHSwl5)KA__ks9N}1xsz#O?2*tG;foE%$M8xMyAubKomZ6QrsLh~;l*mKP;zK32M$AKVY}b?K__A}r_;3Csy3G)7Vn zlSEj5OW1!X-k9mw`JhoSxquPsQI($mfSrH6d0}`%Y0CE;(n-JCN8R!^R-vPbkpNFr zimb*WQorn-q{#v2sP`_{HqAo+jrr%}7=<}5ONPdVpWyx2JAAxDXzQ&u)hMZEn;(1V zbS6>R+07a)nNYy7?aGDqGF?(_OX-)Uvr#j#O1$-VEKclD+P!pE_4|zht4jm1XhFpE<=sP#=*dN~?6c-l| zO|H$N6Mi+xGD2LHe&s}auIY92!HB@|dzuOFd-+9dHx8p;_kT173lErlT^BJ5RN0kf z+AmZBcuBp*-32A3In-knpLUEtZvQ6@hk~8YYLAEVP6m+o$Ai1`69%9hb(VQ*#IL7K zhe;q73c)Adv(NYH8E-@d>J!YD=E!f4HUnehr5Qhej8_%8o1E2885{(!B@Py;e44|A z0M56-nj;h~RViO0Rpaw`fXM700Q&&0vmFRtZgyE2_yx{wdiA?>WS)?*K>xo}PUK%H z@N9)JraI>U7ip=wJV(zyc(oV*yhcb_{;L%p(pxnNV4pAC9=~0;nd1tC&*|UdPpnb5@NBecP1@J zPZq*(Cpm51sF$$aShJ?qR)Go@O?pm`h8=NX63)PXw=&b9rYy>_8yb?Vs zuBz;I(jE3xa)zbJ0XBO#?nLk?|A9q;q2DD1Hc7N&MI& zQbar+`vqY~OZ;)=2?vv5bd^_wXiZ&Tqa-^^#Vy%yi|muT7cs}p0Rn$!5mhPn21&lFD`o`qpH^*D-CW=kBG)? z2+(~Yl6o5;8;*Z;WTK{khf`wp7n~YVb5H$vc*i?|mZCq9g-c)wV}sgytl_L)W82;? z|LHB;TtYHXuw{QWPS6@wy{SwFeC8|sR1dAG_hqVATGUb7npb< z3<4OE~dS-7dlaTy1?Iz@(Vd;Xpi5HyDC4j>t8rjd6i2- zI#8h&xq-e~$F%`ppJm2tCu{TO2$IxUXdyoQR#+lds(*!<#WiIwmMCzk3iLn8?Qb%& ztTX)TeCu?2%xhOYW@Y%122(v%GA>m#sIcwg5KMp~USj_Ge>ihog&nJzn}8O@5s`!I z2#P@to*3)Uwc7+`!^6ZQ1NsXNpGhdwwr8ILC&X(xHG!`2$J4LU?|g+)@fta2)dzn+Wxou%VNi2 zQ&HxOSw5`~RiBr?O3eCe68-SmI3pXq*nMBMCUlb2W>x8$FEh8S{>x%_XD~Gf{=*}7 zLp^ME8E@MG_HRts`g}>^*ZorCuu$7qjzMw`d1SW+DV6xGUvXUCuCT5ReAVi3okOgX z%vrvd7a~C`VaFDykmMz=<2OXU`p^a641w8L`01VP+%d3x0F`K8Gm^X?%9%cj@vUuTq$3^`a67GB|!Wwxb-sAZ952kNwWO z0E?sMtrC}~@3b19{hqaY=lgas;g1s0xLrpKvD<62gp_|fukf(c6W}J*bvtJ3r^>VD zEmHvh1mM26PA9^raG!Rd{SkiS*6oa6_9G?(>nb}j@fEYL&vl+lY2)+4fXit#bWG#2 zZSQ#%1Mp_tV-$dp1KO@62=iDwN|Y5vdm9KM-`PSr`ERP?#aX+|C;kgT2jzGj{@Lw+ zEzUQID}Nz+c%BXX+|Vt&d%vXc+n+tFcnRBi>+ge3N|Yn|5F=9`fjdvU11r_$iDinq zA3qVIZ6tSx8Wt?(w5@J8+KcQmg*^JYQPsZSP>0ZqY)*ACHBW;x<93VN9l;N91q4yI z`+eVG(}dIj@SYE%q3U{|cC$d4(~YaV#eR$(%;A^Jm9_quc2ZY0lJBkV6vGXn#QdtQ zPc)hQZ7eEzXl&b7(!;EYmVXKd8y)uUpUSTZxut})X;QQ1S6C{J3K)!l5u7A9G2<{O ziTv^9At;X+ru|!(Zo9hy315O=Yx#{2Z6WoAet@2xbOeBXOzG>@oWwe!DJATJJRGpv zI&X68OkAQYc1;r3jR`q?PXoAZNfsHkBuVO;bXGUT-ay;VZ9eSl9crM1 zk0K~ktzSa)126tE%U&Z+xF+5ZqJeiBq-djJ!}(yjzf!M5EQ%j)3r4Mk^Tsy5GOxE3 z0>Ajz{+X8z173fepjDJhT(fkpaYbj%@j14FkkdB)-(vE6Rq(I|@+jNn{)+>Izn&a! zj{_pg?t&)7sgl~vh}TQ>1u_XRZ)D`uWW@xIN$V7q7or*123O347oRBHRSf3+$tCI~ z?{0S1_?P1yzo(E@9wCdq1M~vmI6vVyj2Tk_cXNw4S~a@v(sY(-x1>916ym>rrN$EGn7_h=`-jNTe4MYN%fqHIce{+y|8FnzaatIWXe&I{BjwWQrD} zWP*Iu&S-U@pGUKU#|t!v{S)Iui-ju-C5cwSHnoNJ3tzA__9|Pgw%C= zDz|Q3(}Fd&Y;!#RA-dXeLIN(p5DY!gT{QS$@;daxwB@zT3D^%D@w4Kc8nn|}zOUq| zjLZ3vi0WGrNIj3f0;lLbDR=$J_^==|r=tBIJV&&)Ruc9l)xLsD_W2zTm#md;-Zn0% z_<5)_=G&^oX?QxO=;)~0q#K)ARQ96AVY=gPavXh&bfQTu&A_=|Mc}e%&rx+`#n08# zL$D~^(>)8{YIcHjH@uotM6$ ze#E+ExS~#k$PJer`yo9yQ*rU1C<#cPR8rKc%ICcR;p;J}K%+$9`4&LL5m@`tZ`lg* zHUa&_?`$CG>X%cuGjW!IQ%KA53*S@GwjgkWts%XTzV@$0*Dh?@q2S2JHig1>1JlV> zGKRMYACl9zx#B^)8}gd$7(Wi5^#M>v!hyY;@iD-93M9XWSz^`9uLNv|4=z_QOAn9S zuYj-o;Apw?%JDXvG2yJfDoi7^333`fjs^~oq?Scaf%L82(3;t`1H9D4XG+N;r$1#&B5oxAuE{%UN5MG1RiXM?PU9m*3eO*7RF>M zZ&h{}RqAyh&>&CubAtc(Y4vijA!Ca2v+8WwMJcxJLHIyB;`lOg)9_|>AsLaF zcgBR^Yy{bkd*49iwNTSN{6?xos(UzbziGlwB5Kzp@>E_=qSkez4GW$p!4=@vPouQ) z@A=P>XEEBnFEHU9X4?3ktD)!iO;V>{aGSfcr~uqvfWH9N+|!6Lo(h*A6LimUZCLg& za1P&k7c!1@L7n&`WU}={_6B>()&X}!yv5pDwC2=8O1J#1`cr|stJ)+Xt1ZZWHDyK4 z`+M1ip=rDNK8m4t+~@LA39f=L9N|s= z(6MO`o+e+l|0f-GQXTk2);lBJD(}W(HcIh9?>pRVaUj+bilb93`0oIC9$z}-E_>8Q{=>>5qm6@Lc@oiAJqq3dEdxWVuzyg9ri8=P z?6m{yz@8>!UHw~n?VHTNJ{H_bbTEria^b7w1cX;yo&un29%x?m@;bgrC41-dF{jBh zAdQ?=TdtYb-`;KstHM?_iZ%aSaN1mO^iOIN#ybkEKJCL&wsN)1r=~3UlvVh1Uwlli z3_c4vzPKBINY|olytHHSQViqP_DS~3c5$CuO^VRisp%O?Qd@J+Z9@F%O~;pKbT3pZ z>9S{aUluk;zEtkEea5j*k&{^r)}`G0e%>Yd;q<)~RMAOV!0jsJi{iiJ7XrDp@@+sT zN$?lBlQHcduugZ_wjun236YiO=c7;Mq4Kn_HHW*P@6^7jv=QMeAF$wo(RunF<-F75aMFn`i>QcHANc4Mj>3|1ai*bnf4Y$ZDQv?Y#eAyjXP1 zlBQ6Cf{8i4%JvhX0#GFcEe}-chj9cZWeJWdFLMDLsACY1`DGi_b%*uqV=hP!R@7cK zHGQk4%`9PV=U%Am&?$JT0$K@n?f{j;U2kycSS790&l@G%9TPD!y@~jSe_EsDb{+90 z?dMF<6Y)2XaULQ>tx*j{fKV1`dU8LE1$=^5^3u}e0gk)!Y^m#2 z`LYP@CbIyGn}r`xGhyml)YK3T85cPho%y0~^MZ`e?xR@;p6yz_c`YcZbdj0hF7hlf z0E`5zI4<2VW!FqWw_(Xpv0P%F4r z01EJH9RczWb*6cW7akvdDJRbbk^qnLF*vx_+>B}_>+K{zzKIEOEI{cFiQj&J864Vl_&z)zl@2z!_)~b|IqmM54x%G zi{!6yo%c%0!Rp(MXW-5-ur_$?q_7I1?ybJy&=1~gG@-zcjAQ0;+N`G6g}h9?0Md4> zhR_H@()CFtkt!%X~7Ka@nD)1G6jT&CX0_?!OIg zKUF1P-OqGN)Dh&*x%z-+{_Xf^ETrk(ZyHej+a5h^ziqat{-WHQmRRQrlpmUSeNOJ& z#q_h7VWp99%GLw$aUSXQDvo_;ODulehH14scx2;Pi+N@^3s0xx3AuXCfVVP!{YDeb{~% zFAMtOF{?C%c_foQFj#zkbzMQd#m)HEkZDHS7sY>ME_$JND*1y&AMI*-1;yT*q0`2m z^x`0^RTs^h#z>%h;3yD1BdXw1j5g;S9f3%)mxo|5l|2k&z@I%f>3 z>uA2Md#ra*nfcZ9p+2S+mxl~}RYc*j(SmZW*3l{Pu=k&60a3HxJn(`|lG_~@PHLA;EKK8q*JbOc+?(%{PKBOW zZ)$L~UMWdn|C!NLTWxtaoeG^ltVx4Xo{pNkU3UC2(Gv^2o&)^+2CCXLR!V>a zONm6?7GUzy_kn!00+B-MC3C=~3c?g6YHipOU0P5uU@TVsc#m5`HqA;_H+Jn<_Dl2~ zs2s*${WZ3y@w_*P075@)Mwwp?>B}3MKNo_kpL}n{$I4wGh8Jo>+KPdveHF(bcZ)ve z2Rt;0md!F-M#b`=7)lO&5|yz_JBL6pW=j!yeGCeoSu4CWe0sQ0j@sPw zC>tr0mB9t640gAIhYQc1IHpzwtVVfDMXrMsHS`FcyLh zMTlUxuZ7{K-*E_ZZc4c5ruyi(A%T3vnL6nmWlT-| zGN)1^Qx7A3Fys8BdH(J(<~@a`DPkpZM&^+94VdcMOgMX(=Mm+2hS#uuRe9dEaDM%J zFU0{iw&kE3QJF$##lC^@W;WmErocS8H=_l$EUzOq>9C$J`OY7myZotym-p&boH>Mj zr&pvn`db8siDEVUhE9Pl{4UbwqksvF`-b^-(b12~!>V`rwi{j!ERLC_NdJ*a*Sm}N z7arF(a5J1>Yje1Z5Gdpytgin4m%=|v0)t+1zl->g(Z!8_C5?UkmpKS9TNGQAVuJNh z7^!hQ%*A_wgP{iC1#*1XknlD<)p!j$BO3_X{Ipi&!F7f48pmN%?rej-oGQ)W(}2Ot zf1lA%IT&Fes+!Y|-f1RWeDs7B!K4jY!BP>dSRGP_SkhxEf3ry}lywMXM^)RF^T6QS zXDO55gjR9x(Z%OE0!PYybh_(HunM93j>y9y&gq=rn&(;)H)8i&AfHn|?xhDl7s@oH zUbMUK(PYhbtew@z=jhPpMM4yv_dsO9)82|)HfO!;tuir}M3SQ&$2wwu&kQGyd#((` znh^iEbs-E7Dh?cF!sT#&LQAZ2pe*;*HIxqyMrvodrl(Th(?lsvB_0|*n?7k9`uuN$ zujjCdgVOm-YQ+82a{?m-qzQ_Q`yZx=oU1RkAK`Lv9xzzmk_rB}+dVZHJ-USS>pq9Q z?99Y_0~P;fui=G27%DLW2*JTe%~m-)Eb-+jOJ@neBN0P$atAJX+k}|NC_u4YAl=lh z*5{(-YQyM-!laWlBan7yy8&ZroT|oa;1&sB%uA%MSE8~#=KS#yqmZbxwv-?4j~w)P z%&)O$5o7rC0eBkCQ7k5pI@?uWjQ5oojwnA273K z_wTkW!Fl`L0`HDC!fqPg3K{f>*lTPQkS*q`wbA|-ZlHdA?G`tG5CH*gHNyKHHC}vG zWvy<2l4$e3xln^oup6J9ZTO}t+C&1SUMa2S*S~QPP7X{HpiH>d!lgC^C*3YrH>1== zq?tHVgG!=6EEFvcL#e6ZACE-v2&52;Oq6{a$;uPkdibwnj7xY#)Oiv}$}l77%~%NL z5pW4vhi;LJVv9fi2;a&A^p6SPS9Tk7isU+-Hsj zAQ#tzcw7Tra&@0^LNmnrv>mLNww|7V5vqvP-(}p=xq4Y+spDy+aZ4zI{QX?v+H~fH z^B5p|bbZfnJq4r|AHVb&@1mq)Ww@P+B+X6}%mUJsw%OEHnrs`d%Q7CG3>6#ih0SC> zjG~o!v3lU;hrVf2q@AJTDmOj(A+L!)P;f_?%4F88>ek-G3}aD?TO0c-6-moljtTJp zIJ)Y%CjTyqv>+iJ(jX0z(nACVDHSP+Q3^mhYKZP2;A z%>MQTwf({Kv5%dk@H3*#hitc1DS}EF68R#a@mABern?U=nG5!>tejJ&V~(FPA=rLf zLsVj4w9;(dQ@BprxI;Pa^D_UD^St^~sVcpiq(0~Le4$q5LI%5z}m^AST#f&^{ zUxN+k0tisXQ(&>OZ+EpaW*umQU$va4r-UD$yL8qh24eY9alp1lE(p1KC14RVMjyE0 zu=#WOas(TyQa{JJ9{)+fr=^wEl?DqeW3?U`0icpA9X2UX3S`7k>E51?ByK!^iV~jj z!Wf#szqLvmPvo_7{RK`yvVQ$>Nq~UD#BU_D#&kba0ESmK}y%i(w?r{QKXk| zx0I#JuWyzxv4;Ilu(rz$LycHRsf^B;ZR;HEN2_{uL@%o~$KejYY$<4)R^hyMl0`_E z6|)V#(P-&;Cel3XZOZAl%qdBu9=TDq8svh0mKCs|X35LYbGC!X#%b9Mt-LLO3qlWw za^0e^-CsuDlpdEsX6P<`#3S>lnm$v1$EE$iaO=1i+p%*e9zW(Lzcs?eW!AzTPSL#_ zCfzXhPMZ$U!nOI6vsck*Of(=q9CXJ7WSAON{5Hi;x5WkDl)#eMWR1hxN7}_8y;x%X zdxt0kCUn<}F1Q>{(LiAZlTl50dD9{;CjBJv9OK;0ymA`T*aHo|C=rYLDR*#m)_v=a zJkO&t42|yu4z?2rs=vMmIblUZin~zvnHjT6+jz@EyPTZ72`y`s9%JNpsnD z{zCvkDcR`Z6eKh!*R9uNZ3c>Q*{Zeq;P@}))6Ucg;Jvz%nUJIcMs-ditO)r;A?~Nw z0voD}TXrx>3*2)x$&UpFkag*KzcRqi%{!975opox-dFNGje2${-GTHy&6(R+dM4)d zD~HzvME@+ddePggk$Fi7=vx?AV?in9Ufy5+LJWE@Uba#bYr=R%;@leFD5x6@$uOI} zMen@}&QyyWwarH_c%nLqA3FZHa{4?jV z+1>?I`X5u@kfxh-)>!%-l|nxPj5qW?V7g6STZS_NO0b`Eio43#gvWU+sPY+pex{Xuh` z0Y9Ora;#A8cYryqVUU78a=`xP4}H3IO9#N*+<7hqFrGW-sLw3zsYB?qt)viaY9_)| z`p$q&W=Bnbe5-A3LEZx7thWMzc?X4!uS>y5VHL*_doM_W=PiWsU z(Y>8C1&8wSz3mP)WXTO>yA748wo(N@U;*mwTsn7-Y<;MAK(iJwjC_RmJ>M}(D71-U>Vxd+d3A3n7lzm^PDO07-X zw3x|uEH1sC>PY-T4nQ%xqJjxAG0zqPDdpS+;bSE%^BdkXwy1stC<> zALd)b*Cw=h^%*E{-3WsZ(SIEtg1Q*Yw}2cV?{$wsq55{^VpQo(WO?*WiW6X9C1IJo zDtLvF8MZPRLFO%L~_s?M?h{GfzeSV7;L1fGR0BtD{~BgVocAtkyUoNk}R3C zUtw-#MfmBXzp7ud!wm0y6J(zK887zSX3eEDQS5;jA8A;fiC&f2AZJ0ZOnNzkAk-DT zxjKSEENm8uBEUM28%D5(BN*G9_8rnq2OYZa4F@^Mv5HZd#_qn~?)Q8v+_q@YUmE0| zWH2|3(HyKAUpujp6IX`B_bvWYI}G@pa|@KE2&3$wJ~L^~ zA*)O38;}o>pW%0Kg9V8!O%*6$3kHBtq|QU&y!REU&~aOZ^Fg{I6BM`)%*xS3TLz{> z^`fU%y$|Vg;8{LC(60c+*~+;iTJzQI%|tDoMTF@zY6UuKKK9ME`M!>!+kHCl8_3l% zNq@5NuQp;TuKVZ2g{#Mqr4Kh3WOavb=2_{5Mk9N5#6Gh$QTH}FY;~V4x;2ZGE?)`6 zf~GAZ^f_+dUz;?JEv{ax^S3Dy3(sYySPjNxbzH@1uI4w~74rVxbg5l0e5eu6h;LsZ zeED+eMqWt627Ee?VgBwNh;_WgvW}i1+H5!`uF^xPtUCk0M>q3?+(*P4Yy?9~>^+^I zq!)AZaTpmZ?Cz7Z$C{EwpW>8BU0cgPFCcm&cVZ1&LP@$V0Mb&JTh zW7LWS&8=yU`}u8sC1wt7gJuy03N(#_%Df*<_u4JaE64*}!*mYXwxRy%Y`EF`yWWp7 z`e_0$$y}DfwB|_R+bR()Hs7_FaUO6wJk>Mj79N0{0?@3!d!$e!bFcH0Zl&}5I|8J8 zJ<2_hM9VTAtIq~TI}Y?-^jR7ktw7v+SLkNH+-;zsOqdu8VWnx53!E#{R;QZQse$Te zW|nEME6JvL>HhYr!Vmf9v?gj+m)B(3k<^KwHFRiWAtx)G>UPg_Rjotx;;OY1_yo+z z34fyk=^rPn=VV(}%Z%xA^Xik>cYjcA3mNSf@bzXwfa9v*h@?xAmfx6ikRWn^EXOfD zn_)^H93^OG=9aDA)p&+&FqXcifM5|{-9pq5ZSc(@bb7CU=!c_ub0US*$+%5&Y4~In z;?X_GqV8Q6p;Lxe%PQ`+?{JaK91W!0fsD_6BzhqU@J3IKG#4$-L4%KD+I5#P)7~p| zsGIw*LuQin97KdpGT0`8ni1$X)RYSZRkYY(E^{Zmg3iD`ssL|6lx}~@l7LvmuNY6Z zOx^dAQTN~6keri{qBPWe9<-rw#X?WwftGpkLOC;(0G$*`J4{SVj8ox0t=*BT^(!G^}oUxgZul z_p@}@xzXzHp~q0*(W490+gR<*+PJoi#-YIQL2mcqM@=lZ(4CBOH$_pbP0)-;%qY)| zGd0F`$qI#5=|fE|h=Rm1GwtVhH-;%#;)Hv`560|q@~;dJ11Q-`dRT|rdW@%{lh+!> zMizR6)CjoQPFa}xujUMunqR{Q)mE`Bow2KJApaInJi$<$H^Xmg&kb|0&j(22-;O@kzoxHVsGSnLl ziP=G4`Clq%FO1?Be$7aC6oWKnE<(rrI`lQ45II&=fN^^v|^-l z_?B6iz&XyJk^a0KUww8D$K#$wOdZyZ6TawfCe6?oQmHu5&Axrd&7h}L>$DLdn|6dM&%}N5ui#n0GL)saEK`Y(1zKB=`>98=o0 z_NbzG&FGaWDX!K#>YL4KeeUSjGj#We-A~4o#og@3*AwWHMivfB#s6>7~sw_xiskV#6=v3>Gs>qHV3cyIrMQ z#wR9gpaw={Jw}&=tt!5VL3x<$NEG)^8w2|N8Blit5Ueg^w#o%Oe6NAJ#?6zxgyhy^ zeL&T@54gKRL3J?TD-_%!t?)>)Cv1PCP_Wc|lNxu5Ji6uMJas4|WSRq#w zon>*ip`TtKtQMvlZBeWKSXxHLOHF=*__U<_FFC zI)S_9_@_lt1M}^1u#WrpgJ24gyI&Q|Wrjgo8cFOf9DVCQZ(8pfuN$dOj-YMZ1=R{d z0C0N@+yruja!WCN&pmT#T&oOl_+iYd5|}qaH2eqrx zs{r2h$~>mP1c^I{m6B@Dk%qv8(x_7(Kv(nmkM`Mph1A&W-(|hK=dHUnyTA1@6dse? z{&6?1N@onb1K&g%gZz=@w+kUaV*fydyBo%cz5r4sa#szz5xd)Q*A3k=q-a0X5M2Pw z5C0(&euIaB#tx{)bv~Gq*;IA|1rN}(w^cKbdGkU`DndO`65^FJ$x?>)kdXCZjkB|O z&SNG@-Y`)GNZV1%Gjefqt3cVG=9&n4skdo4hwBnSsv>8LZgUpo2aTO-W5f4f!-JQ+ zkL76oj?O7HZa!Dz$NhHj(jgbd=o}GmjgZ|FdjNkd{@ktKghu*)kI36E10NI8FNAzr z+f7(Ypx7d+iXF-;ynWh!f;HT%-LKXQSbjl0KnN1PcX$RnAG%Nx2PqsUyO(W8z0VCE z>9<{VcP#k*i{i7vq6i8)Xa;LYSo5tG;xtEgJzZ``-3+|u*eQ7YY4D|ndxnxX{E}_J z0gTq&EI7l;kSTXN_gvC|Oc~;)C6bx9=J;$AHpR)0k2hmXI;D0%*UXm_;s7{E_w9B= zeV@{8Dm<)4LHfMQ#jhK4R#s8}XdTcW0R{|j?qRaxyBQjv04G5$%O~jTyAtiU7Oq$E z6w4**A`GlOX88K~irgxEiz5ycN~{rsd2e$n@*?~^xN?P^QRBah*?sF|My@U~`GDN@ zC&PK!C?3b@g)bhm$0-%y8{P3|V)s6y!1o!D#MJluFBl4jhKU1S8@pBGYGmx%;Co#? zIZjS#joRE7)k&UY4QPX|s5IvF?uSAV&t2x|i-)@2@&R|inkdqCNaC;C#ZclKE^3d5WA*NedSn2-z>lkWG!-c*)? zr(w0pBkq>Mo%|m_AN+CthCy+S6tnqDI%bF7>V{yhzde$jc4f=71|!mhfomK(&3YGwTvbaRplMY+#fEknQf(UNgH0nGxlVc&U02{qZ~3+ z(hM9E`oR)7QAf!6-;~d_-X)!Omf#&L^LQF)1Jk$trNj-}NCQ=S(gz zv_bP9q8%)^m|L6$Yc-qQo-Dr6CjDlBR3B?Q2Pz>`faltXH5Bnu$#aR%6bJZzT-IPg zmY`w6ZI(1HMlqwXG;nKFP0%)tYMhz)i~WvUJ7<5lb+H3k$-D};+gZI>knEB;(}sk( zW3Y~Yil8g^ZD`X*{1xNalrm$aOAdj23suWI8b42N9+69j;@29^s7I-0{jb@-lq0Ln zp37EvlTpNuaTAC~8`jlWAB+V4c@jU_Gnu$|-x0RT$f~-BPwUt+-L3&i10X5z8jrnObH)_H5sMeOfm6c~mQa<5GG%)Ha4&l=QLQqM%h31ZKD6rUAzAEcyb!=47MRujM`fq5Mfk*+KTY&^$XeJ;U4cJvPX1o6d z=N&O_1L$&JCvkFau_Vb;+~es{j)wtXgM@0|tPw^(e^MG-7^*Ipi<_6{opoiF&`4-a z{)~Lba!s7$VFw=_qnA)*aPS~#qxm>-x|*{%-y@C1S~cL6%EqxK$+Jy`KkYSR6TS)7 z@mqD}_Jt|e&3%vQ6KSo3M^g<2nnu=VGTKgGif&04ST+qdD7*t#D&+mk1yfr&Z&z<> zlld|0|~F{P1c67>Bh!!I)@HD4tOTg!qO^b5)LX#|WF+VrEP=tkZ4*&a=&w z_sB%Ntllece{d7@a$gA5@5Lz%EWBxhVP9`QbaJa;2f*$PA#%zn%?WnyKh3FLq7t$@ zN^WP|&wqV2Lug$RtHy!7C67ZQH%(OiVO0N_>7Ub%dYQPr@3iL!Vh?a_Lc!}xAXBMB zEx@H(#XOe?>q-R39b(sH~&0Ywth50;2f58wxhSF7|NS>|rHzf?_~Ea0@sz z!?KH;xI5iKW+VFx*9;nqmZIa(zD|Jiw5--kUuq*wTYOI-nzubb4TtF%32b)hXju-5k zON{9SSb^}N6%*pQTavvJ36G`alY|2fpX{G!G?8wnV?7h;HXa1Jf4oOyGhU;U|c8`7KMV1xXY$6|!)0_xjUts7!{FHbL!E`V}N z-(#eF`^|8u6PC!-Fe(TFW-fmg{)2d(C<--IY+V3XMn2}XV3Yph~mLwmGlQ3ky7!BeQw+|qRglB|xBF=LQk`;FDKY9}VT(Y2m zI~uqBr=`}r)MppZ?@1wOXkK^l)jlgCdf~5}czt}MKV|NKo|(UszsbIsYT8+xsBalT z@0ZT|{{!kH=JnZz#w^$%yBUB(3d6vuyWmjT;Z4r@R7%ZV>EqqjC@O6|7lkkdrM7>OS% z!PsM+t~Y)|wI#CWk!hL!M|uY@KPZQqS-(U)J^P6yp@)jT2@M?xm-pO~zS+VG_XTe> zw~_(R^nz|wEq_J}X|{RLMfFsYvpnJ3-)&hR)D`d}{S3@{c`^gz&upQGMKUGsdzbHj zzH}xmVk@UAxX*W;rhYM)uxpJe4R?FT*RU^jf71lSm}|@$UmF@hH1N6R6o4umV?JBC zBF+Uz0ctlYs7vbkJU?XLAciS|T;{!WkQaKG{}Ozm#* z>3$CLNiDJdWvGy61_TTn7a1F*Z{eu<7RQ%>GOE%?C!&J*lJOqd$iNMvVU07Hj%#4$ zK+ULJ`*=aqjrNA`0^aQlMHjg}UHge;Q-<2v^oFAIzYKQ!yc*ne!UXUtKlvn6o=5R$ zJyO!iUK{8DDk%8kN&{S=6H-4ZfP0{Le(vm2*mWr2b~mI6MPC`!1oVF7td_(&EkB!d z;>5Y3P(j2(I#srMHda6*a{!wqBT;^ODMc`}3=Q~p1LJ7Gi11rqfj+HeIC0rC5}sF` zBw^m~nu01?@kb-q$2y8hiXVm3(n+O*FPc#khBlljx^38lIXv8-TO*0^$K5#CGi-ubuM$E;iJKZ=oxxJY z`j*N11M@Y+v+_k{o;hw{` z)Hxo!E^}`knfelmm(;HKY3@2zc-QG+ifOprpF=!Z)v9bs?7_&{&r+UDMmgfBm^qUp zf&=c$*8OeKzGXHHFf@^#v$}L3;mj5o{h1$yC+3W>|B!!@J6_Z1CCJMLd?J_w15o@e zL)g_P1&5TM6fw{#w{%JB5E<)_ zufpVN^IGgBc0D9-;@|^Pw;<(fF5{Rj`S|GlZSL1K61{#pQ@WoU@okX~>_ar{OoxH( zulU&&OAh;99i=C~5tGI_=z^EwH1s~xtYaCnq_f1Cko~c`gDwksyOpz|#=jcYO*8sB zRn8&9PEQr*my6Wj!0Y}%hcntoB0&E~c4VX|T(s9GR+zvlQqipq_kE9bv(GfC@<*25 zc^ShE9uuX3Wr7HPUQ%E~)gnV&=|09pG@$KFQ3^qyAjyYdbk}|jJTVSVi2-=- zfa(VunkHtRVt5NTtE+r`e=I#-a&d<-i~YqvxS@Km**dkCt=f~y-mQV(h)abd>+IZL z!|wv)_-<|S74;;-Vt%xu_7SNo?x&#AO^eeDj~aEq^g~k}Nnb9=b*F{+#~gC=o}ip9 z;-bVAV>;q>fzYAO#^Fq~+#dtg?0capHZ`B4iw4Z8oSr;xaa-AalLozE0SArvjxJGt zY~;?WBIE9FpZT2S`yhg0Dsz1OC5X1$+57&b?2FCUV(aIuPci*zb!LXo!63x|59BHA zhKBCDTA-*$fa<~t1pr4L8d?vW%ThE8#*+Xg8E+cnbLzQ7)6HCyh6egTFN+)MPqYEJ zDI>4M3ZM;tv}t|^kP-puH^y|2S^*+w>63?KWU8Yq8XlDFQ*ZLIMwn;e2yvXlX!Sfn zGH9Y(51uCN_vR3~!hPlTxXz(n-!QiLdTpt~wnBrjWVO_%pBO$wX>{A_Wz)%w?F!(i zzqq%QOu4-)$MWM;P>i92H{WH6tIxO8ZEzc^wtLKA3}Lr8H)2zwD-Nn_|%9;S;+cmgfDjb|U~%L3#8XjROfE zT-~4CJIty|StSp4%f(J>cTSEqHOzP@+Z+ZP(z4sowd5*krpCOylV~D0a?GQC9`u>m zZ_FO=w~uv>KJgH>FtK#fzmMEA-&ZSx-}%+J2@Z&pCvmW`if8R(3cD8hHGY#8&WA$E za)>-hzS&fCj31nqEXzhtO^w=($3`WsOK!Lh&^&V=|4_r4)CV?bWL@-+7v4ILi`; zNnmdtr5bscw*PY!+9Tap57jYuIsVEYw}=YhK{Ja~~%5*s?o3%VF` z8|!V1ls@P++v~~Qq$SBa@Q6PtbD;3pyVi8{A6*w`GztAICc;S`|4Hj#k1Wo=5N4WlPbH z>Cceqk_WT8Zc1s-bO?JCDx7;A%wQ$0JS=!(dEr)(kY0=>oegg-ft=GP-@B}pI9}+9 z%WCnU3z2cq7F<&)5Ityt+;WUqOc1AD3n!E4MbA5_QtdB$vJd?KRO6 z##r-)%?^|I{j`oChxwr&Az%in^lgg3z{_~(QB_uy-;}W{!|Tf-f?(jUtpfn}zeQ)j z2}BuIXq#~`J2BX>$VPZ`aT6-SO0;q?(62-pDs;4XB@PTiWSA-3Vp(75x2ugr#UAU@ z)q(5AY1w;yX!*a-_eiOnq#vOlJJ?kY=!^>`rKAqLW8oHwI2S@O5!l~`slMau6E3z2 zqIG`BO5?-g!uzLDG2HXtS~YC^Pp=$z7EOBip`q~h4EL>Z0Y%7>#(sfk&B*=@RX|K8 zAC;3OOm5X2dEn9k^_@T2C?1^6$1I%qL|SL8Yj6BypuGQFk=acl+=y^e_l2PxlJ~A= zWze!<6Mq#LA97Ztc<&|T0=NeA?4%U%DBFQ06qo%poKaS8xVg!GzeXGEOG0gam3 zn1^d@-=rs!o?BRHHnE>V6EVEY4lX13LmCrh@7^|} zAqP|VuV0}K5N+vZ+23J#RH}EpfxZ8t4)X_<}IBE=%QxQDsL3oskj*_-i-1dJArRT3%SWJl2ba z`jB1+uMIwMaFu_60V4~ZS`E1O)@`lto{ccLfh^8CXEgeOz&qf>pg0122c(1oJV+q; zWuw-6FmK297zG4M_aVrF_+y8zty^9M{TNk(3ZY?>WZrf+2mXqw{SVFd7^l@2KNerS zC|IQ-nHp_Mu72i9wIyun5?N1Mv=>4{@*vIRN*R5u@%c$Jk6&bAWKFP*yj|3_SJMS6 zZF<4$keu2QhB(I8&L$HSxeAc!ubXLD)A{^o5GkY9%hR=TUDd6_q@?O*S zbvIb3=yC{t)K`vX8wcA$U*e(Z3oo+R$$ue8|P{~YI7aBf(BHuvElaV6z+h{ z9Qp4jUY-tGCGr(&({d)hdP1xIN+CG%06;u;_K|+t|mZ0_1kjvIk!Ee{{uBn`;=@mzEFU@GH#XX0BCKRI%z9IqMfs zSxi+Rm?Ruu%i-E;fRE{K`{!2^&k*>we9d zP*T6I87fpdD4bCd+BW)hFu)x5sjM!|Gup!<%WW1t zN?F1##;*n3WnF$>dCyBoE*^Aqq7^(qu5~5lYHXhG5gx*|+a4J$&_HYi?Y!mVSoolT=lnMSq_ka<2AYQ;a>2+YhHs?OG<{k>Xz4t@{C= zpadkUOu42JBObz(6ok%PZNE{@)}Krif@5FKI6036t~`ZX__a;ENp)LUNKo8(Gx1z& zEWT<%g(s+CkZiOxiBm|52QgIg5Y_8-c!WnL$VVj99|y=g8T|EvM4^p-ES&${quGF` z>8r3j?9$kBqeLZ~(3q9PwzusXGkfG9?VPV^6bp0$g?&x#K=Nq$lX29#ftKWU9rK0y&AG|?B?j!Q?bN+}v z-~fCvV^s5(I_@F@Ae5JRAnw=Ob~u|mG|&N;1e_0mjGBRYp!=$04@(@;fU5xx_?7n*vqdz-I^E7g4w(lgFDWy4O6D;V{EN>?%Tl-Z%S%^cWQb}hcZ9d16js2V8gY@E# zkx|9SYYed?Yi-oe2?vt3lD@bq+bjQBE!TLgtMGTnLXFRL((pnzi_A;MiQ3?XS3XJq z4_)#-+ReC*sA@yqof+?0U&^mLDIzKCyn%1nezaMYOd#UNP8Jq_fJ(%@DmDg-E3Qv5 z-;J%HaS{JskhQ8X=(TY4C7Vl>*@bX$%qoql`h9f|K!887%T+`gBEyOpRM8RUq){i(RhgcWJ*YuF=w3fn|mY zg^e#>s*FsK9FY-=ZpWVu)e&+vtUTisFn-D!(^vHA>gtcP${#F*qO-$oRyY5i&&Y*x zE50M=U?L=+8R}4OIByohBd8xQR+zN){lcp~u2N?i|MI%&ub?~#a{|c6mn_~o!y=(~ zM-W?Un{J4cI8yR*? zMyn!pY?~Z6{vIGkbYvcOEA|+R**{?kPKU5^8 zWmP7Wln;-jFEwLf`l|7ONk+y88uBGCzT}^gif3xFj_V9;@`DQj1@>$(QZ7uLI<3p9@1{JGq{X@%UR=OdkiZX3|3;9aTDSI6%* z!1CZ9W+N2IRu6_Zsu1Aw;G&jTC8ftGB9kMd!q=vr)n2%#qIX9?24BrJ@RJ7M79+>< zj;&aZ>{!l12-U;`8?jg&jk>yx@xr%d`C*SJiFm(*dm)8R4;c^g6QAuM@qQ0w$A{kp z%P2m~S2C8{N7S^3^y9^PzK$?Tmj9Cub@0cSh|` z5-AxHqvVNsB#0Rls8Y1G{KjlMU&wm>G5BFB`UN+>sL!4wThl_HFOs`=x;F5b;s+!L z3mI-Y-=tzegYCwb0}QLE&$WX#?~wI_PYn;-SZ$Dl(qD%k=!4^UwV8N&p63Y?B_wV1 z06dK?pUs39%1xn55ju((wK9W3!{WfMX%Pe*X*Of|OB{)iIfJ^syNnqUI8BbVuyKPdq`hsM;Sl$Y)+A`i_sia5zG21BNW^&G2zpv7&v=GT7(e#+v-=yB; zYZAV;!)l3EzH_VBSF59xk^Gwcaf9}JR!t2_BG*2NZ=`&Jo>tvw1sYP@TAI!E-+FaU zndby1MQQ6;O9dk4uk3X(OM3=Ls!Edmw0_7P-VaFhhF4HBl{$Y>)bojj91CRLv_p2@ zeW(IYJtjWq$ZZ`9HNBwk1BE66``(uOzdAb^O;*+**44@?bLB%NfO1;iH64BITFaSt zTV;z$ZB1s}w0OYAjA{GVgamk^tF*O_(Hr0(#fz7%0Tai-$Wsi(0+4V-SY)o1TAbSR zJFNK~Zuh+gRgtn-%GY5p>8i%0-SBu4_&G*hs%o-dt+*2naVoShR+6O~eT9gL5q=U? zR=1QSrB9A?w3Jha-fwLVs1cU`lkwLKUS&ummQf5bvlWvwkEwiAVbsc3USc~i$%7oW zA0qA%p0-h4Dsmq7`P5EU2L(oIH1<(# z{Ro22^g%lOq|Ys$qQF;Aht^bAMBD-pAQ_Pc+Godx5q>R(PfqN6&eowYG$0<1#C`M# z%UBb*`v*D!%m3t`SCfQzae2v@cTcK;0_p{1z_9Z~&W9;eM98kImk^xwMOwsbagyj4 zOw0U8u@l&-#hdSAw{o<}eUFJRpI1fmhIaWy%lF>+sw>hS@vyYS^qe^A5r)qw8YPKP zkl58^3_K2u`5u=+)6@A_IX>k}W1S}ncZE^pLSHbhYj#2R2m+K5-u@x{ zzHtNqh)bv}+&XoA{O}c=sY{w7if@-iY`=HG{%z_HiCGs}C6s7Ar(Ao*LEQ$(i$o=d zGt(#2o?@03&|I_0&c25QAUv-qh&CPEa{IpkkQ<)J_{!TfF8}`B*}cFMT?NPGJ9V%1LiRY(eanG(o$BSW zf5SALYlCNNKm%!cB;lMcKc-2KkWA7>(~+jdHVeIeo=XZ0S*gZ91T^Uyj9;ej-|BT<_$JewvWMY4#)g{w|V#!jN$2e|1 zs>Yfa^|A@!q(hqn(zWa{7>fw$)$QoskuzbOx9r6hJ6BIlJuI{)DDQiAixDN_J3mu3 z;E;KTR;|%Y=nH)H%}HpRqCk*lbCdc8=6;>G`OP;`W4%0~t09>jl1^Yjqk|2HOr(EL zUXMjyaSbz#hk^+NU&+wLSw3*3v6bPaeqUSh$~79y;FR7afm9J7N3|{uM#nvJp)=I^ z`RMVBS@Ru6Aj7<2QW?9qw1OU);W4%DQfX$R16=$s{HxwI?M}1BS$6}Lu4BScI;^vC zHIr%W!KeO#XK>-i+}8l`C=TEZh#P#_{}(V$Lu1?KjH)a;78f9#VCK#_C_beZk3ZC(342*!u=3 zXe8#mnluDVXFUJm#v{U&<<;F<(v$BUAj26R+HY~TsXBeQOf$%LP?YDuHMmV-3x||T z3q(=$I%tTQsw_^vt#S4+ZCy(M2zC9>Pu7YDZ52<4eHI&+KyyNK4XUtOw5Garpm13U z_dI7rREl*EkiQ|9mW7YmIY73K9Q? z-0JI{+d3bgk88e-sed9D9+rHFf2S1Iv*~x|R@qiO+>fztd&+WzMAhX(8A>(ee3u zrG)vxUyYY(hJVr{j;ITa`5rPpv8)A^zH0tf#`$Wz_8)#=>DCPF;-}B_NE^vZeb%$Bn?5)u^Uhc3o89{UGy~t&*Q1XE zlT^x1)|6?9JLL4-&b-;SC~!b&mUR-R%oSoLnTSdSVaOcPN)17ws2FxnZ)(awR3@7q4+|Z#D#4a@t0j;OMh|H&NNhVVRJ_AR15E8 z3zcJp4cE7#6ysOriFo;i*4UXh7Y%nA95W1rUbC;=Dcd9Q&bw~K7&^mzJF+Q^+gH5Y z^m)rdqxg+|LVY0Y<9Zi{*vM$HX{)#x-TVBad7VDy}t0(%F1dAjVI5++7 z|0Rx|B>*;B+%g0|CRuj^R_|R+L)q=Vs(sD7Pr1VHSBUUd+Sv!_`MEc+DN+fQ)%NGd zD}R3g&KR9Z{V)F5&M?_VRsM8xWLVR09_VI*r=4B7A$?tL98` zcd*LgUWNddMM~bTO0KWC?Fci*>}Nko6qBWh2be3s?(A}!{t5^X{uAUlUT1%*ZsDj! zw5JsK00+r;28IZ-%HG;BYEBkd$Z%t2PQYdZc#Q^rbSXFdvJHpmg$I*nJu{QfxAIho z%o4g6lu`S6&a}>~hz;*!>s#>H6X6^3DI>XaHe4f5o>5!ksuN^+s*piilyqx9T}A1L ziYZ0CNo&q(ZR>!gK<^X$T;jU*n?y?PVXepWp)T{zDL?Bh7G72xQIG3+gzrZ^^9ZW{ zCQBX+oh%p^QmkOwW!2m!9WB%SGO4v_xHg^KZ@qjnRrK8OR~C*8N#Q?JU1a)-(dCTI z@7T)E$Yq$%F3MG>E&R>fY`Zzd%iAHlX=b(40Nb^_7VxRbMmg@fn(h zp*3jK+Yep0{lHrfRxWGZVv1@oRb$)q4PwSe;XUf45dasKp`okyvkg$T!c|!Q9_4AM z?C8~ZGLcE3*B=wi_8>1Lk0v=84a&Y~{i-E74jQ^3IP0u-%%6}2Rg8aiY?h<$QVt=T zjFjNhTM*z2lE&s+&@Bpo9fWYkf-NIy zZfCmG>Ws|c^vk5`%ln2gci>85(#(;cnp8Q(KQiZj1+ZIp#_=dPB&J&zt?BXT8jQ<| zF1`kT64Z({2%L3GvTPG#S(=+;U#B`SUYeC2zxU6FhX92kT@VfG4*9xOa^Y@bgb_rNBsuaDJktwp@{rn#9&cB@jRY=1O;w$;Q2eH#CwV4}bP|rirDyXtOPhH4X z6Tg1IyXon#*10G$PuNEvp!6s4^BDU-jr2oH?qs1kFFM47*w8ebA5@h+-=yB+L?1Zs zP#(@dIOm=-v-RO54&4)BpN!|GSdSgDpINY!7F>EEh>SNxS@GUOK7v}`wIR+<{AK^6 z?-h-mje)@PWb_Nb&PPwxn;+oLrbRj~?+IPQo$@Mp7&fr>2yXy(@0y!^GnrWJxY#TeNc#Gbhz*?vP-I6!N5nF!} zKZjj#J)ovsuN=lv@a{Ux4~^|TgC}6116YA$_(pOKc!CB#KBKX{yb_o^j6 zLY^-79?+_4{TgdZr5f>AJoR5Wd|#jZ&X$%+V>Dli;DbFvz(omMBa%6)&UVN8N23(h z{{>3lXiuVs6CPrN`PfO^z{M+N@I~3+y)60L#~Oss0$a6L$m}u1!TZe!!Dq?BtLMME z!}jpyw_E9tEW8BPYNir#R+p20mpy(O#Ho!M?iZtD44Bg$!Q9ShVL{2Cj|3NdgEN5( zJ6b09mQORi)l8%Dp&qGed4{ndS=FENz58NoKnYef<=Jq$Vj1#rz|?I(2UBd5PL)I1 zjynd(TUMdJ#K}}AaP|YRugENHy=6CV{;o0z{AnWKOYnApA0tY>+~W!mWsC<+rSCY{>jL^s1uG%i_fwYvMrn*q3um?4P=hC!8kZGkh@x5F270dB%+|B`@?sk|_URWwx}tMMD|y zUnZ6sfQe6e%N+NZb+Ki8V9?eJf6AArZ0PXD!UUJWTld=VQEYgmTZ^hJ{)rZg= zj1Lxd(5;_QuiVJ{++{7td>2@`+W^-w#x7<07%*yH8ap&jgE@SzjpL~S&GskgY(!WQOZdr&9zLu1736uO6-fT8up5l3udw-OZxp$a)3Q6k{@PDV7FSZMoUh>1J< zt$+7rbK(TzJ_y~!XJB%hdGTPCX?I`UMQY&1mCr{j&Ewr5?i|C_-EyJ~ecKh{2Fki1 zi-S}nS<{UMK5pG7$AK|-+SV#)&M{+ypD(#s$#N~6`k1UEg0YPQvg+MyLlci3@gW&@ zocaH8bQOM0eqCI0A`$}9Dc#+TC?E(bE!`sB%}4?128ki5(x8CU=CbdDS__PqPO zf5P*8?!D)nZ=HWPluVt(rVzyf8+GhuJ5fB4N9^KyBCte3x9E_^*E~B4FOt8hvA3BB zBvVd#t>HQ5YbkAjhBNqYyDse~JiozR^oxS?`>pUiYw%G%{4gR(T7DE!Lab@bwZ*q^ zuYr%_Qa6`XgM8muZ=HR3s`pIlds7-?xU>O!VB!xd(#b#)nP!RCA11sZKS@IR&jsGrtxK5ucg?pWRM!RXdKiG+>DW`| z*L51S6uRCRn0xtW*75A#wSFFKfJqL{YjTn|BFyUk=jT32G|PjX^ev|7{`P)3dEVZ z19Bt^=v5P(kK@5AwyICfW4tM9;#oqmH*+WTDAe2OTsxHNDKytGHgv@|J4T&YmZCzn z4M3}}%?Clrwoz5Le^kX$JbKEO#y?il!K!r@-!wOVLcEv5U}=pC?=ai^r?XKTjSq8O zQ0VdYn9l=t;P8!XO&{I!UarBDde;Om+A3P+|BT~T2ESJJog10(w3txYZnJ8X4sqKg zm|zgnD*3#@&0)9}hAz^_H&#YmXj}w4P(&-3xi6Om`L&NOJ$!5ZsAqmt%y^=@3wcR- z-w&Wi98aV=^933#6i!8vCsicjJB#u1V$q94KOw?2_Ocx8$bKr+W91|~3uoUQp_@(( zJ$fuEMdPO+9ByHk#wABX6^+$E%>1GJ*0EEJRvr1X;gOEV1hEshjKrnlm~yNwSX87a zenE~g=clzle&osvo@qIJ(A%6xe+z@3x{0FYaKzQ`H-pki;tAU$cN$+Fc*TkU>_P`s|H}skqEvE}gQiY2>Gv4tt{%(l^9uI(>v!yI>@dtIl>ky=y?=abqxf7cZIr zw^hNpS^_JW!ZzXz{1Dc-;}Wpg3W3jTts4a7-Yt}n;@3%|%5-;dzB+eG@FDp>HjU$5 zMjZsWG2j?#JKE=FeYX7P(*-Er0VcysKtQ>6G|-K1)g)81FL4FQ#@Sw0C*V_5UrgK8 zj~;wk_+0S8{|i&I?!OnmLEX7rw07kA&F~hzs$+E=StYD=eLB;DkCC*`ytw$Vu+s4! zi!*+STtqKwj5-+m`y!?KzL-R|Uw6GU;Ca3M`}7{aUv#M_Q}9?;;kz2$5LzP1td4bp z4@|iDBxdQgJ5KMV^7Uyt)#=(-IOv;Fl4%lW zGVBZ5Ja!3Y!1F`F`J-@DxV(afZtIQ*`aWxfV{p?vZeDrvyT0S zC=&aBrAJF^)L}I2xX1?L6YZlkQSh8*^|LINKY2tPvyArav)?oFi1Rw5w_RY|k8W5^ zd~*?>;>@BH)~&gyh3UykYY`)Fuv+y#&wBNh9eMqMDm4)>?`=(ilp$jjnl zm?GtaPZEjUM@#=NJr(zMBN+c~{N-4}ekCrNUhuK3Jd1{xcwe+h;Rrsd;A~`|ZOTaE zU|f)+6)t_r6y}W6LT($A{+`p3e^&esF%P+yhaZ(e2~~94kq#%}Aoc7D60frk>Vo~RMfbA$N%V*v;9K=b{tTF}*>y1o)aGT=OufRCA%5$r!#h#I82R& zm7IxQ^Q9d_oBu1PcQ*fw<|?dI3A?WC0Rsj#@2zZJ@U?Y)NRk{xGUibfl}#2@8uczH z{K&}qu@FUw-RWF5M_$Sin~2pLZ=rj%L>23UD27yf(n5xn>9&qs$-H;0iB1Azp3D-ZZjgNcPmj=u*I&`fR=T zZNGTssijdT>I~Y$=*i>aJF45C2$Z~u$J0TopJ!kH>@=g3@x14Em9btV3IqOGsiMJx zUuYHceh>J@MgBp4jFCvUGEIQsT^Ziayy=XG(!AY}Kjz}kJ+9KRZN|(mrz?)Cuj$lD zAc!2dSNlIgL5w3wEbz)u)BVwA!e{?T!r74JSPJ-WBK#Gh6@Qvm!bTDu3rqRmt1#tH z_JKIUD2-no>!_=l56am|Is`rF_#ySgL`7RhW!kLN>K4l)V#!mVv9aV&zuu`9qnMx7 zXEUDf68e(l1$irM8_V$aY1KNxd;%IW8GQvo?YQsT65lav-EZBJ|J*8L8OZ{JXiI6u zQR}GEZQOI8=4E!4_A(H#A{ccY3ZIye<3aHo?%72eY;i1d)52QxY8&I@5S9cBtD&A2@FvFga$Pt% zf6R=fd>VF)QaZ-R@d&mwB8~lL-Gf)wz-ts1eEK4<_+>}_Knu$DVrj;+-2E}p$}a+3 zs%AlPnuLFkFMDyl;Xg4UC4N&=-j`%H7Ih^1H0!sp%AhS4?RMDDOMct4zYL{|hW*vJ7McAe6PYl5=eM-brUE+ZPb z3yemPCKIZbAP3ntw0Uhq!}wd80(IKjQF-eoO2&=>xT`u|z5xL|+6GSbD2=HN#=a8y z61t$u%a;|$p@2JDTKDt67ncMG?N_`5YiQA~R8aS?r;CE;hfXp!j`pFQhqLu1=)kpw z=f7??*k?Daa>h#a#MWrZyuMI{;Qs1AkLfp<{FO#Blia1i(pH{&e#nZrqO2eL_t-1R z*H!HzjcQ|%X^Cy5&wl5Jr>x6_#xh4!V9WTPUAvoC2qyHLn@v0lU*2_+?bUwEV>x1kt$ZpH9g z;g9D`*`nBI5B1madAG0Vj2Vb8ovO5C+~Y*toKei*)Y!g@q3)h*ZgK96TVNHb)L6&E&rIeF$v5~;$De8F!7cAW5f^@y?DX^qj=)xG(%0$cX6u4P_ zy5qxJz5Y~5iv)dmcKg7j+#(Viov&S9#F260NIEZB_5Ifx|EIEmyhffb0YoIWUroE> zlmB|Q`sYRG^lHL%^zPn`7{6CeHGSPLFV!=KX3eW zC5~7167V$6NpC; zvE3H6W{iM#FXQ28s?ASevQdv#-;!FB5HF!sB6*L- zh6k94CGeunrp>lKS@Q~*=+cAh2$Uhl*`E9?lJizMIMk64j_`fU4eh+aHAVmr>5qrJ zHdAsan#YgY`F7T%RL^PGL@ay=J zycKiQ<_%uH!25w~)+C6mAF9Gt9j?j!wWkm+egm6gU)0zr}=$~D+ zTV4T9Me>8tc-p_Hm>vW7YqDLg|~-jT42$d^FNYA3OT^G zi-#^*Oz38K!I}Sl9@G5nCDxel3;u`sW~F*6_`0X=X2&BPxR}@2dBvAoS0c53p6YhG z?*atnf|UFLU*nt<>IVf<3H^T}W;t!P>N5ZeTdL54IA?!Cb}0J?yWxM_^GY4Hg9~T7`O{F^|!9}YMwTc zCp5d@g-qUEzuWeO10d*ye(ch|Iz!OSozZ?74nQ9u_P*wZgw2qcoe0zkyll5_4BbO; z)$2d3t>rK45LEZ9Q0nBgVj2|{Henm@E#U<K9o#gKyVJ0oW?o82EDLKYsySd)6y9dpL0v5wGc5HWmR7(Mxn zkq{d((-7{d&KmEvE+R=O82&6_OOrXkyyovtTPr^(r3ZW~M>z{qJ{&XC#K|GP`*amC z1oZNBGi4}iJweI)KExx!BN;wYgLKh_>~UUH&!?ArmkSV32e5tfmn?JT%YA{m{^9-riZ`J;M0cjzAdqmh6U29DnLLT4N&F}p- zQQphCzqh6s`6%InZN#HMHtHh=#bmE)OWlHZJjq(v^y+d2aqYHwIBT1ntNCV#p9;I> zLRVJC1`SJwaZvip3wii|+Vhcl<52#fnN_ze_mnfBjsl9Mp5dl@`FjIgDA?pQdNOr4 zcqK!L>Q@`B+Lj#m?T+aIgtlD~;x30B+Fp4_ME@vZo!IiTyvp)D_#r=F!FRyw@YH{9 z19V>{^dNuyERU*S4D(B|2(eK*5L%S64$f6k)3W|6gXJc-) zlW1F;PO;hw5-)OLy*9RhGWFHdS&wI{4gT?H zznhq1%`}PVM+c0#QJ+;evIsxPwoDib|G#e~GU`ZzIA}3;J;7n^N-_23-v+}lnWPLV zr~@OB6E2bM_3PM=m=micIHrNLcf#Cj)l>paV+U+vpfNGC1%z1@0O4i8cwZP&BKYO^ zJPR%*QHV$fbNnwFf4Yyu+R;SgNP{`dZ-!|--5F<5lp!K7?KA4)>k;P4pF)%_Eu>Q9 za0WCT_NWa$mT`}oGbnnj9aZK*Pa0=rl|a0fKuA#6T~lH&zv4%*=BQV7iRZz4%!nQ; zN>(zwVAgwu#}n`diebk_LJ?-S`-J1zhDvy!)bk}4zVAUZue>rC%lg9!7IcF5mywcM zVCLWlKbNle=_*>`RpA*C)940ftGqC=d3i_dL1j~^A37|CU?2%j6YJ%lNbHRRx_dQw ztO8-!TTn6{9q(>v9`|#KC9usm?+n4|nD0up+V|0ctJ`~5K+AJY9Q92G1N719fZh*# zN$CLKzAw<-o7DNVeJnYdg*=A zYiNIj?`cJ#2Hvvse4dpiasK&nb6)ZcIEH9h}--tkppo_>=o8=XlUdDuDxo?6|_ zfEruh_?PxC75(wUrssq!uB$3FI#f4bH3L3rF{5l^<^A2_dBHgjFd9nw^9gCoOd&$0 z>c8jV9e6!ZqNhGQBB~NRDAs*TFZFfty-io6k+g(|g%gZn{50kc=xwHz)ZWuf`NM=9 z0{}{lDndzL1L6k?X>)2$bE^cPcG6^ZT29QJe2!Qykj_oE#S9M7#V#yl2rJ?5 z=I6v%6y*G4wSTHjYqK4g07h1SiqlbL zx3{rd$7KM?{vg~u=afH-Qn^l;#L6W70>JYM)vKw&`$eZ;hvgqq@Tq}|^@)KQ%Qs8u zg&rG#pjnWlHzzFhoIeniqs52H5@8gRDgDiOWKu`i$uoTbmWG+n!|9gbe<_Ba9p;* zXakxPFwC&ts@mccPCNz|9%>Ejt0$+cbIQO<^|@xy}c!A|D;m)O;qjX=FFkJRgKGsHOt%P8~<@rI~eeAL|}Yt2Gc-Kg7G zfOoF#^s@}gi^A5gRv}(r1{v%I`4YbhibyTA^J~sT48!r@45);4`8uCC`X9LpNa)_J zi=n5kC(k;v?Is5tj#BEC|C34FZ_MJkasPkZI0D39LoIcGhz$dWcI930AzbdZb;ixm z@gnc?zI(>@z^RSbAO5pNa!R6ME{%<@9I zReez=3ty%VdK;qc$4Fz@^1{h41PghB%MH8Cx$oa?$Z;ua9nan;y7(Eako{r`GE(j5 zqb8z<)==iQlP6x92e?YtF%MD%Dz!hk{w!6Sf2w%-{%SkxVk`n9@M=eF#|PE2ZW!3% zHQ`PImq$@{RLh@^8q~!R@yQ<4-ZYuR6MLAK}HK-1C zA%o|y!8GaF*qc{bD%+hF1qC5AJRy%KRY~Z!-9xK{33g3Va^>)cAWBXf!Y5ti1tA5G zwiy%2IPJ5Jge%XaK)$;sFW3uvKC7tEsJP{!@nU|&zV1EEm(qNY`O`XLkn(!!BaY}z zg=7PEjTz#Ho@TM?UzE7g)$82_k0se;#g2_@N<`G8)xYriGcV%);wNwpr;SjLkAY|G z_&DJf^&4rjq55?vC*{;L(8buq4SEkI;ZsGbUx&if2An+zz)cqX$i&8fK7KBH5;6WK z)4)+!2k_!mMlZ0UjM?V+e4ewK$33{Pb2k*tv#8IYXKH>PB!e0t-==cum|j|}RfF$E zoNG3zboCX&tspS>w5}6pAQV?&@6{jHi?VH3$YveYAvgP1(@d^^?|_f6arfIp>XrAJ z^UKP_0tH^LId%F+n6W?IN!4I8)W&ruIQpeHp7^j%eR4H>C=&HdV%TgNQtJgI2KeE*|?Zrbok06qIn6gc>E`z_ob(1Cp%AWK3FGAX~b^Raj-$gRm1^C4{J{H9t#{f0f2F;iP=mydEzvpJ#1b30wow#UT@ffB9_s8SR=GsrI#& zXB|BHWi`st%uE+uVTC`t?i-(mE5LqOeLcBA)_~uW`hChh(gZxGPBO>RSHxlzx7%-& zGahsY^th#^#sToQLYD<3uVJ6Q@E}i`%v&2UdBvAd71)Fi22* zjz8ccmhKrSfjoq7Jpl33E~7+2;qQo5G2=P)ayu&&YB7?ijT91+#TEz{XZ&zp;!A1} zZ$FZb7<=v>(E#y%I>|&W@~@|Ze~^#KeE-|fyOi#FQi-Grxd%LuC&9peQ%{g^o_?_M z@~BAP`g8eDXq`(=iy0QtZ?&Ir_JaDq9O|F-5i7(<@{aLG!XbyAPc>Uu9c6!ecs9#Ka5h*@*%)*N5$ob2Nw=aeNb2@+_vLrIz*!!$sTe%| z;b!9Bm-5f(KMRa#{oGew>tO3q+5h2zo;%$)(moF{iYSHPtt8zI#dHZ<=;;`xal9mr z%Vt1Oo~X{5rG&>MHWiBwMyC$D*91iz;3P5Keu-^(=HN4E)7YapEaIyRvHyvR*P6K< zQf4w4N@H9-RciQ`l^=c>Wuc*exH zOkQl>c{Y!F%Mo^Nc`w6~spOg1!Wd@wP*+s)w|BkzkH!r(B~blF(D9%?h}FJ(SxYca z@SfcXG`k{b1}7AJEFp>8MoJeFp>?l{U~uV|N4|%Ib!WJJI9mlyZd@O{#J7|>|7-mo z-x$yXn=*@xm(!A&$;JhU$AJx(Xws9p56zcby+<;50Yo#QKTv@gIKPx(RiFFR{@Wq7 zirZN%!CZ91W6NU3S#~OI={zq~)F~xedeJE1f{q&k@F9R+>w!;o&(wATkx<4@|OF{Kg}P?iMrce`7rU``trT zw9FsNEb+IW{Fk9pukLAEoPZ(jtxJ|cvL%haYj)m9--6B18lUi+Fl$Kz{!&SzlU}p+ zWZxf0FX$Ll?@Vd2VNN1+I`qYHbd`(Wi`3PS>Ss6vQok#8q~Ba(?a|)TkP(ex(Jhxj z!xWbFXdgAYrB_n4#5*g38l!$dVu#u2z<&ai{YZU=Ghu=YDI_LE;Pm}3aJr&Ip!<$n zRK*ON0v8270GWEQi2a3?A(>^iGwEe4j*7R;U{P*mfwSJm;#M9q;Ig-TzDMFFp(aC3 zLJv_nc%6}7(7_?Eu+jMl4KHi#)!eYxnYlyB2aRAqX!>zt(=H-`j(xT{fIk%6xkhPN zg*G*6{k07}OtmA$!VzumOmHoAIihs0#9I7uH)GyzX%`We{Q4i}RSu(kXK%s>y7aVB za@OHR^e>xvt-;Ns|1vC>Pro7YJXYAtXXRZu>Gl3`T0?<|ok_y`((Z~c3EP@Eo#mC+ z9WVt&5)5;F;z#`0O(|H5qOYaI3dr)_z9*Q}Uz1YBUfv2jrg|v!vck4=Em~gFzy9J^ z$dNz7lM%Wn{ZZ6Qoe7=?9rtHFoH(@ob!KZ9>f?O6wvvE40pAQ=TqaE7V*%nT0;tCw zLt0D5K0IT4+W1at2_ep`Jqdw?D}ry6~fp_4_q3_ZxJCU$SE7oN*p z0(NZb?n$YxQbHhB9IqECn@%qj%BWaabK-6?aXR-BG5c((XEeL$L3V2%xj3KOa5kYC z8#~G{Pp0s_cJUP5f%o-Y6AE=w7Gj6)HEXM`zX<0INiOp8j-7U~E5VjB^bZRyFaett zz#DqMUiFo!^RGQS>%7wUF zY@oTqTO*m9Y;b512h9AE6W9**o$)=qi`X>lfw?qHhAh1A^Yu=~CJOkM2anfk9oGz> zK)0QFIf{E`KcpyVQ9hG-!4-lO1k+^80U2%{9PC z&rSpw?*?81;)ST5GD&Tfv#o+Z{~p^Lv!^b%h%_a(A;5jV_J*)YioV$Ad~C?IM2-^mEOSx@BS@?oWJ3D&1 zW4tU2-tcNlLR*sy9C$85GGLpZ;1IvR!C14eI*!mNQLK1vZLX}VDIBbQ2<&>eni=v~c{{Y>=%^>}o`ncUPW^!NBd zwR(-3X#|oiW!VKLyEr-6(#m!VBj2t6ZvK8WC4Km2-Qix{Ibis0zb~2-KkdYWIX&cC1; zgm}dnJ52Rc2X6nW=>yQj?;j(y=GL;i(1;DeREY=IFLIs&ZmLL-S;$erRS5upo-;Q80}3RQC9}ZqgGR-%IsxROF-FYI8#K1i}>sAy`S_J&%lke12;zX|b$T zJA3!tiiEN1>(fsm2~>=QwY+!=v+_zZJ5)?lkDk&mkF0-sM$gEJN8ru3G9`F_e~dC0 zR*ZhwmAe?74!Il{!ifglLN4n@750A&MYp&tZ0zhq?}%4UQH`QwTvnS<^PWIrEU! zHsI)qo^Y_h9%n43BGA^~J*%V>CwHR=?$r!zituv9Vl#Y4nwfN@s;OL;I7IJRGP+$* z@GO&QWQ?Xcq&P@u=(upSGL_+O9MZNh;&qhPexY)ba|F{u)RHq{vJ6#7WM~GeML(AB zzS`A%b=1NNQwp&A_EZ?c9lfsvrY1T=7RvL2rbss=U|HE$_1?2uk!Q?`rRJ13KYN); zMt%AEKjM-2Y2Y|~RY%2@As0Q%gZJH;U_e=-uYgp>GwJoKqMJNiAIR-(V=p=&Wdhtz zDX{CEJN&A#U6TGm*Qb9Pyv>xOJ0Wc`f4*YZ>i4yAIt18vo=~ze#t59qM3T~iP|Ka_ zT?Ktha(6%gpNIg%a5sZj*)914Izo{KwYVNRrkHl9@S(XvWfIWZMcvvVm$=0sMDG|q z<#FI3-XFgoh1u&#m3ahIvFC~H4Qv%TOKEzQ!NUBe-hcdSO+=^h1s-H+uP~XKXz!TH zD#G>Y)AiEMfown=nlqBKorVYXS%$ykgLR|3NjO-h4J3do#KCx+hDYvM?bSHAK3z-m zv_w1cN&n~Z6P{|%r>hS07rTE0+aR#~6}||32d9I-`6i*ql&#ync4ukm?RcE8Gq@5F z6%;Cqjb|rKr#%}04RqJkE5!8@oyP$wvKLcySc8h{dF$W($gVI>Wug%)nu$}K9?jC`N=rgdZ56Elu` zajE}iv)!`~kXUQAr)%c2uE_}JEt9(jc3WcT$X6ArrdyRB{+2sW4nq@By3>_gCAjqC z_mPdpX9)1@sflb*TVQ8;zLU-GdkF-MK0QD5hF!xw(YG0Omv|Hh-meHm{OWVekq#cJ zguhB`dJxI-ow0rA);KIrC=Tr9Sj-ExlONtgw`YB~hpT$*JAl117vxER*0o_>oM%5$ zW@$eVW+sJXoWx~ajC$}U3!kWsYocMdIrSa(LaVxqdgX_?IdL&xr{baT+wzseRE-c9;b+9~Tuf;lod+ueI zRr=*BP|d3=?Z>%tnJei#*_i&Z=__ohJN?p4S?AH#4jVm{+O{IiEc!Qhzg&=IIfN%4 za;t?Zj~s1lt=Q$-m1PI!5wa4W@n2P2!C5A?jO-j7!LF=~JrTcyPwz45l6!5#-d1>8 z>W;VYsa5m1)KF1pmz+ZmlR~;i4*afPlDm5N_P4B1%OfE29?6}1%yRdvWw?NcN&o^< zy;2fK+TzoCyJTPDDYb??rU0DovYZ6&Zb-$;*Kbyy`kwmE8^MAhKKquWNj&#pU!=p% z^EK@dz%A@dcl}bUO!5AGx|R!=>Fe0?o|G*4`r&!wslubXZ+hoSmIcd6t@aG4KtOVl`nTN zK1+fiPV-HKu@%3iao1z3zr{RIkJRdt<7u9Y(W!Wa(DK<6U@8>M)8cT-BuK#}Gh)RW z<4`lF6IS8R(CUq>mF5G~S2@$YgcoUV7lf{_rQ2@GUT(maYUo032 zAFI_y4_qss53F~fMtRX=LYaP|yUq4qD*E1i&!;QAB_ECM$+zj+m^JnjTz9}Fmm;r0 zXGVlYmFJ#Iv^oucPmHs-t?5@a8})n_icV?_)z*(2yBTV!qVvU&X70<0*|_`aCnd5@ zHnhH|OCl&n^<7^1cnm@OV4y#An*%O?l0y&5zi9zVa_}DdVNL(FLgLe(5j1A^?e+rR za%bx>K~3}5MlyS`^7{r95`98T7QdsGY>>T8IhFwA;vg5qT+?t%%gN@B#${wxy@i7d zdi#BY&;x2Gnu3Fi5YHwbwqDZe%LNg|GO*{vTevJnj7T3pIP5ww@6Pw(y0nj_T6WOw z1dtW#d;Vj<;CmER@)KKjAxl5x&32 zyqf<)E*Nc&e)o0mHx(9@OT&173QopdQ;q}MM%6h%3p~3%b5HuY!X+pt+3@t!^9h!6ZbX3lR$e-$Tj z1xeTN-yyt_MHnw27(n~zq2#zW!=O)^QS0HmxQ4`>C4vX8h^ut0vog%;y%L^FflT~+ zMSp`r*uRh`Y|z}XMm5`G$`iJ)!RH*{nJ(?lQeZL!blWx=b{;Rw2XS;iw4#fHlz);J zTHNtEtzNJ01-UfA!w!L$D5WDWiR#*1%~Dh1jQrFBTODZSI7~cvgm+j!3@MoZ zC#YlwtY&KEom&h^5X+)BH;#-ROy~#0R_ABmk8tb!_XD>Ga*PI79aV#vLXN5G2Y-Gn zZ+L>RgB~-W7j=5$uUH5#(CRnx|6Sd2o-%RvvOIlpTo#8_`N zia{^I^T=|IKOPoKuRs)8+vZd{nnEGV;9#?G_tcbljI*y_DebqP+X(gbEFauhzj4Zi zFoG`LwnsNH;7^Pklru;u7I+ToPz&OA_P zY`>?(Yo!99eaxDzdr(yMzHhLP9g|F`t2%N0LNQ_ER9c$KZ9ptoQUC?skYBygc}wr9 zKKF0}9=r@Peipbj-{!xLU|`U>|8n}5wyZWT6@S#^Go_L7-7vNib z)hPa`Uh%Y=Ak7n6PA59NbBWQZV)2x5sV#;Y#eAsbO;IF+%B@_Nh$iMN}s)(XY^}Lkj*=1M{OwBj5C8pA; zNkig3nH`B2yhR~@xRK}c%}_j069XL^oUto=;pBVk(vF{q9Flg?OLU3KdE?jX(uzNh z+=q4$%&$=%OJ-~ZkcOLR^EkAKosJS7?M#}$!ArvtMd6!3siAj2G{~?9;Me&%cqLhN z8|e0zg|{JX1fo3V#x&YV|Gg`#;x@q96&t|-{-^C?-}gFj-0b@CrIfoU^;K5XnjfX< zN)Cz}!;Q?`2wOw#C&W3ML`v**@IZH=<(DdOHn=-G@xdIrX1*)>HLEI0JW<=&l-$7? zoH|aBCj@hBc=L=pYs8LtVsH<4!ZtIbDXKofd{5}gp_lMeu`u0-z^SjMc<`MFCCp)} z1i_cwwc0YG=h6>`b5r_FEP4u{%-X`rIZIl{2dsR=6*!K;_rQ+UQQ!@w+%W>WV*(bh zq)!a5cT@1c4ax}W|EIq=d&n zS#6fqbu5tMEE)44pBIOgeD6W|7(`3Hf6-J)>vB>6h$i%L6}^AZ-y{qffsw}s)s$e4zddZ+g< z&bEcx-rVP~%UhpHBz9%Lkzr#b;}+rM#wclp(`HbLPt;zVl^tjJM zSRflWQ@Fis7}x2i0nar3Z-$4ld6*ioFE@?ldCw)Ti01u}Yly4r&g~nNgv?nizqBZK zG3?Q0?>NBSih#Cx+-*aCa^#m<`I=1}UJMh}GcBVseUIhn_m2mUOMcfT`hf4^Yd2|opO}M!+=Tny453>J)ab@Vb!iliyzgqft@KIU zO6g;_zGQo!Xpf-oGUAyplu>VUOyK+y$E??r0WdRX%0ejFbP zVJnYt-oKa49K=2eGz78WjA9xZWDPaXAlcOBEQeHEFDO}E|1M=23|lXM<~+w|$NOUf z*GO48VDHYuw_#FNc`%aD(|wB9D(R2^agm4oD)3>%+4)ul#~|Zx6(La(t)v^*0-n@c z6MPTY`$9RE>2kAMdSsVY8IQAVU?WXbN{kndqHNWcBMdH{6;sunug<)GD5}~K*Y|0AOP9wJ;WIpw z4W^U|gBAbk*`X@h6U&(itdi_6y{Fo2ef6#1{`tZeYmFuv?RLBO?#SnvuNF8&euy%D zpt+9fExJ>#*BH~}ik)OLeleH6^{Ccrq%mWFY{1O)(hT@aUEp~W`-L*?IS>Jex1V55 zuN(9k-M~UF=^@v({p}D>S{`5#(#n7~C4t09<9)QCE({ET@d`Wht!FfJBYdK-cMtz? zZm!oee518^6(HPZEm$j!GHZ=lH!=;Z&zk=rZDU-c(q3pFp8LII_b-_RF`fIdWWo&( zZC4HqzI}q8`w{s&yYd%w$vgBi_*RZNJUBuAHu!Hn?|u_YJFm;Ud*WRv)+VQ#SpE0l z<)_jLmAL;Bh-894Uu4<6E@B;IBaQD#JhxRyW*L3r=#?T^IiL6(aK}A|uAVlU)=FN5 z_{IN;NMMubNK*v$mc%#VCQCMlwACv}Y5s5tzDUQZcjOLul=yy9Z_CHg$;k-$J$gq< z#S%nm>(D|rxpT)kNY=ah-cGA5!6l^B^zsiC(_OssY)693uiUBef#y331M%9)K_xQb zP?yxd2lBdvSUJTKQ!nxs3LUQR`&HfM7oeo|$HzFIr)u4pUnb=F^EI`yB{6EJHSWHw zEK+NLFMkE{;MHzYgsP_qP6`+Fj*wWb)??nIDDDhCSb+zv@5pIhYq0R6hYrs;?F7Iu z|2e>oLVF43Q4IHeV5)ziIiY(lP|J%ej2{KE4jWc499fjRx0^6NLT&G7u5mAUYbidx zSWJDw&!!@ovhqg^GCf;WDY%$kNy?Ee_UEFWE=N?z&1ube^+Hi)jIZ4v50j35*?Oro z(d;7X-L(XTbvCz6vQ^!6!)hy3cQ=2%o~+)Hc~vox#%q7?aFE{UD7I3Pad)z9t1>2a z?DJq>@tUL?IgW6}*8C{-92BM)9@JW{<-AXCN1Cy*gH{bKDoFDMhFgWc)Pa zMfg0}n%XmAz06GJBOJN~?ge7{!NXBDTT9~cD4=2^)UK)PXzw51Gkk5k0(Z3unl7cg zDVOM2^w7gHHI$LgN<$c0E#3M~c|?7O_G#Y0t0g05KK9KXb_@S}x`FyLwjW!6Q+#h| zsU5S$UPm>sXm9We_G23=dJpdozIF;xD`2=(YgMoNQ-j2*Xqe2({~~MjLV)F^n_Q{g z!Afu+Mc#{5;mF(Y^3s(s|c0{e2^R~bcDYz3ehcBXCn5`G$xgM ze-N`0VMY#|wjXp)GxQe;0F{CSjo_H087*#yOP`%LzAMJzwv2T zIpzwHgTwi&TH=%X98Q|?$Iss77<6aJ@wRrEw>O64LZq2dH(8JGC~G&SPm9%^RhE@M z%NFu$Kqt5ZW=g5=$i^2b(p}l-T6*VsbF~IQg1^ILrY64jmvl3GB7V|S7f|#h#NTW* zp+0GI8|vub@c1U@z} z5Zv#KAgb;ZM*19mdrbEnC3!Ly37(FL^Vo63>2FQ;lC!TS`oSBSVr1R9bn7)ZjYq20 z5n?%gd;NSzG@^roP%eG^>0&shOh&5FOpUWI6M^p39d%YRim^Si6p_m#(eV12{NrMw z5u(1Qm9n^XUaWIRp(4~Nw)7vhILvd`0uzuH_ocSgzaD?M%}^CJ2r89?CPY1z2>-!& zmdRy>w}**i@v&yUxio-j>>ck4VYrT8INPY(7>#YavC%kb>^5d&+cq0b z>@;W^H@4MSjcsFM&zZdazH`o>%>0_`d2(;8z4pG>maOSc)Csl?3zBFIwu8Ah-JM&` zqMlcs<3oE&I$bYY&a!jhOGv*AB~2&*tEst&9NLKfH0jGe5f(8&LbG%dbQ}YpJTTsf zrs*jfloSafG#QExkR$^y-5C!AH`grMkRhSlHoKa`!StutCYhzf;)=3wfyyEd+})HD zKKf6>ur4G&JYE=MV<*C3HZponWpN$`y)odMEBmZ?eSs$+8nHb{jjamO%(v%i(eW2u z=(k=}sH0yHbk7QD53NM})>x{UgS-vh8wl{cTu7$D}l5!2aosYk}r z3%S3^25T2&N?nEt;kZTW=&C|DA>#cEp1l7eujJ#ZQ4I*am-g7C`$+bR-CcIciS{!V?04D4|N z1HY@h!|$~vJ#@DJ!odw<>y|kf7dQ=83qS^~_Mll1|B>m3AGT_gwwc8N{n63Y27;3c z<6F(Pp~eeqAc#}KP3{*$kx}COFkrj&+kOdLZ5Gn@S;*{6L-Mx*;$Yzo-wrGlOkeup zzyp>LLLt0C?TG#Uq-^~niF{4MKqH47euBQ+xqO>IwYwj_GAdE5OWcU0!pW%BFv(xt zs!jL<Rou*x+TOQZ@p7_#b6rno;tJO zD2IOd-`ix*Ebk8qj-b&XJ+O>ePhZ5$x0k%2w^~3pciHTid@~7iwmhRIHXCfoy0?t+ zk-X}tyW-X}iMfFFuy&kIeCi&Je`UQN&q7RwaUKmsca^LrSO4u%Ch|iS1_NUY!!>o* zHMf1@3T$g;3hj!e<>$7$_(H0srs)7xc#}*_>vEG)Kwy37P>2eY3W3ZtW-2>o=Kbd6 z)xn7v%eSR|NWJ9GyCNRqqK&$^RE5;b>=PzT zRbcCxGzKfpfo+J4@hu(!wA0n6VEIdnIC535G$FCT3TB#Zo7;3fi;Z>X_>Zp=gv%7N zhBQ{69-K&Sk(swWkqzgJW?`tMhj+0IVD<4)4HWp%iQ8U0`&h-R#o$~BK4>;ovK(eT zWR5jo@*@lD@uTPXWSfF<=NB-IsPQ0zxWQz5s_}XIK-OTB^M+oYNg@*dm(uo4nDIc= zud(xZsR+69DL0m~m=j4?hR!)9^9@XsQQugKY3C*G^Wwzm`<#|>890nUZfwL_PQ28- z9=m2Hg0xbEC5cs1;xGTtLBOZwv;`Vt@-2m6=*%;zFukBvF>cjPCoXj=3}ll?B~KT2 z{#hhPSmq-Bp&MIPsqwq&)5hJ{YkJdbOy-Jb=|#z2yFl``6%V-2>j>-Z=0!Z%xdKPIq^Kh^ON$17 z4@eX4Ouv28P5gY8VoW+!*X{<*fAj?~Hy0ds3czAtxS@&*h_?$$U`j?#+|llVz4@6Q zho%D7u;g=FdERk;cw?&(QY>~Xh{8u^)oa8zIvWT!yPJy+=y^{OTK{sp*8nKv=&l_; zhyeD-;sVvTMBl{k!82k~ zgJGYRiJ9KCYfqW9mY_DvsA7IV{v2=cueU2N?|&da&n=R~B%5KloDgPZl6E(SiKZ)O zZ5jP198I#& zcwg3$`Y~)b_58v?db7@DdUFU%J=tVHkEu~$`=R2LtJ*5R-Mt%L8VUonpPp$58K z3lp$ub076I04ag6tsw5JKW9oeQTF`-E@60GmmOftgKiu=O*;DnkwHul3GvQ~bsg)` z-k6yG#KBs*Kt77!5}fO=1Yj`1aD~Iu3Hg|=eW^PF7 zp4(=S`OTuGaf=P=8#O8&2Ec@;(Di$)hI_5zdKY^W&hw^?zdS|mta~eyetN|8u16dN zSR(}xlCTU1N*u$LBsWA0YFJSqm(|S8IXcTw(?ecBIixM0;m>_Qd9!Lo`>Jfbno+$( zryIQPJ5_2SN;bus!P>y+xc;Jjn-DHCZL>RKJKRXTLKDqqn3&v61N?sGeX8+7m5Kvm zq0-j_DxbY$5O9z{eml62)F`Al)}A>O&Q9C3+MVW@6kSUdxT?0p|J30BE6svK&QM5G z`bF@hmTuvA&pZotx}vg!*|`%Vlt3I}MZrQt-ORxXI7Wr%PF$4IV=mWwFiZ>Rq+431 zjN%=p*)6ek?qB>}hrJRMWBMsIUmkbJrKx}KZJTwzfz~8IJz$XKlHqbgo2OJZ4`7~~ ze5t@I24P@jn`5e(c|;mH^HkJ3x-duDU&nj?$E2Ly-l`p`Oq z{ONhALWa@4x~BAm9lDdk7jV0@nlnGY0dm3PP0p=xyt~~soB?zBvB6Gf(yk!Nd2Q)K z9m7Cp3__;%4}-MdE2XJHyNkvFQC!r+edSPLVLuJ1T+qM8|5Veu=m7*LU6XzTr=fr@ zQm^U)Ln_x z!SvWe%qPS35EsPy(v4Oz5jri?A`h`~A?7cmjGvbu67h#J*e`0fwKQ?f9iG1-1N;9) zfPe}x>?2l<&HKJ#dILn_M62;9e%YnPKNAon7RvQ>@75;+LXmce3t5 z&=B`$v!y5bDio7aYX>41A=@Q|dyz7D+%^t>6j{k9rh0_M)Wu$dDL4sDFb<_$jQrl5 z0pSg$M&B)?3XS?cIsoAIesCQh|HC_Gy1*{Mw;^ZqH{(i-hy~S}bL7UxoKSk%B|wPG zSi-VafLISb;C^lEwv8|^8{;^1XQb-k%QsZ}P|C>GiB`>)^rj9Td6{|q@8af=@IR+1 z_kBAPm_BF;;H_ewj?|-LK^#%h`d5N_6rR#wT6TT~4as)f z=6mSP%zl6B!jUQ?} zGHh~^E?I|-Lq^k1Guj8W$U#Pm2Bu7f$2N{Y)j9xGm~r!)4a@@fw@a(+h%Qh4 zhL$OQ&{qns($qM!=4JzX*7#VRfzM$>quJeBcnMVdtiU;J*X$2NlAX5aY%uP|Yh%pV z@!o5GFmg|@UOu0iRO{|`S#txKk=NqqGIRSwPqDbFYFO6&-?1MK=xF(0kdMa&6^|*8 zw^5A2VDIMJ1gjWgB3(yI>I|TKGSU8{65QR+2a?fTuAc1?g>&)m6;Kt$MmQ)-$hPe# zySXBW&+~u}gV^K4a&V~Y>}||qTv5;flm~+q%2MsV>PaatPWwMLNi|Aq}Q-MPJ_pB;er5LATwh0K$u10=g08J6v9?3zG18=8!O7OirCy*K;_dQ98ii@9^CMW044Ez*&HCyvMn<51D^5ifWwHq zeK&0i7oZ6Hp|^fWEdPltlqcAP6gFbKJSF7DlLJsE5i^_i;Z$uBJ_NHk;UV&_qRWS> z{P>AsG8X76(T*_0!C@im+VA;Xay;lh0+a0?_hFuwqQ|)?J$~-4^+%pyh*uRUf26CW zxo{$hH!l4yBSj6j(taD1(-;1=NFY_ID@_y^9@>}Cq7Y>Fzd%(s!E3kO-r5eu(%o-*FRoPn_}FQ242Hxiu%OUSvJcTPkZMSBwbMK={7Ws=2XrlzTm|)Nd)uaC{tT9Wj6uuc2imYd zsX+xb5x8qBW8I@YX|Ed(AvaUz8M9*&GMb+Assw#yu;SS@m8)d-S=6S{JN{#^zmsD5 zS?XO>D3`j7wCQUIt1%zt6LL#>uLxf=s|L-E6NUOx2OQ7HESh| z$m^q}vUXEi?5v99+$mn^K1G)g1C$QrY~+!?KiTuG(5WGYj-S%VV|GPo`~0|2mttR{ zS&TD7di>G9>Bhf#K$AN;q}Xu`V)D6(*owI%IN4+_90#6@}|khIU_ji_W} zs7OxjQn7+>GvRI(PV%`r8XzdnRd5=NFC#{#>#`7GaY@vViQv63Gw61*w+YLEYiEVwNzr9|VI%^l_hl z`Te6({$n6CUxs+VTb{C14+$Kor=tqsrUFgn)NrI>qffXwQ-5Jg2f%μlIktv+m3 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 z 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 literal 0 HcmV?d00001 diff --git a/noir/docs/static/img/solidity_verifier_ex.png b/noir/docs/static/img/solidity_verifier_ex.png new file mode 100644 index 0000000000000000000000000000000000000000..e0f381ff424d8abeefc19e82f20678e922252095 GIT binary patch literal 1177990 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

N5GqT#q0#Jxgbb94*&(h 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%0D?P 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

<@<2TYLQJN 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

3&~vS!p{Udb9JJZ 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 z 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

?;n!4VD~ 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%0D!dBtRaWANRJ_#0zy1PUY0Jq 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�JE>7<_kz^OM^ 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 O&s7T>^Ey-a=>G=~KfMS5 literal 0 HcmV?d00001 diff --git a/noir/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md index 8b4416beba1..d4daae605a2 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md @@ -144,4 +144,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./02_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md index 9fb4177c2a8..36c2b593fcd 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md +++ b/noir/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md @@ -110,4 +110,4 @@ fn main() { ``` You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). +[here](https://github.com/noir-lang/noir/blob/master/test_programs/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md index 6955f7a1e64..142cd02b94c 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md +++ b/noir/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md @@ -251,6 +251,6 @@ By saving, your app will refresh and here's our complete Tiny Noir App! ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md index 6e6b19b6861..d3af3cf7c3b 100644 --- a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -71,7 +71,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md index 8b4416beba1..d4daae605a2 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md @@ -144,4 +144,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./02_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md index c51ed61de52..795baa59d59 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md +++ b/noir/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md @@ -255,6 +255,6 @@ You can find the complete app code for this guide [here](https://github.com/noir ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md index 6e6b19b6861..d3af3cf7c3b 100644 --- a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -71,7 +71,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md index 8b4416beba1..d4daae605a2 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md @@ -144,4 +144,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./02_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md index 9fb4177c2a8..36c2b593fcd 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md +++ b/noir/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md @@ -110,4 +110,4 @@ fn main() { ``` You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). +[here](https://github.com/noir-lang/noir/blob/master/test_programs/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md index c51ed61de52..795baa59d59 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md +++ b/noir/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md @@ -255,6 +255,6 @@ You can find the complete app code for this guide [here](https://github.com/noir ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md index 6e6b19b6861..d3af3cf7c3b 100644 --- a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -71,7 +71,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md index 8b4416beba1..d4daae605a2 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md @@ -144,4 +144,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./02_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md index 9fb4177c2a8..36c2b593fcd 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md +++ b/noir/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md @@ -110,4 +110,4 @@ fn main() { ``` You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). +[here](https://github.com/noir-lang/noir/blob/master/test_programs/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md index c51ed61de52..795baa59d59 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md +++ b/noir/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md @@ -255,6 +255,6 @@ You can find the complete app code for this guide [here](https://github.com/noir ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md index 6e6b19b6861..d3af3cf7c3b 100644 --- a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -71,7 +71,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md index 8b4416beba1..d4daae605a2 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md @@ -144,4 +144,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./02_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md index 9fb4177c2a8..36c2b593fcd 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md +++ b/noir/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md @@ -110,4 +110,4 @@ fn main() { ``` You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). +[here](https://github.com/noir-lang/noir/blob/master/test_programs/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md index c51ed61de52..795baa59d59 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md +++ b/noir/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md @@ -255,6 +255,6 @@ You can find the complete app code for this guide [here](https://github.com/noir ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md index 6e6b19b6861..d3af3cf7c3b 100644 --- a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -71,7 +71,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md b/noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md index 8b4416beba1..d4daae605a2 100644 --- a/noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md +++ b/noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md @@ -144,4 +144,4 @@ corresponding error instead. Congratulations, you have now created and verified a proof for your very first Noir program! -In the [next section](breakdown), we will go into more detail on each step performed. +In the [next section](./02_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md index 9fb4177c2a8..36c2b593fcd 100644 --- a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md +++ b/noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md @@ -110,4 +110,4 @@ fn main() { ``` You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). +[here](https://github.com/noir-lang/noir/blob/master/test_programs/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md b/noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md index c51ed61de52..795baa59d59 100644 --- a/noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md +++ b/noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md @@ -255,6 +255,6 @@ You can find the complete app code for this guide [here](https://github.com/noir ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md index 6e6b19b6861..d3af3cf7c3b 100644 --- a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md @@ -71,7 +71,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md b/noir/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md index db9ad0e99f8..2f7be604401 100644 --- a/noir/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md +++ b/noir/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md @@ -47,7 +47,7 @@ In a standard recursive app, you're also dealing with at least two circuits. For - `main`: a circuit of type `assert(x != y)` - `recursive`: a circuit that verifies `main` -For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir/noir-examples) repository. We will *not* be using it as a reference for this guide. +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir-lang/noir-examples) repository. We will *not* be using it as a reference for this guide. ## Step 1: Setup diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md index 8d573adb3be..d2b42d67b7c 100644 --- a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md +++ b/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -72,7 +72,7 @@ does indeed lie on `c` by calling `c.contains(p1)`. ## Examples The -[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/crates/nargo_cli/tests/test_data/ec_baby_jubjub/src/main.nr) +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more interesting examples in Noir would be: diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md b/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md index 443ca2b45a5..d59e4c5d7c6 100644 --- a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md +++ b/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md @@ -111,4 +111,4 @@ fn main() { ``` You can see an example of generics in the tests -[here](https://github.com/noir-lang/noir/blob/master/tooling/nargo_cli/tests/execution_success/generics/src/main.nr). +[here](https://github.com/noir-lang/noir/blob/master/test_programs/execution_success/generics/src/main.nr). diff --git a/noir/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md b/noir/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md index 302ee4aeade..0763b6224c9 100644 --- a/noir/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md +++ b/noir/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md @@ -256,6 +256,6 @@ You can find the complete app code for this guide [here](https://github.com/noir ## Further Reading -You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/next-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md b/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md new file mode 100644 index 00000000000..b84ca5dd986 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md @@ -0,0 +1,57 @@ +--- +title: Oracles +description: This guide provides an in-depth understanding of how Oracles work in Noir programming. Learn how to use outside calculations in your programs, constrain oracles, and understand their uses and limitations. +keywords: + - Noir Programming + - Oracles + - JSON-RPC + - Foreign Call Handlers + - Constrained Functions + - Blockchain Programming +sidebar_position: 1 +--- + +If you've seen "The Matrix" you may recall "The Oracle" as Gloria Foster smoking cigarettes and baking cookies. While she appears to "know things", she is actually providing a calculation of a pre-determined future. Noir Oracles are similar, in a way. They don't calculate the future (yet), but they allow you to use outside calculations in your programs. + +![matrix oracle prediction](@site/static/img/memes/matrix_oracle.jpeg) + +A Noir program is usually self-contained. You can pass certain inputs to it, and it will generate a deterministic output for those inputs. But what if you wanted to defer some calculation to an outside process or source? + +Oracles are functions that provide this feature. + +## Use cases + +An example usage for Oracles is proving something on-chain. For example, proving that the ETH-USDC quote was below a certain target at a certain block time. Or even making more complex proofs like proving the ownership of an NFT as an anonymous login method. + +Another interesting use case is to defer expensive calculations to be made outside of the Noir program, and then constraining the result; similar to the use of [unconstrained functions](../noir/concepts//unconstrained.md). + +In short, anything that can be constrained in a Noir program but needs to be fetched from an external source is a great candidate to be used in oracles. + +## Constraining oracles + +Just like in The Matrix, Oracles are powerful. But with great power, comes great responsibility. Just because you're using them in a Noir program doesn't mean they're true. Noir has no superpowers. If you want to prove that Portugal won the Euro Cup 2016, you're still relying on potentially untrusted information. + +To give a concrete example, Alice wants to login to the [NounsDAO](https://nouns.wtf/) forum with her username "noir_nouner" by proving she owns a noun without revealing her ethereum address. Her Noir program could have a oracle call like this: + +```rust +#[oracle(getNoun)] +unconstrained fn get_noun(address: Field) -> Field +``` + +This oracle could naively resolve with the number of Nouns she possesses. However, it is useless as a trusted source, as the oracle could resolve to anything Alice wants. In order to make this oracle call actually useful, Alice would need to constrain the response from the oracle, by proving her address and the noun count belongs to the state tree of the contract. + +In short, **Oracles don't prove anything. Your Noir program does.** + +:::danger + +If you don't constrain the return of your oracle, you could be clearly opening an attack vector on your Noir program. Make double-triple sure that the return of an oracle call is constrained! + +::: + +## How to use Oracles + +On CLI, Nargo resolves oracles by making JSON RPC calls, which means it would require an RPC node to be running. + +In JavaScript, NoirJS accepts and resolves arbitrary call handlers (that is, not limited to JSON) as long as they matches the expected types the developer defines. Refer to [Foreign Call Handler](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) to learn more about NoirJS's call handling. + +If you want to build using oracles, follow through to the [oracle guide](../how_to/how-to-oracles.md) for a simple example on how to do that. diff --git a/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md b/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md new file mode 100644 index 00000000000..8f992ec29fd --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md @@ -0,0 +1,177 @@ +--- +title: Recursive proofs +description: Explore the concept of recursive proofs in Zero-Knowledge programming. Understand how recursion works in Noir, a language for writing smart contracts on the EVM blockchain. Learn through practical examples like Alice and Bob's guessing game, Charlie's recursive merkle tree, and Daniel's reusable components. Discover how to use recursive proofs to optimize computational resources and improve efficiency. + +keywords: + [ + "Recursive Proofs", + "Zero-Knowledge Programming", + "Noir", + "EVM Blockchain", + "Smart Contracts", + "Recursion in Noir", + "Alice and Bob Guessing Game", + "Recursive Merkle Tree", + "Reusable Components", + "Optimizing Computational Resources", + "Improving Efficiency", + "Verification Key", + "Aggregation Objects", + "Recursive zkSNARK schemes", + "PLONK", + "Proving and Verification Keys" + ] +sidebar_position: 1 +--- + +In programming, we tend to think of recursion as something calling itself. A classic example would be the calculation of the factorial of a number: + +```js +function factorial(n) { + if (n === 0 || n === 1) { + return 1; + } else { + return n * factorial(n - 1); + } +} +``` + +In this case, while `n` is not `1`, this function will keep calling itself until it hits the base case, bubbling up the result on the call stack: + +```md + Is `n` 1? <--------- + /\ / + / \ n = n -1 + / \ / + Yes No -------- +``` + +In Zero-Knowledge, recursion has some similarities. + +It is not a Noir function calling itself, but a proof being used as an input to another circuit. In short, you verify one proof *inside* another proof, returning the proof that both proofs are valid. + +This means that, given enough computational resources, you can prove the correctness of any arbitrary number of proofs in a single proof. This could be useful to design state channels (for which a common example would be [Bitcoin's Lightning Network](https://en.wikipedia.org/wiki/Lightning_Network)), to save on gas costs by settling one proof on-chain, or simply to make business logic less dependent on a consensus mechanism. + +## Examples + +Let us look at some of these examples + +### Alice and Bob - Guessing game + +Alice and Bob are friends, and they like guessing games. They want to play a guessing game online, but for that, they need a trusted third-party that knows both of their secrets and finishes the game once someone wins. + +So, they use zero-knowledge proofs. Alice tries to guess Bob's number, and Bob will generate a ZK proof stating whether she succeeded or failed. + +This ZK proof can go on a smart contract, revealing the winner and even giving prizes. However, this means every turn needs to be verified on-chain. This incurs some cost and waiting time that may simply make the game too expensive or time-consuming to be worth it. + +As a solution, Alice proposes the following: "what if Bob generates his proof, and instead of sending it on-chain, I verify it *within* my own proof before playing my own turn?". + +She can then generate a proof that she verified his proof, and so on. + +```md + Did you fail? <-------------------------- + / \ / + / \ n = n -1 + / \ / + Yes No / + | | / + | | / + | You win / + | / + | / +Generate proof of that / + + / + my own guess ---------------- +``` + +### Charlie - Recursive merkle tree + +Charlie is a concerned citizen, and wants to be sure his vote in an election is accounted for. He votes with a ZK proof, but he has no way of knowing that his ZK proof was included in the total vote count! + +If the vote collector puts all of the votes into a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree), everyone can prove the verification of two proofs within one proof, as such: + +```md + abcd + __________|______________ + | | + ab cd + _____|_____ ______|______ + | | | | + alice bob charlie daniel +``` + +Doing this recursively allows us to arrive on a final proof `abcd` which if true, verifies the correctness of all the votes. + +### Daniel - Reusable components + +Daniel has a big circuit and a big headache. A part of his circuit is a setup phase that finishes with some assertions that need to be made. But that section alone takes most of the proving time, and is largely independent of the rest of the circuit. + +He might find it more efficient to generate a proof for that setup phase separately, and verify that proof recursively in the actual business logic section of his circuit. This will allow for parallelization of both proofs, which results in a considerable speedup. + +## What params do I need + +As you can see in the [recursion reference](noir/standard_library/recursion.md), a simple recursive proof requires: + +- The proof to verify +- The Verification Key of the circuit that generated the proof +- A hash of this verification key, as it's needed for some backends +- The public inputs for the proof +- The input aggregation object + +It also returns the `output aggregation object`. These aggregation objects can be confusing at times, so let's dive in a little bit. + +### Aggregation objects + +Recursive zkSNARK schemes do not necessarily "verify a proof" in the sense that you expect a true or false to be spit out by the verifier. Rather an aggregation object is built over the public inputs. + +In the case of PLONK the recursive aggregation object is two G1 points (expressed as 16 witness values). The final verifier (in our case this is most often the smart contract verifier) has to be aware of this aggregation object to execute a pairing and check the validity of these points. + +So, taking the example of Alice and Bob and their guessing game: + +- Alice makes her guess. Her proof is *not* recursive: it doesn't verify any proof within it! It's just a standard `assert(x != y)` circuit +- Bob verifies Alice's proof and makes his own guess. In this circuit, he is verifying a proof, so it needs to output an `aggregation object`: he is generating a recursive proof! +- Alice verifies Bob's *recursive proof*, and uses Bob's `output aggregation object` as the `input aggregation object` in her proof... Which in turn, generates another `output aggregation object`. + +One should notice that when Bob generates his first proof, he has no input aggregation object. Because he is not verifying an recursive proof, he has no `input aggregation object`. In this case, he may use zeros instead. + +We can imagine the `aggregation object` as the baton in a [relay race](https://en.wikipedia.org/wiki/Relay_race). The first runner doesn't have to receive the baton from anyone else, as he/she already starts with it. But when his/her turn is over, the next runner needs to receive it, run a bit more, and pass it along. Even though every runner could theoretically verify the baton mid-run (why not? 🏃🔍), only at the end of the race does the referee verify that the whole race is valid. + +## Some architecture + +As with everything in computer science, there's no one-size-fits all. But there are some patterns that could help understanding and implementing them. To give three examples: + +### Adding some logic to a proof verification + +This would be an approach for something like our guessing game, where proofs are sent back and forth and are verified by each opponent. This circuit would be divided in two sections: + +- A `recursive verification` section, which would be just the call to `std::verify_proof`, and that would be skipped on the first move (since there's no proof to verify) +- A `guessing` section, which is basically the logic part where the actual guessing happens + +In such a situation, and assuming Alice is first, she would skip the first part and try to guess Bob's number. Bob would then verify her proof on the first section of his run, and try to guess Alice's number on the second part, and so on. + +### Aggregating proofs + +In some one-way interaction situations, recursion would allow for aggregation of simple proofs that don't need to be immediately verified on-chain or elsewhere. + +To give a practical example, a barman wouldn't need to verify a "proof-of-age" on-chain every time he serves alcohol to a customer. Instead, the architecture would comprise two circuits: + +- A `main`, non-recursive circuit with some logic +- A `recursive` circuit meant to verify two proofs in one proof + +The customer's proofs would be intermediate, and made on their phones, and the barman could just verify them locally. He would then aggregate them into a final proof sent on-chain (or elsewhere) at the end of the day. + +### Recursively verifying different circuits + +Nothing prevents you from verifying different circuits in a recursive proof, for example: + +- A `circuit1` circuit +- A `circuit2` circuit +- A `recursive` circuit + +In this example, a regulator could verify that taxes were paid for a specific purchase by aggregating both a `payer` circuit (proving that a purchase was made and taxes were paid), and a `receipt` circuit (proving that the payment was received) + +## How fast is it + +At the time of writing, verifying recursive proofs is surprisingly fast. This is because most of the time is spent on generating the verification key that will be used to generate the next proof. So you are able to cache the verification key and reuse it later. + +Currently, Noir JS packages don't expose the functionality of loading proving and verification keys, but that feature exists in the underlying `bb.js` package. diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md b/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md new file mode 100644 index 00000000000..743c4d8d634 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md @@ -0,0 +1,142 @@ +--- +title: Creating a Project +description: + Learn how to create and verify your first Noir program using Nargo, a programming language for + zero-knowledge proofs. +keywords: + [ + Nargo, + Noir, + zero-knowledge proofs, + programming language, + create Noir program, + verify Noir program, + step-by-step guide, + ] +sidebar_position: 1 + +--- + +Now that we have installed Nargo, it is time to make our first hello world program! + +## Create a Project Directory + +Noir code can live anywhere on your computer. Let us create a _projects_ folder in the home +directory to house our Noir programs. + +For Linux, macOS, and Windows PowerShell, create the directory and change directory into it by +running: + +```sh +mkdir ~/projects +cd ~/projects +``` + +## Create Our First Nargo Project + +Now that we are in the projects directory, create a new Nargo project by running: + +```sh +nargo new hello_world +``` + +> **Note:** `hello_world` can be any arbitrary project name, we are simply using `hello_world` for +> demonstration. +> +> In production, the common practice is to name the project folder as `circuits` for better +> identifiability when sitting alongside other folders in the codebase (e.g. `contracts`, `scripts`, +> `test`). + +A `hello_world` folder would be created. Similar to Rust, the folder houses _src/main.nr_ and +_Nargo.toml_ which contain the source code and environmental options of your Noir program +respectively. + +### Intro to Noir Syntax + +Let us take a closer look at _main.nr_. The default _main.nr_ generated should look like this: + +```rust +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` + +The first line of the program specifies the program's inputs: + +```rust +x : Field, y : pub Field +``` + +Program inputs in Noir are private by default (e.g. `x`), but can be labeled public using the +keyword `pub` (e.g. `y`). To learn more about private and public values, check the +[Data Types](../../noir/concepts/data_types/index.md) section. + +The next line of the program specifies its body: + +```rust +assert(x != y); +``` + +The Noir syntax `assert` can be interpreted as something similar to constraints in other zk-contract languages. + +For more Noir syntax, check the [Language Concepts](../../noir/concepts/comments.md) chapter. + +## Build In/Output Files + +Change directory into _hello_world_ and build in/output files for your Noir program by running: + +```sh +cd hello_world +nargo check +``` + +Two additional files would be generated in your project directory: + +_Prover.toml_ houses input values, and _Verifier.toml_ houses public values. + +## Prove Our Noir Program + +Now that the project is set up, we can create a proof of correct execution of our Noir program. + +Fill in input values for execution in the _Prover.toml_ file. For example: + +```toml +x = "1" +y = "2" +``` + +Prove the valid execution of your Noir program: + +```sh +nargo prove +``` + +A new folder _proofs_ would then be generated in your project directory, containing the proof file +`.proof`, where the project name is defined in Nargo.toml. + +The _Verifier.toml_ file would also be updated with the public values computed from program +execution (in this case the value of `y`): + +```toml +y = "0x0000000000000000000000000000000000000000000000000000000000000002" +``` + +> **Note:** Values in _Verifier.toml_ are computed as 32-byte hex values. + +## Verify Our Noir Program + +Once a proof is generated, we can verify correct execution of our Noir program by verifying the +proof file. + +Verify your proof by running: + +```sh +nargo verify +``` + +The verification will complete in silence if it is successful. If it fails, it will log the +corresponding error instead. + +Congratulations, you have now created and verified a proof for your very first Noir program! + +In the [next section](./project_breakdown.md), we will go into more detail on each step performed. diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md b/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md new file mode 100644 index 00000000000..6160a102c6c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md @@ -0,0 +1,199 @@ +--- +title: Project Breakdown +description: + Learn about the anatomy of a Nargo project, including the purpose of the Prover and Verifier TOML + files, and how to prove and verify your program. +keywords: + [Nargo, Nargo project, Prover.toml, Verifier.toml, proof verification, private asset transfer] +sidebar_position: 2 +--- + +This section breaks down our hello world program from the previous section. We elaborate on the project +structure and what the `prove` and `verify` commands did. + +## Anatomy of a Nargo Project + +Upon creating a new project with `nargo new` and building the in/output files with `nargo check` +commands, you would get a minimal Nargo project of the following structure: + + - src + - Prover.toml + - Verifier.toml + - Nargo.toml + +The source directory _src_ holds the source code for your Noir program. By default only a _main.nr_ +file will be generated within it. + +### Prover.toml + +_Prover.toml_ is used for specifying the input values for executing and proving the program. You can specify `toml` files with different names by using the `--prover-name` or `-p` flags, see the [Prover](#provertoml) section below. Optionally you may specify expected output values for prove-time checking as well. + +### Verifier.toml + +_Verifier.toml_ contains public in/output values computed when executing the Noir program. + +### Nargo.toml + +_Nargo.toml_ contains the environmental options of your project. It contains a "package" section and a "dependencies" section. + +Example Nargo.toml: + +```toml +[package] +name = "noir_starter" +type = "bin" +authors = ["Alice"] +compiler_version = "0.9.0" +description = "Getting started with Noir" +entry = "circuit/main.nr" +license = "MIT" + +[dependencies] +ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"} +``` + +Nargo.toml for a [workspace](../../noir/modules_packages_crates/workspaces.md) will look a bit different. For example: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +#### Package section + +The package section defines a number of fields including: + +- `name` (**required**) - the name of the package +- `type` (**required**) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract +- `authors` (optional) - authors of the project +- `compiler_version` - specifies the version of the compiler to use. This is enforced by the compiler and follow's [Rust's versioning](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field), so a `compiler_version = 0.18.0` will enforce Nargo version 0.18.0, `compiler_version = ^0.18.0` will enforce anything above 0.18.0 but below 0.19.0, etc. For more information, see how [Rust handles these operators](https://docs.rs/semver/latest/semver/enum.Op.html) +- `description` (optional) +- `entry` (optional) - a relative filepath to use as the entry point into your package (overrides the default of `src/lib.nr` or `src/main.nr`) +- `backend` (optional) +- `license` (optional) + +#### Dependencies section + +This is where you will specify any dependencies for your project. See the [Dependencies page](../../noir/modules_packages_crates/dependencies.md) for more info. + +`./proofs/` and `./contract/` directories will not be immediately visible until you create a proof or +verifier contract respectively. + +### main.nr + +The _main.nr_ file contains a `main` method, this method is the entry point into your Noir program. + +In our sample program, _main.nr_ looks like this: + +```rust +fn main(x : Field, y : Field) { + assert(x != y); +} +``` + +The parameters `x` and `y` can be seen as the API for the program and must be supplied by the +prover. Since neither `x` nor `y` is marked as public, the verifier does not supply any inputs, when +verifying the proof. + +The prover supplies the values for `x` and `y` in the _Prover.toml_ file. + +As for the program body, `assert` ensures that the condition to be satisfied (e.g. `x != y`) is +constrained by the proof of the execution of said program (i.e. if the condition was not met, the +verifier would reject the proof as an invalid proof). + +### Prover.toml + +The _Prover.toml_ file is a file which the prover uses to supply his witness values(both private and +public). + +In our hello world program the _Prover.toml_ file looks like this: + +```toml +x = "1" +y = "2" +``` + +When the command `nargo prove` is executed, two processes happen: + +1. Noir creates a proof that `x`, which holds the value of `1`, and `y`, which holds the value of `2`, + is not equal. This inequality constraint is due to the line `assert(x != y)`. + +2. Noir creates and stores the proof of this statement in the _proofs_ directory in a file called your-project.proof. So if your project is named "private_voting" (defined in the project Nargo.toml), the proof will be saved at `./proofs/private_voting.proof`. Opening this file will display the proof in hex format. + +#### Arrays of Structs + +The following code shows how to pass an array of structs to a Noir program to generate a proof. + +```rust +// main.nr +struct Foo { + bar: Field, + baz: Field, +} + +fn main(foos: [Foo; 3]) -> pub Field { + foos[2].bar + foos[2].baz +} +``` + +Prover.toml: + +```toml +[[foos]] # foos[0] +bar = 0 +baz = 0 + +[[foos]] # foos[1] +bar = 0 +baz = 0 + +[[foos]] # foos[2] +bar = 1 +baz = 2 +``` + +#### Custom toml files + +You can specify a `toml` file with a different name to use for proving by using the `--prover-name` or `-p` flags. + +This command looks for proof inputs in the default **Prover.toml** and generates the proof and saves it at `./proofs/.proof`: + +```bash +nargo prove +``` + +This command looks for proof inputs in the custom **OtherProver.toml** and generates proof and saves it at `./proofs/.proof`: + +```bash +nargo prove -p OtherProver +``` + +## Verifying a Proof + +When the command `nargo verify` is executed, two processes happen: + +1. Noir checks in the _proofs_ directory for a proof file with the project name (eg. test_project.proof) + +2. If that file is found, the proof's validity is checked + +> **Note:** The validity of the proof is linked to the current Noir program; if the program is +> changed and the verifier verifies the proof, it will fail because the proof is not valid for the +> _modified_ Noir program. + +In production, the prover and the verifier are usually two separate entities. A prover would +retrieve the necessary inputs, execute the Noir program, generate a proof and pass it to the +verifier. The verifier would then retrieve the public inputs, usually from external sources, and +verify the validity of the proof against it. + +Take a private asset transfer as an example: + +A person using a browser as the prover would retrieve private inputs locally (e.g. the user's private key) and +public inputs (e.g. the user's encrypted balance on-chain), compute the transfer, generate a proof +and submit it to the verifier smart contract. + +The verifier contract would then draw the user's encrypted balance directly from the blockchain and +verify the proof submitted against it. If the verification passes, additional functions in the +verifier contract could trigger (e.g. approve the asset transfer). + +Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code. diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json new file mode 100644 index 00000000000..0c02fb5d4d7 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 0, + "label": "Install Nargo", + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md b/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md new file mode 100644 index 00000000000..4ef86aa5914 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md @@ -0,0 +1,48 @@ +--- +title: Nargo Installation +description: + nargo is a command line tool for interacting with Noir programs. This page is a quick guide on how to install Nargo through the most common and easy method, noirup +keywords: [ + Nargo + Noir + Rust + Cargo + Noirup + Installation + Terminal Commands + Version Check + Nightlies + Specific Versions + Branches + Noirup Repository +] +pagination_next: getting_started/hello_noir/index +--- + +`nargo` is the one-stop-shop for almost everything related with Noir. The name comes from our love for Rust and its package manager `cargo`. + +With `nargo`, you can start new projects, compile, execute, prove, verify, test, generate solidity contracts, and do pretty much all that is available in Noir. + +Similarly to `rustup`, we also maintain an easy installation method that covers most machines: `noirup`. + +## Installing Noirup + +Open a terminal on your machine, and write: + +```bash +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Close the terminal, open another one, and run + +```bash +noirup +``` + +Done. That's it. You should have the latest version working. You can check with `nargo --version`. + +You can also install nightlies, specific versions +or branches. Check out the [noirup repository](https://github.com/noir-lang/noirup) for more +information. + +Now we're ready to start working on [our first Noir program!](../hello_noir/index.md) diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md b/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md new file mode 100644 index 00000000000..a532f83750e --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md @@ -0,0 +1,190 @@ +--- +title: Alternative Install Methods +description: + There are different ways to install Nargo, the one-stop shop and command-line tool for developing Noir programs. This guide explains other methods that don't rely on noirup, such as compiling from source, installing from binaries, and using WSL for windows +keywords: [ + Installation + Nargo + Noirup + Binaries + Compiling from Source + WSL for Windows + macOS + Linux + Nix + Direnv + Shell & editor experience + Building and testing + Uninstalling Nargo + Noir vs code extension +] +sidebar_position: 1 +--- + + +## Installation + +The most common method of installing Nargo is through [Noirup](./index.md) + +However, there are other methods for installing Nargo: + +- [Binaries](#binaries) +- [Compiling from Source](#compile-from-source) +- [WSL for Windows](#wsl-for-windows) + +### Binaries + +See [GitHub Releases](https://github.com/noir-lang/noir/releases) for the latest and previous +platform specific binaries. + +#### Step 1 + +Paste and run the following in the terminal to extract and install the binary: + +> **macOS / Linux:** If you are prompted with `Permission denied` when running commands, prepend +> `sudo` and re-run it. + +##### macOS (Apple Silicon) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-aarch64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-aarch64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### macOS (Intel) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-apple-darwin.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-apple-darwin.tar.gz -C $HOME/.nargo/bin/ && \ +echo '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.zshrc && \ +source ~/.zshrc +``` + +##### Linux (Bash) + +```bash +mkdir -p $HOME/.nargo/bin && \ +curl -o $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -L https://github.com/noir-lang/noir/releases/download/v0.6.0/nargo-x86_64-unknown-linux-gnu.tar.gz && \ +tar -xvf $HOME/.nargo/bin/nargo-x86_64-unknown-linux-gnu.tar.gz -C $HOME/.nargo/bin/ && \ +echo -e '\nexport PATH=$PATH:$HOME/.nargo/bin' >> ~/.bashrc && \ +source ~/.bashrc +``` + +#### Step 2 + +Check if the installation was successful by running `nargo --version`. You should get a version number. + +> **macOS:** If you are prompted with an OS alert, right-click and open the _nargo_ executable from +> Finder. Close the new terminal popped up and `nargo` should now be accessible. + +### Option 3: Compile from Source + +Due to the large number of native dependencies, Noir projects uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. It helps mitigating issues commonly associated with dependency management, such as conflicts between required package versions for different projects (often referred to as "dependency hell"). + +Combined with direnv, which automatically sets or clears environment variables based on the directory, it further simplifies the development process by seamlessly integrating with the developer's shell, facilitating an efficient and reliable workflow for managing and deploying Noir projects with multiple dependencies. + +#### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: + +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system. +2. Create the file `~/.config/nix/nix.conf` with the contents: + +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` + +3. Install direnv into your Nix profile by running: + +```sh +nix profile install nixpkgs#direnv +``` + +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html). + 1. For bash or zshell, add `eval "$(direnv hook bash)"` or `eval "$(direnv hook zsh)"` to your ~/.bashrc or ~/.zshrc file, respectively. +5. Restart your shell. + +#### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: + +```sh +git clone git@github.com:noir-lang/noir +``` + +> Replacing `noir` with whichever repository you want to work on. + +2. Navigate to the directory: + +```sh +cd noir +``` + +> Replacing `noir` with whichever repository you cloned. + +3. You should see a **direnv error** because projects aren't allowed by default. Make sure you've reviewed and trust our `.envrc` file, then you need to run: + +```sh +direnv allow +``` + +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. + +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): + +```sh +code . +``` + +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +#### Building and testing + +Assuming you are using `direnv` to populate your environment, building and testing the project can be done +with the typical `cargo build`, `cargo test`, and `cargo clippy` commands. You'll notice that the `cargo` version matches the version we specify in `rust-toolchain.toml`, which is 1.71.1 at the time of this writing. + +If you want to build the entire project in an isolated sandbox, you can use Nix commands: + +1. `nix build .` (or `nix build . -L` for verbose output) to build the project in a Nix sandbox. +2. `nix flake check` (or `nix flake check -L` for verbose output) to run clippy and tests in a Nix sandbox. + +#### Without `direnv` + +If you have hesitations with using direnv, you can launch a subshell with `nix develop` and then launch your editor from within the subshell. However, if VSCode was already launched in the project directory, the environment won't be updated. + +Advanced: If you aren't using direnv nor launching your editor within the subshell, you can try to install Barretenberg and other global dependencies the package needs. This is an advanced workflow and likely won't receive support! + +### Option 4: WSL (for Windows) + +The default backend for Noir (Barretenberg) doesn't provide Windows binaries at this time. For that reason, Noir cannot be installed natively. However, it is available by using Windows Subsystem for Linux (WSL). + +Step 1: Follow the instructions [here](https://learn.microsoft.com/en-us/windows/wsl/install) to install and run WSL. + +step 2: Follow the [Noirup instructions](./index.md). + +## Uninstalling Nargo + +### Noirup + +If you installed Noir with `noirup`, you can uninstall Noir by removing the files in `~/.nargo`, `~/nargo` and `~/noir_cache`. + +```bash +rm -r ~/.nargo +rm -r ~/nargo +rm -r ~/noir_cache +``` + +### Nix + +If you installed Noir with Nix or from source, you can remove the binary located at `~/.nix-profile/bin/nargo`. + +```bash +rm ~/.nix-profile/bin/nargo +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json new file mode 100644 index 00000000000..55804c03a71 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 2, + "label": "Tooling", + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx new file mode 100644 index 00000000000..ac480f3c9f5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx @@ -0,0 +1,38 @@ +--- +title: Tooling +Description: This section provides information about the various tools and utilities available for Noir development. It covers the Noir playground, IDE tools, Codespaces, and community projects. +Keywords: [Noir, Development, Playground, IDE Tools, Language Service Provider, VS Code Extension, Codespaces, noir-starter, Community Projects, Awesome Noir Repository, Developer Tooling] +--- + +Noir is meant to be easy to develop with. For that reason, a number of utilities have been put together to ease the development process as much as feasible in the zero-knowledge world. + +## Playground + +The Noir playground is an easy way to test small ideas, share snippets, and integrate in other websites. You can access it at [play.noir-lang.org](https://play.noir-lang.org). + +## IDE tools + +When you install Nargo, you're also installing a Language Service Provider (LSP), which can be used by IDEs to provide syntax highlighting, codelens, warnings, and more. + +The easiest way to use these tools is by installing the [Noir VS Code extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). + +## Codespaces + +Some Noir repos have leveraged Codespaces in order to ease the development process. You can visit the [noir-starter](https://github.com/noir-lang/noir-starter) for an example. + + + +## GitHub Actions + +You can use `noirup` with GitHub Actions for CI/CD and automated testing. It is as simple as +installing `noirup` and running tests in your GitHub Action `yml` file. + +See the +[config file in the Noir repo](https://github.com/TomAFrench/noir-hashes/blob/master/.github/workflows/noir.yml) for an example usage. + +## Community projects + +As an open-source project, Noir has received many contributions over time. Some of them are related with developer tooling, and you can see some of them in [Awesome Noir repository](https://github.com/noir-lang/awesome-noir#dev-tools) diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md new file mode 100644 index 00000000000..81e0356ef8a --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md @@ -0,0 +1,43 @@ +--- +title: Language Server +description: Learn about the Noir Language Server, how to install the components, and configuration that may be required. +keywords: [Nargo, Language Server, LSP, VSCode, Visual Studio Code] +sidebar_position: 0 +--- + +This section helps you install and configure the Noir Language Server. + +The Language Server Protocol (LSP) has two components, the [Server](#language-server) and the [Client](#language-client). Below we describe each in the context of Noir. + +## Language Server + +The Server component is provided by the Nargo command line tool that you installed at the beginning of this guide. +As long as Nargo is installed and you've used it to run other commands in this guide, it should be good to go! + +If you'd like to verify that the `nargo lsp` command is available, you can run `nargo --help` and look for `lsp` in the list of commands. If you see it, you're using a version of Noir with LSP support. + +## Language Client + +The Client component is usually an editor plugin that launches the Server. It communicates LSP messages between the editor and the Server. For example, when you save a file, the Client will alert the Server, so it can try to compile the project and report any errors. + +Currently, Noir provides a Language Client for Visual Studio Code via the [vscode-noir](https://github.com/noir-lang/vscode-noir) extension. You can install it via the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir). + +> **Note:** Noir's Language Server Protocol support currently assumes users' VSCode workspace root to be the same as users' Noir project root (i.e. where Nargo.toml lies). +> +> If LSP features seem to be missing / malfunctioning, make sure you are opening your Noir project directly (instead of as a sub-folder) in your VSCode instance. + +When your language server is running correctly and the VSCode plugin is installed, you should see handy codelens buttons for compilation, measuring circuit size, execution, and tests: + +![Compile and Execute](@site/static/img/codelens_compile_execute.png) +![Run test](@site/static/img/codelens_run_test.png) + +You should also see your tests in the `testing` panel: + +![Testing panel](@site/static/img/codelens_testing_panel.png) + +### Configuration + +- **Noir: Enable LSP** - If checked, the extension will launch the Language Server via `nargo lsp` and communicate with it. +- **Noir: Nargo Flags** - Additional flags may be specified if you require them to be added when the extension calls `nargo lsp`. +- **Noir: Nargo Path** - An absolute path to a Nargo binary with the `lsp` command. This may be useful if Nargo is not within the `PATH` of your editor. +- **Noir > Trace: Server** - Setting this to `"messages"` or `"verbose"` will log LSP messages between the Client and Server. Useful for debugging. diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md new file mode 100644 index 00000000000..d3e0c522473 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md @@ -0,0 +1,62 @@ +--- +title: Testing in Noir +description: Learn how to use Nargo to test your Noir program in a quick and easy way +keywords: [Nargo, testing, Noir, compile, test] +sidebar_position: 1 +--- + +You can test your Noir programs using Noir circuits. + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. + +For example if you have a program like: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test] +fn test_add() { + assert(add(2,2) == 4); + assert(add(0,1) == 1); + assert(add(1,0) == 1); +} +``` + +Running `nargo test` will test that the `test_add` function can be executed while satisfying all +the constraints which allows you to test that add returns the expected values. Test functions can't +have any arguments currently. + +### Test fail + +You can write tests that are expected to fail by using the decorator `#[test(should_fail)]`. For example: + +```rust +fn add(x: u64, y: u64) -> u64 { + x + y +} +#[test(should_fail)] +fn test_add() { + assert(add(2,2) == 5); +} +``` + +You can be more specific and make it fail with a specific reason by using `should_fail_with = "`: + +```rust +fn main(african_swallow_avg_speed : Field) { + assert(african_swallow_avg_speed == 65, "What is the airspeed velocity of an unladen swallow"); +} + +#[test] +fn test_king_arthur() { + main(65); +} + +#[test(should_fail_with = "What is the airspeed velocity of an unladen swallow")] +fn test_bridgekeeper() { + main(32); +} + +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/how_to/_category_.json new file mode 100644 index 00000000000..23b560f610b --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/how_to/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md b/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md new file mode 100644 index 00000000000..0d84d992320 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md @@ -0,0 +1,280 @@ +--- +title: How to use Oracles +description: Learn how to use oracles in your Noir program with examples in both Nargo and NoirJS. This guide also covers writing a JSON RPC server and providing custom foreign call handlers for NoirJS. +keywords: + - Noir Programming + - Oracles + - Nargo + - NoirJS + - JSON RPC Server + - Foreign Call Handlers +sidebar_position: 1 +--- + +This guide shows you how to use oracles in your Noir program. For the sake of clarity, it assumes that: + +- You have read the [explainer on Oracles](../explainers/explainer-oracle.md) and are comfortable with the concept. +- You have a Noir program to add oracles to. You can create one using the [vite-hardhat starter](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) as a boilerplate. +- You understand the concept of a JSON-RPC server. Visit the [JSON-RPC website](https://www.jsonrpc.org/) if you need a refresher. +- You are comfortable with server-side JavaScript (e.g. Node.js, managing packages, etc.). + +For reference, you can find the snippets used in this tutorial on the [Aztec DevRel Repository](https://github.com/AztecProtocol/dev-rel/tree/main/code-snippets/how-to-oracles). + +## Rundown + +This guide has 3 major steps: + +1. How to modify our Noir program to make use of oracle calls as unconstrained functions +2. How to write a JSON RPC Server to resolve these oracle calls with Nargo +3. How to use them in Nargo and how to provide a custom resolver in NoirJS + +## Step 1 - Modify your Noir program + +An oracle is defined in a Noir program by defining two methods: + +- An unconstrained method - This tells the compiler that it is executing an [unconstrained functions](../noir/concepts//unconstrained.md). +- A decorated oracle method - This tells the compiler that this method is an RPC call. + +An example of an oracle that returns a `Field` would be: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt(number: Field) -> Field { } + +unconstrained fn get_sqrt(number: Field) -> Field { + sqrt(number) +} +``` + +In this example, we're wrapping our oracle function in a unconstrained method, and decorating it with `oracle(getSqrt)`. We can then call the unconstrained function as we would call any other function: + +```rust +fn main(input: Field) { + let sqrt = get_sqrt(input); +} +``` + +In the next section, we will make this `getSqrt` (defined on the `sqrt` decorator) be a method of the RPC server Noir will use. + +:::danger + +As explained in the [Oracle Explainer](../explainers/explainer-oracle.md), this `main` function is unsafe unless you constrain its return value. For example: + +```rust +fn main(input: Field) { + let sqrt = get_sqrt(input); + assert(sqrt.pow_32(2) as u64 == input as u64); // <---- constrain the return of an oracle! +} +``` + +::: + +:::info + +Currently, oracles only work with single params or array params. For example: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt([Field; 2]) -> [Field; 2] { } +``` + +::: + +## Step 2 - Write an RPC server + +Brillig will call *one* RPC server. Most likely you will have to write your own, and you can do it in whatever language you prefer. In this guide, we will do it in Javascript. + +Let's use the above example of an oracle that consumes an array with two `Field` and returns their square roots: + +```rust +#[oracle(getSqrt)] +unconstrained fn sqrt(input: [Field; 2]) -> [Field; 2] { } + +unconstrained fn get_sqrt(input: [Field; 2]) -> [Field; 2] { + sqrt(input) +} + +fn main(input: [Field; 2]) { + let sqrt = get_sqrt(input); + assert(sqrt[0].pow_32(2) as u64 == input[0] as u64); + assert(sqrt[1].pow_32(2) as u64 == input[1] as u64); +} +``` + +:::info + +Why square root? + +In general, computing square roots is computationally more expensive than multiplications, which takes a toll when speaking about ZK applications. In this case, instead of calculating the square root in Noir, we are using our oracle to offload that computation to be made in plain. In our circuit we can simply multiply the two values. + +::: + +Now, we should write the correspondent RPC server, starting with the [default JSON-RPC 2.0 boilerplate](https://www.npmjs.com/package/json-rpc-2.0#example): + +```js +import { JSONRPCServer } from "json-rpc-2.0"; +import express from "express"; +import bodyParser from "body-parser"; + +const app = express(); +app.use(bodyParser.json()); + +const server = new JSONRPCServer(); +app.post("/", (req, res) => { + const jsonRPCRequest = req.body; + server.receive(jsonRPCRequest).then((jsonRPCResponse) => { + if (jsonRPCResponse) { + res.json(jsonRPCResponse); + } else { + res.sendStatus(204); + } + }); +}); + +app.listen(5555); +``` + +Now, we will add our `getSqrt` method, as expected by the `#[oracle(getSqrt)]` decorator in our Noir code. It maps through the params array and returns their square roots: + +```js +server.addMethod("getSqrt", async (params) => { + const values = params[0].Array.map(({ inner }) => { + return { inner: `${Math.sqrt(parseInt(inner, 16))}` }; + }); + return { values: [{ Array: values }] }; +}); +``` + +:::tip + +Brillig expects an object with an array of values. Each value is an object declaring to be `Single` or `Array` and returning a `inner` property *as a string*. For example: + +```json +{ "values": [{ "Array": [{ "inner": "1" }, { "inner": "2"}]}]} +{ "values": [{ "Single": { "inner": "1" }}]} +{ "values": [{ "Single": { "inner": "1" }}, { "Array": [{ "inner": "1", { "inner": "2" }}]}]} +``` + +If you're using Typescript, the following types may be helpful in understanding the expected return value and making sure they're easy to follow: + +```js +interface Value { + inner: string, +} + +interface SingleForeignCallParam { + Single: Value, +} + +interface ArrayForeignCallParam { + Array: Value[], +} + +type ForeignCallParam = SingleForeignCallParam | ArrayForeignCallParam; + +interface ForeignCallResult { + values: ForeignCallParam[], +} +``` + +::: + +## Step 3 - Usage with Nargo + +Using the [`nargo` CLI tool](../getting_started/installation/index.md), you can use oracles in the `nargo test`, `nargo execute` and `nargo prove` commands by passing a value to `--oracle-resolver`. For example: + +```bash +nargo test --oracle-resolver http://localhost:5555 +``` + +This tells `nargo` to use your RPC Server URL whenever it finds an oracle decorator. + +## Step 4 - Usage with NoirJS + +In a JS environment, an RPC server is not strictly necessary, as you may want to resolve your oracles without needing any JSON call at all. NoirJS simply expects that you pass a callback function when you generate proofs, and that callback function can be anything. + +For example, if your Noir program expects the host machine to provide CPU pseudo-randomness, you could simply pass it as the `foreignCallHandler`. You don't strictly need to create an RPC server to serve pseudo-randomness, as you may as well get it directly in your app: + +```js +const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc + +await noir.generateFinalProof(inputs, foreignCallHandler) +``` + +As one can see, in NoirJS, the [`foreignCallHandler`](../reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md) function simply means "a callback function that returns a value of type [`ForeignCallOutput`](../reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md). It doesn't have to be an RPC call like in the case for Nargo. + +:::tip + +Does this mean you don't have to write an RPC server like in [Step #2](#step-2---write-an-rpc-server)? + +You don't technically have to, but then how would you run `nargo test` or `nargo prove`? To use both `Nargo` and `NoirJS` in your development flow, you will have to write a JSON RPC server. + +::: + +In this case, let's make `foreignCallHandler` call the JSON RPC Server we created in [Step #2](#step-2---write-an-rpc-server), by making it a JSON RPC Client. + +For example, using the same `getSqrt` program in [Step #1](#step-1---modify-your-noir-program) (comments in the code): + +```js +import { JSONRPCClient } from "json-rpc-2.0"; + +// declaring the JSONRPCClient +const client = new JSONRPCClient((jsonRPCRequest) => { +// hitting the same JSON RPC Server we coded above + return fetch("http://localhost:5555", { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(jsonRPCRequest), + }).then((response) => { + if (response.status === 200) { + return response + .json() + .then((jsonRPCResponse) => client.receive(jsonRPCResponse)); + } else if (jsonRPCRequest.id !== undefined) { + return Promise.reject(new Error(response.statusText)); + } + }); +}); + +// declaring a function that takes the name of the foreign call (getSqrt) and the inputs +const foreignCallHandler = async (name, input) => { + // notice that the "inputs" parameter contains *all* the inputs + // in this case we to make the RPC request with the first parameter "numbers", which would be input[0] + const oracleReturn = await client.request(name, [ + { Array: input[0].map((i) => ({ inner: i.toString("hex") })) }, + ]); + return [oracleReturn.values[0].Array.map((x) => x.inner)]; +}; + +// the rest of your NoirJS code +const input = { input: [4, 16] }; +const { witness } = await noir.execute(numbers, foreignCallHandler); +``` + +:::tip + +If you're in a NoirJS environment running your RPC server together with a frontend app, you'll probably hit a familiar problem in full-stack development: requests being blocked by [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) policy. For development only, you can simply install and use the [`cors` npm package](https://www.npmjs.com/package/cors) to get around the problem: + +```bash +yarn add cors +``` + +and use it as a middleware: + +```js +import cors from "cors"; + +const app = express(); +app.use(cors()) +``` + +::: + +## Conclusion + +Hopefully by the end of this guide, you should be able to: + +- Write your own logic around Oracles and how to write a JSON RPC server to make them work with your Nargo commands. +- Provide custom foreign call handlers for NoirJS. diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md b/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md new file mode 100644 index 00000000000..39db23f1f3a --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md @@ -0,0 +1,184 @@ +--- +title: How to use recursion on NoirJS +description: Learn how to implement recursion with NoirJS, a powerful tool for creating smart contracts on the EVM blockchain. This guide assumes familiarity with NoirJS, solidity verifiers, and the Barretenberg proving backend. Discover how to generate both final and intermediate proofs using `noir_js` and `backend_barretenberg`. +keywords: + [ + "NoirJS", + "EVM blockchain", + "smart contracts", + "recursion", + "solidity verifiers", + "Barretenberg backend", + "noir_js", + "backend_barretenberg", + "intermediate proofs", + "final proofs", + "nargo compile", + "json import", + "recursive circuit", + "recursive app" + ] +sidebar_position: 1 +--- + +This guide shows you how to use recursive proofs in your NoirJS app. For the sake of clarity, it is assumed that: + +- You already have a NoirJS app. If you don't, please visit the [NoirJS tutorial](../tutorials/noirjs_app.md) and the [reference](../reference/NoirJS/noir_js/index.md). +- You are familiar with what are recursive proofs and you have read the [recursion explainer](../explainers/explainer-recursion.md) +- You already built a recursive circuit following [the reference](../noir/standard_library/recursion.md), and understand how it works. + +It is also assumed that you're not using `noir_wasm` for compilation, and instead you've used [`nargo compile`](../reference/nargo_commands.md) to generate the `json` you're now importing into your project. However, the guide should work just the same if you're using `noir_wasm`. + +:::info + +As you've read in the [explainer](../explainers/explainer-recursion.md), a recursive proof is an intermediate proof. This means that it doesn't necessarily generate the final step that makes it verifiable in a smart contract. However, it is easy to verify within another circuit. + +While "standard" usage of NoirJS packages abstracts final proofs, it currently lacks the necessary interface to abstract away intermediate proofs. This means that these proofs need to be created by using the backend directly. + +In short: + +- `noir_js` generates *only* final proofs +- `backend_barretenberg` generates both types of proofs + +::: + +In a standard recursive app, you're also dealing with at least two circuits. For the purpose of this guide, we will assume these two: + +- `main`: a circuit of type `assert(x != y)` +- `recursive`: a circuit that verifies `main` + +For a full example on how recursive proofs work, please refer to the [noir-examples](https://github.com/noir-lang/noir-examples) repository. We will *not* be using it as a reference for this guide. + +## Step 1: Setup + +In a common NoirJS app, you need to instantiate a backend with something like `const backend = new Backend(circuit)`. Then you feed it to the `noir_js` interface. + +For recursion, this doesn't happen, and the only need for `noir_js` is only to `execute` a circuit and get its witness and return value. Everything else is not interfaced, so it needs to happen on the `backend` object. + +It is also recommended that you instantiate the backend with as many threads as possible, to allow for maximum concurrency: + +```js +const backend = new Backend(circuit, { threads: 8 }) +``` + +:::tip +You can use the [`os.cpus()`](https://nodejs.org/api/os.html#oscpus) object in `nodejs` or [`navigator.hardwareConcurrency`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency) on the browser to make the most out of those glorious cpu cores +::: + +## Step 2: Generating the witness and the proof for `main` + +After instantiating the backend, you should also instantiate `noir_js`. We will use it to execute the circuit and get the witness. + +```js +const noir = new Noir(circuit, backend) +const { witness } = noir.execute(input) +``` + +With this witness, you are now able to generate the intermediate proof for the main circuit: + +```js +const { proof, publicInputs } = await backend.generateIntermediateProof(witness) +``` + +:::warning + +Always keep in mind what is actually happening on your development process, otherwise you'll quickly become confused about what circuit we are actually running and why! + +In this case, you can imagine that Alice (running the `main` circuit) is proving something to Bob (running the `recursive` circuit), and Bob is verifying her proof within his proof. + +With this in mind, it becomes clear that our intermediate proof is the one *meant to be verified within another circuit*, so it must be Alice's. Actually, the only final proof in this theoretical scenario would be the last one, sent on-chain. + +::: + +## Step 3 - Verification and proof artifacts + +Optionally, you are able to verify the intermediate proof: + +```js +const verified = await backend.verifyIntermediateProof({ proof, publicInputs }) +``` + +This can be useful to make sure our intermediate proof was correctly generated. But the real goal is to do it within another circuit. For that, we need to generate the intermediate artifacts: + +```js +const { proofAsFields, vkAsFields, vkHash } = await backend.generateIntermediateProofArtifacts( { publicInputs, proof }, publicInputsCount) +``` + +This call takes the public inputs and the proof, but also the public inputs count. While this is easily retrievable by simply counting the `publicInputs` length, the backend interface doesn't currently abstract it away. + +:::info + +The `proofAsFields` has a constant size `[Field; 93]`. However, currently the backend doesn't remove the public inputs from the proof when converting it. + +This means that if your `main` circuit has two public inputs, then you should also modify the recursive circuit to accept a proof with the public inputs appended. This means that in our example, since `y` is a public input, our `proofAsFields` is of type `[Field; 94]`. + +Verification keys in Barretenberg are always of size 114. + +::: + +:::warning + +One common mistake is to forget *who* makes this call. + +In a situation where Alice is generating the `main` proof, if she generates the proof artifacts and sends them to Bob, which gladly takes them as true, this would mean Alice could prove anything! + +Instead, Bob needs to make sure *he* extracts the proof artifacts, using his own instance of the `main` circuit backend. This way, Alice has to provide a valid proof for the correct `main` circuit. + +::: + +## Step 4 - Recursive proof generation + +With the artifacts, generating a recursive proof is no different from a normal proof. You simply use the `backend` (with the recursive circuit) to generate it: + +```js +const recursiveInputs = { + verification_key: vkAsFields, // array of length 114 + proof: proofAsFields, // array of length 93 + size of public inputs + publicInputs: [mainInput.y], // using the example above, where `y` is the only public input + key_hash: vkHash, + input_aggregation_object: Array(16).fill(0) // this circuit is verifying a non-recursive proof, so there's no input aggregation object: just use zero +} + +const { witness, returnValue } = noir.execute(recursiveInputs) // we're executing the recursive circuit now! +const { proof, publicInputs } = backend.generateFinalProof(witness) +const verified = backend.verifyFinalProof({ proof, publicInputs }) +``` + +You can obviously chain this proof into another proof. In fact, if you're using recursive proofs, you're probably interested of using them this way! In that case, you should keep in mind the `returnValue`, as it will contain the `input_aggregation_object` for the next proof. + +:::tip + +Managing circuits and "who does what" can be confusing. To make sure your naming is consistent, you can keep them in an object. For example: + +```js +const circuits = { +main: mainJSON, +recursive: recursiveJSON +} +const backends = { +main: new BarretenbergBackend(circuits.main), +recursive: new BarretenbergBackend(circuits.recursive) +} +const noir_programs = { +main: new Noir(circuits.main, backends.main), +recursive: new Noir(circuits.recursive, backends.recursive) +} +``` + +This allows you to neatly call exactly the method you want without conflicting names: + +```js +// Alice runs this 👇 +const { witness: mainWitness } = await noir_programs.main.execute(input) +const proof = await backends.main.generateIntermediateProof(mainWitness) + +// Bob runs this 👇 +const verified = await backends.main.verifyIntermediateProof(proof) +const { proofAsFields, vkAsFields, vkHash } = await backends.main.generateIntermediateProofArtifacts( + proof, + numPublicInputs, +); +const recursiveProof = await noir_programs.recursive.generateFinalProof(recursiveInputs) +``` + +::: diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md b/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md new file mode 100644 index 00000000000..e3c7c1065da --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md @@ -0,0 +1,231 @@ +--- +title: Generate a Solidity Verifier +description: + Learn how to run the verifier as a smart contract on the blockchain. Compile a Solidity verifier + contract for your Noir program and deploy it on any EVM blockchain acting as a verifier smart + contract. Read more to find out +keywords: + [ + solidity verifier, + smart contract, + blockchain, + compiler, + plonk_vk.sol, + EVM blockchain, + verifying Noir programs, + proving backend, + Barretenberg, + ] +sidebar_position: 0 +pagination_next: tutorials/noirjs_app +--- + +Noir has the ability to generate a verifier contract in Solidity, which can be deployed in many EVM-compatible blockchains such as Ethereum. + +This allows for a powerful feature set, as one can make use of the conciseness and the privacy provided by Noir in an immutable ledger. Applications can range from simple P2P guessing games, to complex private DeFi interactions. + +This guide shows you how to generate a Solidity Verifier and deploy it on the [Remix IDE](https://remix.ethereum.org/). It is assumed that: + +- You are comfortable with the Solidity programming language and understand how contracts are deployed on the Ethereum network +- You have Noir installed and you have a Noir program. If you don't, [get started](../getting_started/installation/index.md) with Nargo and the example Hello Noir circuit +- You are comfortable navigating RemixIDE. If you aren't or you need a refresher, you can find some video tutorials [here](https://www.youtube.com/channel/UCjTUPyFEr2xDGN6Cg8nKDaA) that could help you. + +## Rundown + +Generating a Solidity Verifier contract is actually a one-command process. However, compiling it and deploying it can have some caveats. Here's the rundown of this guide: + +1. How to generate a solidity smart contract +2. How to compile the smart contract in the RemixIDE +3. How to deploy it to a testnet + +## Step 1 - Generate a contract + +This is by far the most straight-forward step. Just run: + +```sh +nargo codegen-verifier +``` + +A new `contract` folder would then be generated in your project directory, containing the Solidity +file `plonk_vk.sol`. It can be deployed to any EVM blockchain acting as a verifier smart contract. + +:::info + +It is possible to generate verifier contracts of Noir programs for other smart contract platforms as long as the proving backend supplies an implementation. + +Barretenberg, the default proving backend for Nargo, supports generation of verifier contracts, for the time being these are only in Solidity. +::: + +## Step 2 - Compiling + +We will mostly skip the details of RemixIDE, as the UI can change from version to version. For now, we can just open +Remix and create a blank workspace. + +![Create Workspace](@site/static/img/how-tos/solidity_verifier_1.png) + +We will create a new file to contain the contract Nargo generated, and copy-paste its content. + +:::warning + +You'll likely see a warning advising you to not trust pasted code. While it is an important warning, it is irrelevant in the context of this guide and can be ignored. We will not be deploying anywhere near a mainnet. + +::: + +To compile our the verifier, we can navigate to the compilation tab: + +![Compilation Tab](@site/static/img/how-tos/solidity_verifier_2.png) + +Remix should automatically match a suitable compiler version. However, hitting the "Compile" button will most likely generate a "Stack too deep" error: + +![Stack too deep](@site/static/img/how-tos/solidity_verifier_3.png) + +This is due to the verify function needing to put many variables on the stack, but enabling the optimizer resolves the issue. To do this, let's open the "Advanced Configurations" tab and enable optimization. The default 200 runs will suffice. + +:::info + +This time we will see a warning about an unused function parameter. This is expected, as the `verify` function doesn't use the `_proof` parameter inside a solidity block, it is loaded from calldata and used in assembly. + +::: + +![Compilation success](@site/static/img/how-tos/solidity_verifier_4.png) + +## Step 3 - Deploying + +At this point we should have a compiled contract read to deploy. If we navigate to the deploy section in Remix, we will see many different environments we can deploy to. The steps to deploy on each environment would be out-of-scope for this guide, so we will just use the default Remix VM. + +Looking closely, we will notice that our "Solidity Verifier" is actually three contracts working together: + +- An `UltraVerificationKey` library which simply stores the verification key for our circuit. +- An abstract contract `BaseUltraVerifier` containing most of the verifying logic. +- A main `UltraVerifier` contract that inherits from the Base and uses the Key contract. + +Remix will take care of the dependencies for us so we can simply deploy the UltraVerifier contract by selecting it and hitting "deploy": + +![Deploying UltraVerifier](@site/static/img/how-tos/solidity_verifier_5.png) + +A contract will show up in the "Deployed Contracts" section, where we can retrieve the Verification Key Hash. This is particularly useful for double-checking the deployer contract is the correct one. + +:::note + +Why "UltraVerifier"? + +To be precise, the Noir compiler (`nargo`) doesn't generate the verifier contract directly. It compiles the Noir code into an intermediate language (ACIR), which is then executed by the backend. So it is the backend that returns the verifier smart contract, not Noir. + +In this case, the Barretenberg Backend uses the UltraPlonk proving system, hence the "UltraVerifier" name. + +::: + +## Step 4 - Verifying + +To verify a proof using the Solidity verifier contract, we call the `verify` function in this extended contract: + +```solidity +function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool) +``` + +When using the default example in the [Hello Noir](../getting_started/hello_noir/index.md) guide, the easiest way to confirm that the verifier contract is doing its job is by calling the `verify` function via remix with the required parameters. For `_proof`, run `nargo prove` and use the string in `proof/.proof` (adding the hex `0x` prefix). We can also copy the public input from `Verifier.toml`, as it will be properly formatted as 32-byte strings: + +``` +0x...... , [0x0000.....02] +``` + +A programmatic example of how the `verify` function is called can be seen in the example zk voting application [here](https://github.com/noir-lang/noir-examples/blob/33e598c257e2402ea3a6b68dd4c5ad492bce1b0a/foundry-voting/src/zkVote.sol#L35): + +```solidity +function castVote(bytes calldata proof, uint proposalId, uint vote, bytes32 nullifierHash) public returns (bool) { + // ... + bytes32[] memory publicInputs = new bytes32[](4); + publicInputs[0] = merkleRoot; + publicInputs[1] = bytes32(proposalId); + publicInputs[2] = bytes32(vote); + publicInputs[3] = nullifierHash; + require(verifier.verify(proof, publicInputs), "Invalid proof"); +``` + +:::info[Return Values] + +A circuit doesn't have the concept of a return value. Return values are just syntactic sugar in +Noir. + +Under the hood, the return value is passed as an input to the circuit and is checked at the end of +the circuit program. + +For example, if you have Noir program like this: + +```rust +fn main( + // Public inputs + pubkey_x: pub Field, + pubkey_y: pub Field, + // Private inputs + priv_key: Field, +) -> pub Field +``` + +the `verify` function will expect the public inputs array (second function parameter) to be of length 3, the two inputs and the return value. Like before, these values are populated in Verifier.toml after running `nargo prove`. + +Passing only two inputs will result in an error such as `PUBLIC_INPUT_COUNT_INVALID(3, 2)`. + +In this case, the inputs parameter to `verify` would be an array ordered as `[pubkey_x, pubkey_y, return]`. + +::: + +:::tip[Structs] + +You can pass structs to the verifier contract. They will be flattened so that the array of inputs is 1-dimensional array. + +For example, consider the following program: + +```rust +struct Type1 { + val1: Field, + val2: Field, +} + +struct Nested { + t1: Type1, + is_true: bool, +} + +fn main(x: pub Field, nested: pub Nested, y: pub Field) { + //... +} +``` + +The order of these inputs would be flattened to: `[x, nested.t1.val1, nested.t1.val2, nested.is_true, y]` + +::: + +The other function you can call is our entrypoint `verify` function, as defined above. + +:::tip + +It's worth noticing that the `verify` function is actually a `view` function. A `view` function does not alter the blockchain state, so it doesn't need to be distributed (i.e. it will run only on the executing node), and therefore doesn't cost any gas. + +This can be particularly useful in some situations. If Alice generated a proof and wants Bob to verify its correctness, Bob doesn't need to run Nargo, NoirJS, or any Noir specific infrastructure. He can simply make a call to the blockchain with the proof and verify it is correct without paying any gas. + +It would be incorrect to say that a Noir proof verification costs any gas at all. However, most of the time the result of `verify` is used to modify state (for example, to update a balance, a game state, etc). In that case the whole network needs to execute it, which does incur gas costs (calldata and execution, but not storage). + +::: + +## A Note on EVM chains + +ZK-SNARK verification depends on some precompiled cryptographic primitives such as Elliptic Curve Pairings (if you like complex math, you can read about EC Pairings [here](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627)). Not all EVM chains support EC Pairings, notably some of the ZK-EVMs. This means that you won't be able to use the verifier contract in all of them. + +For example, chains like `zkSync ERA` and `Polygon zkEVM` do not currently support these precompiles, so proof verification via Solidity verifier contracts won't work. Here's a quick list of EVM chains that have been tested and are known to work: + +- Optimism +- Arbitrum +- Polygon PoS +- Scroll +- Celo + +If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. + +## What's next + +Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks, such as [hardhat](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) and [foundry](https://github.com/noir-lang/noir-starter/tree/main/with-foundry). + +You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. + +You should also be ready to write and deploy your first NoirJS app and start generating proofs on websites, phones, and NodeJS environments! Head on to the [NoirJS tutorial](../tutorials/noirjs_app.md) to learn how to do that. diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx b/noir/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx new file mode 100644 index 00000000000..34074659ac1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx @@ -0,0 +1,48 @@ +--- +title: Prove Merkle Tree Membership +description: + Learn how to use merkle membership proof in Noir to prove that a given leaf is a member of a + merkle tree with a specified root, at a given index. +keywords: + [merkle proof, merkle membership proof, Noir, rust, hash function, Pedersen, sha256, merkle tree] +--- + +Let's walk through an example of a merkle membership proof in Noir that proves that a given leaf is +in a merkle tree. + +```rust +use dep::std; + +fn main(message : [Field; 62], index : Field, hashpath : [Field; 40], root : Field) { + let leaf = std::hash::hash_to_field(message); + let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); + assert(merkle_root == root); +} + +``` + +The message is hashed using `hash_to_field`. The specific hash function that is being used is chosen +by the backend. The only requirement is that this hash function can heuristically be used as a +random oracle. If only collision resistance is needed, then one can call `std::hash::pedersen_hash` +instead. + +```rust +let leaf = std::hash::hash_to_field(message); +``` + +The leaf is then passed to a compute_merkle_root function with the root, index and hashpath. The returned root can then be asserted to be the same as the provided root. + +```rust +let merkle_root = std::merkle::compute_merkle_root(leaf, index, hashpath); +assert (merkle_root == root); +``` + +> **Note:** It is possible to re-implement the merkle tree implementation without standard library. +> However, for most usecases, it is enough. In general, the standard library will always opt to be +> as conservative as possible, while striking a balance with efficiency. + +An example, the merkle membership proof, only requires a hash function that has collision +resistance, hence a hash function like Pedersen is allowed, which in most cases is more efficient +than the even more conservative sha256. + +[View an example on the starter repo](https://github.com/noir-lang/noir-examples/blob/3ea09545cabfa464124ec2f3ea8e60c608abe6df/stealthdrop/circuits/src/main.nr#L20) diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx b/noir/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx new file mode 100644 index 00000000000..727ec6ca667 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx @@ -0,0 +1,110 @@ +--- +title: Developer Containers and Codespaces +description: "Learn how to set up a devcontainer in your GitHub repository for a seamless coding experience with Codespaces. Follow our easy 8-step guide to create your own Noir environment without installing Nargo locally." +keywords: ["Devcontainer", "Codespaces", "GitHub", "Noir Environment", "Docker Image", "Development Environment", "Remote Coding", "GitHub Codespaces", "Noir Programming", "Nargo", "VSCode Extensions", "Noirup"] +sidebar_position: 1 +--- + +Adding a developer container configuration file to your Noir project is one of the easiest way to unlock coding in browser. + +## What's a devcontainer after all? + +A [Developer Container](https://containers.dev/) (devcontainer for short) is a Docker image that comes preloaded with tools, extensions, and other tools you need to quickly get started or continue a project, without having to install Nargo locally. Think of it as a development environment in a box. + +There are many advantages to this: + +- It's platform and architecture agnostic +- You don't need to have an IDE installed, or Nargo, or use a terminal at all +- It's safer for using on a public machine or public network + +One of the best ways of using devcontainers is... not using your machine at all, for maximum control, performance, and ease of use. +Enter Codespaces. + +## Codespaces + +If a devcontainer is just a Docker image, then what stops you from provisioning a `p3dn.24xlarge` AWS EC2 instance with 92 vCPUs and 768 GiB RAM and using it to prove your 10-gate SNARK proof? + +Nothing! Except perhaps the 30-40$ per hour it will cost you. + +The problem is that provisioning takes time, and I bet you don't want to see the AWS console every time you want to code something real quick. + +Fortunately, there's an easy and free way to get a decent remote machine ready and loaded in less than 2 minutes: Codespaces. [Codespaces is a Github feature](https://github.com/features/codespaces) that allows you to code in a remote machine by using devcontainers, and it's pretty cool: + +- You can start coding Noir in less than a minute +- It uses the resources of a remote machine, so you can code on your grandma's phone if needed be +- It makes it easy to share work with your frens +- It's fully reusable, you can stop and restart whenever you need to + +:::info + +Don't take out your wallet just yet. Free GitHub accounts get about [15-60 hours of coding](https://github.com/features/codespaces) for free per month, depending on the size of your provisioned machine. + +::: + +## Tell me it's _actually_ easy + +It is! + +Github comes with a default codespace and you can use it to code your own devcontainer. That's exactly what we will be doing in this guide. + + + +8 simple steps: + +#### 1. Create a new repository on GitHub. + +#### 2. Click "Start coding with Codespaces". This will use the default image. + +#### 3. Create a folder called `.devcontainer` in the root of your repository. + +#### 4. Create a Dockerfile in that folder, and paste the following code: + +```docker +FROM --platform=linux/amd64 node:lts-bookworm-slim +SHELL ["/bin/bash", "-c"] +RUN apt update && apt install -y curl bash git tar gzip libc++-dev +RUN curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +ENV PATH="/root/.nargo/bin:$PATH" +RUN noirup +ENTRYPOINT ["nargo"] +``` +#### 5. Create a file called `devcontainer.json` in the same folder, and paste the following code: + +```json +{ + "name": "Noir on Codespaces", + "build": { + "context": ".", + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "extensions": ["noir-lang.vscode-noir"] + } + } +} +``` +#### 6. Commit and push your changes + +This will pull the new image and build it, so it could take a minute or so + +#### 8. Done! +Just wait for the build to finish, and there's your easy Noir environment. + + +Refer to [noir-starter](https://github.com/noir-lang/noir-starter/) as an example of how devcontainers can be used together with codespaces. + + + +## How do I use it? + +Using the codespace is obviously much easier than setting it up. +Just navigate to your repository and click "Code" -> "Open with Codespaces". It should take a few seconds to load, and you're ready to go. + +:::info + +If you really like the experience, you can add a badge to your readme, links to existing codespaces, and more. +Check out the [official docs](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/setting-up-your-repository/facilitating-quick-creation-and-resumption-of-codespaces) for more info. diff --git a/noir/docs/versioned_docs/version-v0.23.0/index.mdx b/noir/docs/versioned_docs/version-v0.23.0/index.mdx new file mode 100644 index 00000000000..75086ddcdde --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/index.mdx @@ -0,0 +1,67 @@ +--- +title: Noir Lang +hide_title: true +description: + Learn about the public alpha release of Noir, a domain specific language heavily influenced by Rust that compiles to + an intermediate language which can be compiled to an arithmetic circuit or a rank-1 constraint system. +keywords: + [Noir, + Domain Specific Language, + Rust, + Intermediate Language, + Arithmetic Circuit, + Rank-1 Constraint System, + Ethereum Developers, + Protocol Developers, + Blockchain Developers, + Proving System, + Smart Contract Language] +sidebar_position: 0 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Noir Logo + +Noir is a Domain-Specific Language for SNARK proving systems developed by [Aztec Labs](https://aztec.network/). It allows you to generate complex Zero-Knowledge Programs (ZKP) by using simple and flexible syntax, requiring no previous knowledge on the underlying mathematics or cryptography. + +ZK programs are programs that can generate short proofs of a certain statement without revealing some details about it. You can read more about ZKPs [here](https://dev.to/spalladino/a-beginners-intro-to-coding-zero-knowledge-proofs-c56). + +## What's new about Noir? + +Noir works differently from most ZK languages by taking a two-pronged path. First, it compiles the program to an adaptable intermediate language known as ACIR. From there, depending on a given project's needs, ACIR can be further compiled into an arithmetic circuit for integration with the proving backend. + +:::info + +Noir is backend agnostic, which means it makes no assumptions on which proving backend powers the ZK proof. Being the language that powers [Aztec Contracts](https://docs.aztec.network/developers/contracts/main), it defaults to Aztec's Barretenberg proving backend. + +However, the ACIR output can be transformed to be compatible with other PLONK-based backends, or into a [rank-1 constraint system](https://www.rareskills.io/post/rank-1-constraint-system) suitable for backends such as Arkwork's Marlin. + +::: + +## Who is Noir for? + +Noir can be used both in complex cloud-based backends and in user's smartphones, requiring no knowledge on the underlying math or cryptography. From authorization systems that keep a password in the user's device, to complex on-chain verification of recursive proofs, Noir is designed to abstract away complexity without any significant overhead. Here are some examples of situations where Noir can be used: + + + + Noir Logo + + Aztec Contracts leverage Noir to allow for the storage and execution of private information. Writing an Aztec Contract is as easy as writing Noir, and Aztec developers can easily interact with the network storage and execution through the [Aztec.nr](https://docs.aztec.network/developers/contracts/main) library. + + + Soliditry Verifier Example + Noir can auto-generate Solidity verifier contracts that verify Noir proofs. This allows for non-interactive verification of proofs containing private information in an immutable system. This feature powers a multitude of use-case scenarios, from P2P chess tournaments, to [Aztec Layer-2 Blockchain](https://docs.aztec.network/) + + + Aztec Labs developed NoirJS, an easy interface to generate and verify Noir proofs in a Javascript environment. This allows for Noir to be used in webpages, mobile apps, games, and any other environment supporting JS execution in a standalone manner. + + + + +## Libraries + +Noir is meant to be easy to extend by simply importing Noir libraries just like in Rust. +The [awesome-noir repo](https://github.com/noir-lang/awesome-noir#libraries) is a collection of libraries developed by the Noir community. +Writing a new library is easy and makes code be composable and easy to reuse. See the section on [dependencies](noir/modules_packages_crates/dependencies.md) for more information. diff --git a/noir/docs/versioned_docs/version-v0.23.0/migration_notes.md b/noir/docs/versioned_docs/version-v0.23.0/migration_notes.md new file mode 100644 index 00000000000..9f27230a1a0 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/migration_notes.md @@ -0,0 +1,91 @@ +--- +title: Migration notes +description: Read about migration notes from previous versions, which could solve problems while updating +keywords: [Noir, notes, migration, updating, upgrading] +--- + +Noir is in full-speed development. Things break fast, wild, and often. This page attempts to leave some notes on errors you might encounter when upgrading and how to resolve them until proper patches are built. + +## ≥0.19 + +### Enforcing `compiler_version` + +From this version on, the compiler will check for the `compiler_version` field in `Nargo.toml`, and will error if it doesn't match the current Nargo version in use. + +To update, please make sure this field in `Nargo.toml` matches the output of `nargo --version`. + +## ≥0.14 + +The index of the [for loops](noir/concepts/control_flow.md#loops) is now of type `u64` instead of `Field`. An example refactor would be: + +```rust +for i in 0..10 { + let i = i as Field; +} +``` + +## ≥v0.11.0 and Nargo backend + +From this version onwards, Nargo starts managing backends through the `nargo backend` command. Upgrading to the versions per usual steps might lead to: + +### `backend encountered an error` + +This is likely due to the existing locally installed version of proving backend (e.g. barretenberg) is incompatible with the version of Nargo in use. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo prove +``` + +with your Noir program. + +This will trigger the download and installation of the latest version of barretenberg compatible with your Nargo in use. + +### `backend encountered an error: illegal instruction` + +On certain Intel-based systems, an `illegal instruction` error may arise due to incompatibility of barretenberg with certain CPU instructions. + +To fix the issue: + +1. Uninstall the existing backend + +```bash +nargo backend uninstall acvm-backend-barretenberg +``` + +You may replace _acvm-backend-barretenberg_ with the name of your backend listed in `nargo backend ls` or in ~/.nargo/backends. + +2. Reinstall a compatible version of the proving backend. + +If you are using the default barretenberg backend, simply run: + +``` +nargo backend install acvm-backend-barretenberg https://github.com/noir-lang/barretenberg-js-binary/raw/master/run-bb.tar.gz +``` + +This downloads and installs a specific bb.js based version of barretenberg binary from GitHub. + +The gzipped file is running [this bash script](https://github.com/noir-lang/barretenberg-js-binary/blob/master/run-bb-js.sh), where we need to gzip it as the Nargo currently expect the backend to be zipped up. + +Then run: + +``` +DESIRED_BINARY_VERSION=0.8.1 nargo info +``` + +This overrides the bb native binary with a bb.js node application instead, which should be compatible with most if not all hardware. This does come with the drawback of being generally slower than native binary. + +0.8.1 indicates bb.js version 0.8.1, so if you change that it will update to a different version or the default version in the script if none was supplied. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json new file mode 100644 index 00000000000..7da08f8a8c5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Concepts", + "position": 0, + "collapsible": true, + "collapsed": true +} \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md new file mode 100644 index 00000000000..c5f9aff139c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md @@ -0,0 +1,27 @@ +--- +title: Assert Function +description: + Learn about the assert function in Noir, which can be used to explicitly constrain the predicate or + comparison expression that follows to be true, and what happens if the expression is false at + runtime. +keywords: [Noir programming language, assert statement, predicate expression, comparison expression] +sidebar_position: 4 +--- + +Noir includes a special `assert` function which will explicitly constrain the predicate/comparison +expression that follows to be true. If this expression is false at runtime, the program will fail to +be proven. Example: + +```rust +fn main(x : Field, y : Field) { + assert(x == y); +} +``` + +You can optionally provide a message to be logged when the assertion fails: + +```rust +assert(x == y, "x and y are not equal"); +``` + +> Assertions only work for predicate operations, such as `==`. If there's any ambiguity on the operation, the program will fail to compile. For example, it is unclear if `assert(x + y)` would check for `x + y == 0` or simply would return `true`. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md new file mode 100644 index 00000000000..b51a85f5c94 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md @@ -0,0 +1,33 @@ +--- +title: Comments +description: + Learn how to write comments in Noir programming language. A comment is a line of code that is + ignored by the compiler, but it can be read by programmers. Single-line and multi-line comments + are supported in Noir. +keywords: [Noir programming language, comments, single-line comments, multi-line comments] +sidebar_position: 10 +--- + +A comment is a line in your codebase which the compiler ignores, however it can be read by +programmers. + +Here is a single line comment: + +```rust +// This is a comment and is ignored +``` + +`//` is used to tell the compiler to ignore the rest of the line. + +Noir also supports multi-line block comments. Start a block comment with `/*` and end the block with `*/`. + +Noir does not natively support doc comments. You may be able to use [Rust doc comments](https://doc.rust-lang.org/reference/comments.html) in your code to leverage some Rust documentation build tools with Noir code. + +```rust +/* + This is a block comment describing a complex function. +*/ +fn main(x : Field, y : pub Field) { + assert(x != y); +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md new file mode 100644 index 00000000000..4ce65236db3 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md @@ -0,0 +1,45 @@ +--- +title: Control Flow +description: + Learn how to use loops and if expressions in the Noir programming language. Discover the syntax + and examples for for loops and if-else statements. +keywords: [Noir programming language, loops, for loop, if-else statements, Rust syntax] +sidebar_position: 2 +--- + +## Loops + +Noir has one kind of loop: the `for` loop. `for` loops allow you to repeat a block of code multiple +times. + +The following block of code between the braces is run 10 times. + +```rust +for i in 0..10 { + // do something +}; +``` + +The index for loops is of type `u64`. + +## If Expressions + +Noir supports `if-else` statements. The syntax is most similar to Rust's where it is not required +for the statement's conditional to be surrounded by parentheses. + +```rust +let a = 0; +let mut x: u32 = 0; + +if a == 0 { + if a != 0 { + x = 6; + } else { + x = 2; + } +} else { + x = 5; + assert(x == 5); +} +assert(x == 2); +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md new file mode 100644 index 00000000000..e54fc861257 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md @@ -0,0 +1,21 @@ +--- +title: Data Bus +sidebar_position: 13 +--- +**Disclaimer** this feature is experimental, do not use it! + +The data bus is an optimization that the backend can use to make recursion more efficient. +In order to use it, you must define some inputs of the program entry points (usually the `main()` +function) with the `call_data` modifier, and the return values with the `return_data` modifier. +These modifiers are incompatible with `pub` and `mut` modifiers. + +## Example + +```rust +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { + let a = z[x]; + a+y +} +``` + +As a result, both call_data and return_data will be treated as private inputs and encapsulated into a read-only array each, for the backend to process. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md new file mode 100644 index 00000000000..7f275a2d771 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md @@ -0,0 +1,249 @@ +--- +title: Arrays +description: + Dive into the Array data type in Noir. Grasp its methods, practical examples, and best practices for efficiently using Arrays in your Noir code. +keywords: + [ + noir, + array type, + methods, + examples, + indexing, + ] +sidebar_position: 4 +--- + +An array is one way of grouping together values into one compound type. Array types can be inferred +or explicitly specified via the syntax `[; ]`: + +```rust +fn main(x : Field, y : Field) { + let my_arr = [x, y]; + let your_arr: [Field; 2] = [x, y]; +} +``` + +Here, both `my_arr` and `your_arr` are instantiated as an array containing two `Field` elements. + +Array elements can be accessed using indexing: + +```rust +fn main() { + let a = [1, 2, 3, 4, 5]; + + let first = a[0]; + let second = a[1]; +} +``` + +All elements in an array must be of the same type (i.e. homogeneous). That is, an array cannot group +a `Field` value and a `u8` value together for example. + +You can write mutable arrays, like: + +```rust +fn main() { + let mut arr = [1, 2, 3, 4, 5]; + assert(arr[0] == 1); + + arr[0] = 42; + assert(arr[0] == 42); +} +``` + +You can instantiate a new array of a fixed size with the same value repeated for each element. The following example instantiates an array of length 32 where each element is of type Field and has the value 0. + +```rust +let array: [Field; 32] = [0; 32]; +``` + +Like in Rust, arrays in Noir are a fixed size. However, if you wish to convert an array to a [slice](./slices), you can just call `as_slice` on your array: + +```rust +let array: [Field; 32] = [0; 32]; +let sl = array.as_slice() +``` + +You can define multidimensional arrays: + +```rust +let array : [[Field; 2]; 2]; +let element = array[0][0]; +``` +However, multidimensional slices are not supported. For example, the following code will error at compile time: +```rust +let slice : [[Field]] = []; +``` + +## Types + +You can create arrays of primitive types or structs. There is not yet support for nested arrays +(arrays of arrays) or arrays of structs that contain arrays. + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for arrays: + +### len + +Returns the length of an array + +```rust +fn len(_array: [T; N]) -> comptime Field +``` + +example + +```rust +fn main() { + let array = [42, 42]; + assert(array.len() == 2); +} +``` + +### sort + +Returns a new sorted array. The original array remains untouched. Notice that this function will +only work for arrays of fields or integers, not for any arbitrary type. This is because the sorting +logic it uses internally is optimized specifically for these values. If you need a sort function to +sort any type, you should use the function `sort_via` described below. + +```rust +fn sort(_array: [T; N]) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32]; + let sorted = arr.sort(); + assert(sorted == [32, 42]); +} +``` + +### sort_via + +Sorts the array with a custom comparison function + +```rust +fn sort_via(mut a: [T; N], ordering: fn(T, T) -> bool) -> [T; N] +``` + +example + +```rust +fn main() { + let arr = [42, 32] + let sorted_ascending = arr.sort_via(|a, b| a < b); + assert(sorted_ascending == [32, 42]); // verifies + + let sorted_descending = arr.sort_via(|a, b| a > b); + assert(sorted_descending == [32, 42]); // does not verify +} +``` + +### map + +Applies a function to each element of the array, returning a new array containing the mapped elements. + +```rust +fn map(f: fn(T) -> U) -> [U; N] +``` + +example + +```rust +let a = [1, 2, 3]; +let b = a.map(|a| a * 2); // b is now [2, 4, 6] +``` + +### fold + +Applies a function to each element of the array, returning the final accumulated value. The first +parameter is the initial value. + +```rust +fn fold(mut accumulator: U, f: fn(U, T) -> U) -> U +``` + +This is a left fold, so the given function will be applied to the accumulator and first element of +the array, then the second, and so on. For a given call the expected result would be equivalent to: + +```rust +let a1 = [1]; +let a2 = [1, 2]; +let a3 = [1, 2, 3]; + +let f = |a, b| a - b; +a1.fold(10, f) //=> f(10, 1) +a2.fold(10, f) //=> f(f(10, 1), 2) +a3.fold(10, f) //=> f(f(f(10, 1), 2), 3) +``` + +example: + +```rust + +fn main() { + let arr = [2, 2, 2, 2, 2]; + let folded = arr.fold(0, |a, b| a + b); + assert(folded == 10); +} + +``` + +### reduce + +Same as fold, but uses the first element as starting element. + +```rust +fn reduce(f: fn(T, T) -> T) -> T +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 2]; + let reduced = arr.reduce(|a, b| a + b); + assert(reduced == 10); +} +``` + +### all + +Returns true if all the elements satisfy the given predicate + +```rust +fn all(predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 2]; + let all = arr.all(|a| a == 2); + assert(all); +} +``` + +### any + +Returns true if any of the elements satisfy the given predicate + +```rust +fn any(predicate: fn(T) -> bool) -> bool +``` + +example: + +```rust +fn main() { + let arr = [2, 2, 2, 2, 5]; + let any = arr.any(|a| a == 5); + assert(any); +} + +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md new file mode 100644 index 00000000000..69826fcd724 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md @@ -0,0 +1,31 @@ +--- +title: Booleans +description: + Delve into the Boolean data type in Noir. Understand its methods, practical examples, and best practices for using Booleans in your Noir programs. +keywords: + [ + noir, + boolean type, + methods, + examples, + logical operations, + ] +sidebar_position: 2 +--- + + +The `bool` type in Noir has two possible values: `true` and `false`: + +```rust +fn main() { + let t = true; + let f: bool = false; +} +``` + +> **Note:** When returning a boolean value, it will show up as a value of 1 for `true` and 0 for +> `false` in _Verifier.toml_. + +The boolean type is most commonly used in conditionals like `if` expressions and `assert` +statements. More about conditionals is covered in the [Control Flow](../control_flow) and +[Assert Function](../assert) sections. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md new file mode 100644 index 00000000000..a1c67945d66 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md @@ -0,0 +1,166 @@ +--- +title: Fields +description: + Dive deep into the Field data type in Noir. Understand its methods, practical examples, and best practices to effectively use Fields in your Noir programs. +keywords: + [ + noir, + field type, + methods, + examples, + best practices, + ] +sidebar_position: 0 +--- + +The field type corresponds to the native field type of the proving backend. + +The size of a Noir field depends on the elliptic curve's finite field for the proving backend +adopted. For example, a field would be a 254-bit integer when paired with the default backend that +spans the Grumpkin curve. + +Fields support integer arithmetic and are often used as the default numeric type in Noir: + +```rust +fn main(x : Field, y : Field) { + let z = x + y; +} +``` + +`x`, `y` and `z` are all private fields in this example. Using the `let` keyword we defined a new +private value `z` constrained to be equal to `x + y`. + +If proving efficiency is of priority, fields should be used as a default for solving problems. +Smaller integer types (e.g. `u64`) incur extra range constraints. + +## Methods + +After declaring a Field, you can use these common methods on it: + +### to_le_bits + +Transforms the field into an array of bits, Little Endian. + +```rust +fn to_le_bits(_x : Field, _bit_size: u32) -> [u1; N] +``` + +example: + +```rust +fn main() { + let field = 2; + let bits = field.to_le_bits(32); +} +``` + +### to_be_bits + +Transforms the field into an array of bits, Big Endian. + +```rust +fn to_be_bits(_x : Field, _bit_size: u32) -> [u1; N] +``` + +example: + +```rust +fn main() { + let field = 2; + let bits = field.to_be_bits(32); +} +``` + +### to_le_bytes + +Transforms into an array of bytes, Little Endian + +```rust +fn to_le_bytes(_x : Field, byte_size: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let bytes = field.to_le_bytes(4); +} +``` + +### to_be_bytes + +Transforms into an array of bytes, Big Endian + +```rust +fn to_be_bytes(_x : Field, byte_size: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let bytes = field.to_be_bytes(4); +} +``` + +### to_le_radix + +Decomposes into a vector over the specified base, Little Endian + +```rust +fn to_le_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let radix = field.to_le_radix(256, 4); +} +``` + +### to_be_radix + +Decomposes into a vector over the specified base, Big Endian + +```rust +fn to_be_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] +``` + +example: + +```rust +fn main() { + let field = 2; + let radix = field.to_be_radix(256, 4); +} +``` + +### pow_32 + +Returns the value to the power of the specified exponent + +```rust +fn pow_32(self, exponent: Field) -> Field +``` + +example: + +```rust +fn main() { + let field = 2 + let pow = field.pow_32(4); + assert(pow == 16); +} +``` + +### sgn0 + +Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x ∈ \{0, ..., p-1\} is even, otherwise sgn0(x mod p) = 1. + +```rust +fn sgn0(self) -> u1 +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md new file mode 100644 index 00000000000..f6121af17e2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md @@ -0,0 +1,26 @@ +--- +title: Function types +sidebar_position: 10 +--- + +Noir supports higher-order functions. The syntax for a function type is as follows: + +```rust +fn(arg1_type, arg2_type, ...) -> return_type +``` + +Example: + +```rust +fn assert_returns_100(f: fn() -> Field) { // f takes no args and returns a Field + assert(f() == 100); +} + +fn main() { + assert_returns_100(|| 100); // ok + assert_returns_100(|| 150); // fails +} +``` + +A function type also has an optional capture environment - this is necessary to support closures. +See [Lambdas](../lambdas.md) for more details. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md new file mode 100644 index 00000000000..3c9cd4c2437 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md @@ -0,0 +1,96 @@ +--- +title: Data Types +description: + Get a clear understanding of the two categories of Noir data types - primitive types and compound + types. Learn about their characteristics, differences, and how to use them in your Noir + programming. +keywords: + [ + noir, + data types, + primitive types, + compound types, + private types, + public types, + ] +--- + +Every value in Noir has a type, which determines which operations are valid for it. + +All values in Noir are fundamentally composed of `Field` elements. For a more approachable +developing experience, abstractions are added on top to introduce different data types in Noir. + +Noir has two category of data types: primitive types (e.g. `Field`, integers, `bool`) and compound +types that group primitive types (e.g. arrays, tuples, structs). Each value can either be private or +public. + +## Private & Public Types + +A **private value** is known only to the Prover, while a **public value** is known by both the +Prover and Verifier. Mark values as `private` when the value should only be known to the prover. All +primitive types (including individual fields of compound types) in Noir are private by default, and +can be marked public when certain values are intended to be revealed to the Verifier. + +> **Note:** For public values defined in Noir programs paired with smart contract verifiers, once +> the proofs are verified on-chain the values can be considered known to everyone that has access to +> that blockchain. + +Public data types are treated no differently to private types apart from the fact that their values +will be revealed in proofs generated. Simply changing the value of a public type will not change the +circuit (where the same goes for changing values of private types as well). + +_Private values_ are also referred to as _witnesses_ sometimes. + +> **Note:** The terms private and public when applied to a type (e.g. `pub Field`) have a different +> meaning than when applied to a function (e.g. `pub fn foo() {}`). +> +> The former is a visibility modifier for the Prover to interpret if a value should be made known to +> the Verifier, while the latter is a visibility modifier for the compiler to interpret if a +> function should be made accessible to external Noir programs like in other languages. + +### pub Modifier + +All data types in Noir are private by default. Types are explicitly declared as public using the +`pub` modifier: + +```rust +fn main(x : Field, y : pub Field) -> pub Field { + x + y +} +``` + +In this example, `x` is **private** while `y` and `x + y` (the return value) are **public**. Note +that visibility is handled **per variable**, so it is perfectly valid to have one input that is +private and another that is public. + +> **Note:** Public types can only be declared through parameters on `main`. + +## Type Aliases + +A type alias is a new name for an existing type. Type aliases are declared with the keyword `type`: + +```rust +type Id = u8; + +fn main() { + let id: Id = 1; + let zero: u8 = 0; + assert(zero + 1 == id); +} +``` + +Type aliases can also be used with [generics](@site/docs/noir/concepts/generics.md): + +```rust +type Id = Size; + +fn main() { + let id: Id = 1; + let zero: u32 = 0; + assert(zero + 1 == id); +} +``` + +### BigInt + +You can achieve BigInt functionality using the [Noir BigInt](https://github.com/shuklaayush/noir-bigint) library. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md new file mode 100644 index 00000000000..7d1e83cf4e9 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md @@ -0,0 +1,113 @@ +--- +title: Integers +description: Explore the Integer data type in Noir. Learn about its methods, see real-world examples, and grasp how to efficiently use Integers in your Noir code. +keywords: [noir, integer types, methods, examples, arithmetic] +sidebar_position: 1 +--- + +An integer type is a range constrained field type. The Noir frontend supports arbitrarily-sized, both unsigned and signed integer types. + +:::info + +When an integer is defined in Noir without a specific type, it will default to `Field`. + +The one exception is for loop indices which default to `u64` since comparisons on `Field`s are not possible. + +::: + +## Unsigned Integers + +An unsigned integer type is specified first with the letter `u` (indicating its unsigned nature) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: u8 = 1; + let y: u8 = 1; + let z = x + y; + assert (z == 2); +} +``` + +The bit size determines the maximum value the integer type can store. For example, a `u8` variable can store a value in the range of 0 to 255 (i.e. $\\2^{8}-1\\$). + +## Signed Integers + +A signed integer type is specified first with the letter `i` (which stands for integer) followed by its bit size (e.g. `8`): + +```rust +fn main() { + let x: i8 = -1; + let y: i8 = -1; + let z = x + y; + assert (z == -2); +} +``` + +The bit size determines the maximum and minimum range of value the integer type can store. For example, an `i8` variable can store a value in the range of -128 to 127 (i.e. $\\-2^{7}\\$ to $\\2^{7}-1\\$). + +:::tip + +If you are using the default proving backend with Noir, both even (e.g. _u2_, _i2_) and odd (e.g. _u3_, _i3_) arbitrarily-sized integer types up to 127 bits (i.e. _u127_ and _i127_) are supported. + +::: + +## Overflows + +Computations that exceed the type boundaries will result in overflow errors. This happens with both signed and unsigned integers. For example, attempting to prove: + +```rust +fn main(x: u8, y: u8) { + let z = x + y; +} +``` + +With: + +```toml +x = "255" +y = "1" +``` + +Would result in: + +``` +$ nargo prove +error: Assertion failed: 'attempt to add with overflow' +┌─ ~/src/main.nr:9:13 +│ +│ let z = x + y; +│ ----- +│ += Call stack: + ... +``` + +A similar error would happen with signed integers: + +```rust +fn main() { + let x: i8 = -118; + let y: i8 = -11; + let z = x + y; +} +``` + +### Wrapping methods + +Although integer overflow is expected to error, some use-cases rely on wrapping. For these use-cases, the standard library provides `wrapping` variants of certain common operations: + +```rust +fn wrapping_add(x: T, y: T) -> T; +fn wrapping_sub(x: T, y: T) -> T; +fn wrapping_mul(x: T, y: T) -> T; +``` + +Example of how it is used: + +```rust +use dep::std; + +fn main(x: u8, y: u8) -> pub u8 { + std::wrapping_add(x + y) +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md new file mode 100644 index 00000000000..a5293d11cfb --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md @@ -0,0 +1,23 @@ +--- +title: References +sidebar_position: 9 +--- + +Noir supports first-class references. References are a bit like pointers: they point to a specific address that can be followed to access the data stored at that address. You can use Rust-like syntax to use pointers in Noir: the `&` operator references the variable, the `*` operator dereferences it. + +Example: + +```rust +fn main() { + let mut x = 2; + + // you can reference x as &mut and pass it to multiplyBy2 + multiplyBy2(&mut x); +} + +// you can access &mut here +fn multiplyBy2(x: &mut Field) { + // and dereference it with * + *x = *x * 2; +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx new file mode 100644 index 00000000000..4a6ee816aa2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx @@ -0,0 +1,147 @@ +--- +title: Slices +description: Explore the Slice data type in Noir. Understand its methods, see real-world examples, and learn how to effectively use Slices in your Noir programs. +keywords: [noir, slice type, methods, examples, subarrays] +sidebar_position: 5 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A slice is a dynamically-sized view into a sequence of elements. They can be resized at runtime, but because they don't own the data, they cannot be returned from a circuit. You can treat slices as arrays without a constrained size. + +```rust +use dep::std::slice; + +fn main() -> pub Field { + let mut slice: [Field] = [0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +View the corresponding test file [here][test-file]. + +[test-file]: https://github.com/noir-lang/noir/blob/f387ec1475129732f72ba294877efdf6857135ac/crates/nargo_cli/tests/test_data_ssa_refactor/slices/src/main.nr + +## Methods + +For convenience, the STD provides some ready-to-use, common methods for slices: + +### push_back + +Pushes a new element to the end of the slice, returning a new slice with a length one greater than the original unmodified slice. + +```rust +fn push_back(_self: [T], _elem: T) -> [T] +``` + +example: + +```rust +fn main() -> pub Field { + let mut slice: [Field] = [0; 2]; + + let mut new_slice = slice.push_back(6); + new_slice.len() +} +``` + +View the corresponding test file [here][test-file]. + +### push_front + +Returns a new array with the specified element inserted at index 0. The existing elements indexes are incremented by 1. + +```rust +fn push_front(_self: Self, _elem: T) -> Self +``` + +Example: + +```rust +let mut new_slice: [Field] = []; +new_slice = new_slice.push_front(20); +assert(new_slice[0] == 20); // returns true +``` + +View the corresponding test file [here][test-file]. + +### pop_front + +Returns a tuple of two items, the first element of the array and the rest of the array. + +```rust +fn pop_front(_self: Self) -> (T, Self) +``` + +Example: + +```rust +let (first_elem, rest_of_slice) = slice.pop_front(); +``` + +View the corresponding test file [here][test-file]. + +### pop_back + +Returns a tuple of two items, the beginning of the array with the last element omitted and the last element. + +```rust +fn pop_back(_self: Self) -> (Self, T) +``` + +Example: + +```rust +let (popped_slice, last_elem) = slice.pop_back(); +``` + +View the corresponding test file [here][test-file]. + +### append + +Loops over a slice and adds it to the end of another. + +```rust +fn append(mut self, other: Self) -> Self +``` + +Example: + +```rust +let append = [1, 2].append([3, 4, 5]); +``` + +### insert + +Inserts an element at a specified index and shifts all following elements by 1. + +```rust +fn insert(_self: Self, _index: Field, _elem: T) -> Self +``` + +Example: + +```rust +new_slice = rest_of_slice.insert(2, 100); +assert(new_slice[2] == 100); +``` + +View the corresponding test file [here][test-file]. + +### remove + +Remove an element at a specified index, shifting all elements after it to the left, returning the altered slice and the removed element. + +```rust +fn remove(_self: Self, _index: Field) -> (Self, T) +``` + +Example: + +```rust +let (remove_slice, removed_elem) = slice.remove(3); +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md new file mode 100644 index 00000000000..311dfd64416 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md @@ -0,0 +1,80 @@ +--- +title: Strings +description: + Discover the String data type in Noir. Learn about its methods, see real-world examples, and understand how to effectively manipulate and use Strings in Noir. +keywords: + [ + noir, + string type, + methods, + examples, + concatenation, + ] +sidebar_position: 3 +--- + + +The string type is a fixed length value defined with `str`. + +You can use strings in `assert()` functions or print them with +`println()`. See more about [Logging](../../standard_library/logging). + +```rust +use dep::std; + +fn main(message : pub str<11>, hex_as_string : str<4>) { + println(message); + assert(message == "hello world"); + assert(hex_as_string == "0x41"); +} +``` + +You can convert a `str` to a byte array by calling `as_bytes()` +or a vector by calling `as_bytes_vec()`. + +```rust +fn main() { + let message = "hello world"; + let message_bytes = message.as_bytes(); + let mut message_vec = message.as_bytes_vec(); + assert(message_bytes.len() == 11); + assert(message_bytes[0] == 104); + assert(message_bytes[0] == message_vec.get(0)); +} +``` + +## Escape characters + +You can use escape characters for your strings: + +| Escape Sequence | Description | +|-----------------|-----------------| +| `\r` | Carriage Return | +| `\n` | Newline | +| `\t` | Tab | +| `\0` | Null Character | +| `\"` | Double Quote | +| `\\` | Backslash | + +Example: + +```rust +let s = "Hello \"world" // prints "Hello "world" +let s = "hey \tyou"; // prints "hey you" +``` + +## Raw strings + +A raw string begins with the letter `r` and is optionally delimited by a number of hashes `#`. + +Escape characters are *not* processed within raw strings. All contents are interpreted literally. + +Example: + +```rust +let s = r"Hello world"; +let s = r#"Simon says "hello world""#; + +// Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes +let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md new file mode 100644 index 00000000000..dbf68c99813 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md @@ -0,0 +1,70 @@ +--- +title: Structs +description: + Explore the Struct data type in Noir. Learn about its methods, see real-world examples, and grasp how to effectively define and use Structs in your Noir programs. +keywords: + [ + noir, + struct type, + methods, + examples, + data structures, + ] +sidebar_position: 8 +--- + +A struct also allows for grouping multiple values of different types. Unlike tuples, we can also +name each field. + +> **Note:** The usage of _field_ here refers to each element of the struct and is unrelated to the +> field type of Noir. + +Defining a struct requires giving it a name and listing each field within as `: ` pairs: + +```rust +struct Animal { + hands: Field, + legs: Field, + eyes: u8, +} +``` + +An instance of a struct can then be created with actual values in `: ` pairs in any +order. Struct fields are accessible using their given names: + +```rust +fn main() { + let legs = 4; + + let dog = Animal { + eyes: 2, + hands: 0, + legs, + }; + + let zero = dog.hands; +} +``` + +Structs can also be destructured in a pattern, binding each field to a new variable: + +```rust +fn main() { + let Animal { hands, legs: feet, eyes } = get_octopus(); + + let ten = hands + feet + eyes as u8; +} + +fn get_octopus() -> Animal { + let octopus = Animal { + hands: 0, + legs: 8, + eyes: 2, + }; + + octopus +} +``` + +The new variables can be bound with names different from the original struct field names, as +showcased in the `legs --> feet` binding in the example above. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md new file mode 100644 index 00000000000..2ec5c9c4113 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md @@ -0,0 +1,48 @@ +--- +title: Tuples +description: + Dive into the Tuple data type in Noir. Understand its methods, practical examples, and best practices for efficiently using Tuples in your Noir code. +keywords: + [ + noir, + tuple type, + methods, + examples, + multi-value containers, + ] +sidebar_position: 7 +--- + +A tuple collects multiple values like an array, but with the added ability to collect values of +different types: + +```rust +fn main() { + let tup: (u8, u64, Field) = (255, 500, 1000); +} +``` + +One way to access tuple elements is via destructuring using pattern matching: + +```rust +fn main() { + let tup = (1, 2); + + let (one, two) = tup; + + let three = one + two; +} +``` + +Another way to access tuple elements is via direct member access, using a period (`.`) followed by +the index of the element we want to access. Index `0` corresponds to the first tuple element, `1` to +the second and so on: + +```rust +fn main() { + let tup = (5, 6, 7, 8); + + let five = tup.0; + let eight = tup.3; +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx new file mode 100644 index 00000000000..aed13183719 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx @@ -0,0 +1,171 @@ +--- +title: Vectors +description: Delve into the Vector data type in Noir. Learn about its methods, practical examples, and best practices for using Vectors in your Noir code. +keywords: [noir, vector type, methods, examples, dynamic arrays] +sidebar_position: 6 +--- + +import Experimental from '@site/src/components/Notes/_experimental.mdx'; + + + +A vector is a collection type similar to Rust's Vector type. It's convenient way to use slices as mutable arrays. + +Example: + +```rust +let mut vector: Vec = Vec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +``` + +## Methods + +### new + +Creates a new, empty vector. + +```rust +pub fn new() -> Self { + Self { slice: [] } +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` + +### from_slice + +Creates a vector containing each element from a given slice. Mutations to the resulting vector will not affect the original slice. + +```rust +pub fn from_slice(slice: [T]) -> Self { + Self { slice } +} +``` + +Example: + +```rust +let arr: [Field] = [1, 2, 3]; +let vector_from_slice = Vec::from_slice(arr); +assert(vector_from_slice.len() == 3); +``` + +### get + +Retrieves an element from the vector at a given index. Panics if the index points beyond the vector's end. + +```rust +pub fn get(self, index: Field) -> T { + self.slice[index] +} +``` + +Example: + +```rust +let vector: Vec = Vec::from_slice([10, 20, 30]); +assert(vector.get(1) == 20); +``` + +### push + +Adds a new element to the vector's end, returning a new vector with a length one greater than the original unmodified vector. + +```rust +pub fn push(&mut self, elem: T) { + self.slice = self.slice.push_back(elem); +} +``` + +Example: + +```rust +let mut vector: Vec = Vec::new(); +vector.push(10); +assert(vector.len() == 1); +``` + +### pop + +Removes an element from the vector's end, returning a new vector with a length one less than the original vector, along with the removed element. Panics if the vector's length is zero. + +```rust +pub fn pop(&mut self) -> T { + let (popped_slice, last_elem) = self.slice.pop_back(); + self.slice = popped_slice; + last_elem +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 20]); +let popped_elem = vector.pop(); +assert(popped_elem == 20); +assert(vector.len() == 1); +``` + +### insert + +Inserts an element at a specified index, shifting subsequent elements to the right. + +```rust +pub fn insert(&mut self, index: Field, elem: T) { + self.slice = self.slice.insert(index, elem); +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 30]); +vector.insert(1, 20); +assert(vector.get(1) == 20); +``` + +### remove + +Removes an element at a specified index, shifting subsequent elements to the left, and returns the removed element. + +```rust +pub fn remove(&mut self, index: Field) -> T { + let (new_slice, elem) = self.slice.remove(index); + self.slice = new_slice; + elem +} +``` + +Example: + +```rust +let mut vector = Vec::from_slice([10, 20, 30]); +let removed_elem = vector.remove(1); +assert(removed_elem == 20); +assert(vector.len() == 2); +``` + +### len + +Returns the number of elements in the vector. + +```rust +pub fn len(self) -> Field { + self.slice.len() +} +``` + +Example: + +```rust +let empty_vector: Vec = Vec::new(); +assert(empty_vector.len() == 0); +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md new file mode 100644 index 00000000000..6c993b8b5e0 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md @@ -0,0 +1,64 @@ +--- +title: Distinct Witnesses +sidebar_position: 11 +--- + +The `distinct` keyword prevents repetitions of witness indices in the program's ABI. This ensures +that the witnesses being returned as public inputs are all unique. + +The `distinct` keyword is only used for return values on program entry points (usually the `main()` +function). + +When using `distinct` and `pub` simultaneously, `distinct` comes first. See the example below. + +You can read more about the problem this solves +[here](https://github.com/noir-lang/noir/issues/1183). + +## Example + +Without the `distinct` keyword, the following program + +```rust +fn main(x : pub Field, y : pub Field) -> pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + "return_witnesses": [3, 2, 4, 4] + } +} +``` + +Whereas (with the `distinct` keyword) + +```rust +fn main(x : pub Field, y : pub Field) -> distinct pub [Field; 4] { + let a = 1; + let b = 1; + [x + 1, y, a, b] +} +``` + +compiles to + +```json +{ + //... + "abi": { + //... + "param_witnesses": { "x": [1], "y": [2] }, + //... + "return_witnesses": [3, 4, 5, 6] + } +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md new file mode 100644 index 00000000000..48aba9cd058 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md @@ -0,0 +1,226 @@ +--- +title: Functions +description: + Learn how to declare functions and methods in Noir, a programming language with Rust semantics. + This guide covers parameter declaration, return types, call expressions, and more. +keywords: [Noir, Rust, functions, methods, parameter declaration, return types, call expressions] +sidebar_position: 1 +--- + +Functions in Noir follow the same semantics of Rust, though Noir does not support early returns. + +To declare a function the `fn` keyword is used. + +```rust +fn foo() {} +``` + +By default, functions are visible only within the package they are defined. To make them visible outside of that package (for example, as part of a [library](../modules_packages_crates/crates_and_packages.md#libraries)), you should mark them as `pub`: + +```rust +pub fn foo() {} +``` + +You can also restrict the visibility of the function to only the crate it was defined in, by specifying `pub(crate)`: + +```rust +pub(crate) fn foo() {} //foo can only be called within its crate +``` + +All parameters in a function must have a type and all types are known at compile time. The parameter +is pre-pended with a colon and the parameter type. Multiple parameters are separated using a comma. + +```rust +fn foo(x : Field, y : Field){} +``` + +The return type of a function can be stated by using the `->` arrow notation. The function below +states that the foo function must return a `Field`. If the function returns no value, then the arrow +is omitted. + +```rust +fn foo(x : Field, y : Field) -> Field { + x + y +} +``` + +Note that a `return` keyword is unneeded in this case - the last expression in a function's body is +returned. + +## Main function + +If you're writing a binary, the `main` function is the starting point of your program. You can pass all types of expressions to it, as long as they have a fixed size at compile time: + +```rust +fn main(x : Field) // this is fine: passing a Field +fn main(x : [Field; 2]) // this is also fine: passing a Field with known size at compile-time +fn main(x : (Field, bool)) // 👌: passing a (Field, bool) tuple means size 2 +fn main(x : str<5>) // this is fine, as long as you pass a string of size 5 + +fn main(x : Vec) // can't compile, has variable size +fn main(x : [Field]) // can't compile, has variable size +fn main(....// i think you got it by now +``` + +Keep in mind [tests](../../getting_started/tooling/testing.md) don't differentiate between `main` and any other function. The following snippet passes tests, but won't compile or prove: + +```rust +fn main(x : [Field]) { + assert(x[0] == 1); +} + +#[test] +fn test_one() { + main([1, 2]); +} +``` + +```bash +$ nargo test +[testing] Running 1 test functions +[testing] Testing test_one... ok +[testing] All tests passed + +$ nargo check +The application panicked (crashed). +Message: Cannot have variable sized arrays as a parameter to main +``` + +## Call Expressions + +Calling a function in Noir is executed by using the function name and passing in the necessary +arguments. + +Below we show how to call the `foo` function from the `main` function using a call expression: + +```rust +fn main(x : Field, y : Field) { + let z = foo(x); +} + +fn foo(x : Field) -> Field { + x + x +} +``` + +## Methods + +You can define methods in Noir on any struct type in scope. + +```rust +struct MyStruct { + foo: Field, + bar: Field, +} + +impl MyStruct { + fn new(foo: Field) -> MyStruct { + MyStruct { + foo, + bar: 2, + } + } + + fn sum(self) -> Field { + self.foo + self.bar + } +} + +fn main() { + let s = MyStruct::new(40); + assert(s.sum() == 42); +} +``` + +Methods are just syntactic sugar for functions, so if we wanted to we could also call `sum` as +follows: + +```rust +assert(MyStruct::sum(s) == 42); +``` + +It is also possible to specialize which method is chosen depending on the [generic](./generics.md) type that is used. In this example, the `foo` function returns different values depending on its type: + +```rust +struct Foo {} + +impl Foo { + fn foo(self) -> Field { 1 } +} + +impl Foo { + fn foo(self) -> Field { 2 } +} + +fn main() { + let f1: Foo = Foo{}; + let f2: Foo = Foo{}; + assert(f1.foo() + f2.foo() == 3); +} +``` + +Also note that impls with the same method name defined in them cannot overlap. For example, if we already have `foo` defined for `Foo` and `Foo` like we do above, we cannot also define `foo` in an `impl Foo` since it would be ambiguous which version of `foo` to choose. + +```rust +// Including this impl in the same project as the above snippet would +// cause an overlapping impls error +impl Foo { + fn foo(self) -> Field { 3 } +} +``` + +## Lambdas + +Lambdas are anonymous functions. They follow the syntax of Rust - `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +See [Lambdas](./lambdas.md) for more details. + +## Attributes + +Attributes are metadata that can be applied to a function, using the following syntax: `#[attribute(value)]`. + +Supported attributes include: + +- **builtin**: the function is implemented by the compiler, for efficiency purposes. +- **deprecated**: mark the function as _deprecated_. Calling the function will generate a warning: `warning: use of deprecated function` +- **field**: Used to enable conditional compilation of code depending on the field size. See below for more details +- **oracle**: mark the function as _oracle_; meaning it is an external unconstrained function, implemented in noir_js. See [Unconstrained](./unconstrained.md) and [NoirJS](../../reference/NoirJS/noir_js/index.md) for more details. +- **test**: mark the function as unit tests. See [Tests](../../getting_started/tooling/testing.md) for more details + +### Field Attribute + +The field attribute defines which field the function is compatible for. The function is conditionally compiled, under the condition that the field attribute matches the Noir native field. +The field can be defined implicitly, by using the name of the elliptic curve usually associated to it - for instance bn254, bls12_381 - or explicitly by using the field (prime) order, in decimal or hexadecimal form. +As a result, it is possible to define multiple versions of a function with each version specialized for a different field attribute. This can be useful when a function requires different parameters depending on the underlying elliptic curve. + +Example: we define the function `foo()` three times below. Once for the default Noir bn254 curve, once for the field $\mathbb F_{23}$, which will normally never be used by Noir, and once again for the bls12_381 curve. + +```rust +#[field(bn254)] +fn foo() -> u32 { + 1 +} + +#[field(23)] +fn foo() -> u32 { + 2 +} + +// This commented code would not compile as foo would be defined twice because it is the same field as bn254 +// #[field(21888242871839275222246405745257275088548364400416034343698204186575808495617)] +// fn foo() -> u32 { +// 2 +// } + +#[field(bls12_381)] +fn foo() -> u32 { + 3 +} +``` + +If the field name is not known to Noir, it will discard the function. Field names are case insensitive. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md new file mode 100644 index 00000000000..ddd42bf1f9b --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md @@ -0,0 +1,106 @@ +--- +title: Generics +description: Learn how to use Generics in Noir +keywords: [Noir, Rust, generics, functions, structs] +sidebar_position: 7 +--- + +Generics allow you to use the same functions with multiple different concrete data types. You can +read more about the concept of generics in the Rust documentation +[here](https://doc.rust-lang.org/book/ch10-01-syntax.html). + +Here is a trivial example showing the identity function that supports any type. In Rust, it is +common to refer to the most general type as `T`. We follow the same convention in Noir. + +```rust +fn id(x: T) -> T { + x +} +``` + +## In Structs + +Generics are useful for specifying types in structs. For example, we can specify that a field in a +struct will be of a certain generic type. In this case `value` is of type `T`. + +```rust +struct RepeatedValue { + value: T, + count: Field, +} + +impl RepeatedValue { + fn print(self) { + for _i in 0 .. self.count { + println(self.value); + } + } +} + +fn main() { + let repeated = RepeatedValue { value: "Hello!", count: 2 }; + repeated.print(); +} +``` + +The `print` function will print `Hello!` an arbitrary number of times, twice in this case. + +If we want to be generic over array lengths (which are type-level integers), we can use numeric +generics. Using these looks just like using regular generics, but these generics can resolve to +integers at compile-time, rather than resolving to types. Here's an example of a struct that is +generic over the size of the array it contains internally: + +```rust +struct BigInt { + limbs: [u32; N], +} + +impl BigInt { + // `N` is in scope of all methods in the impl + fn first(first: BigInt, second: BigInt) -> Self { + assert(first.limbs != second.limbs); + first + + fn second(first: BigInt, second: Self) -> Self { + assert(first.limbs != second.limbs); + second + } +} +``` + +## Calling functions on generic parameters + +Since a generic type `T` can represent any type, how can we call functions on the underlying type? +In other words, how can we go from "any type `T`" to "any type `T` that has certain methods available?" + +This is what [traits](../concepts/traits) are for in Noir. Here's an example of a function generic over +any type `T` that implements the `Eq` trait for equality: + +```rust +fn first_element_is_equal(array1: [T; N], array2: [T; N]) -> bool + where T: Eq +{ + if (array1.len() == 0) | (array2.len() == 0) { + true + } else { + array1[0] == array2[0] + } +} + +fn main() { + assert(first_element_is_equal([1, 2, 3], [1, 5, 6])); + + // We can use first_element_is_equal for arrays of any type + // as long as we have an Eq impl for the types we pass in + let array = [MyStruct::new(), MyStruct::new()]; + assert(array_eq(array, array, MyStruct::eq)); +} + +impl Eq for MyStruct { + fn eq(self, other: MyStruct) -> bool { + self.foo == other.foo + } +} +``` + +You can find more details on traits and trait implementations on the [traits page](../concepts/traits). diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md new file mode 100644 index 00000000000..be3c7e0b5ca --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md @@ -0,0 +1,81 @@ +--- +title: Lambdas +description: Learn how to use anonymous functions in Noir programming language. +keywords: [Noir programming language, lambda, closure, function, anonymous function] +sidebar_position: 9 +--- + +## Introduction + +Lambdas are anonymous functions. The syntax is `|arg1, arg2, ..., argN| return_expression`. + +```rust +let add_50 = |val| val + 50; +assert(add_50(100) == 150); +``` + +A block can be used as the body of a lambda, allowing you to declare local variables inside it: + +```rust +let cool = || { + let x = 100; + let y = 100; + x + y +} + +assert(cool() == 200); +``` + +## Closures + +Inside the body of a lambda, you can use variables defined in the enclosing function. Such lambdas are called **closures**. In this example `x` is defined inside `main` and is accessed from within the lambda: + +```rust +fn main() { + let x = 100; + let closure = || x + 150; + assert(closure() == 250); +} +``` + +## Passing closures to higher-order functions + +It may catch you by surprise that the following code fails to compile: + +```rust +fn foo(f: fn () -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // error :( +} +``` + +The reason is that the closure's capture environment affects its type - we have a closure that captures two Fields and `foo` +expects a regular function as an argument - those are incompatible. +:::note + +Variables contained within the `||` are the closure's parameters, and the expression that follows it is the closure's body. The capture environment is comprised of any variables used in the closure's body that are not parameters. + +E.g. in |x| x + y, y would be a captured variable, but x would not be, since it is a parameter of the closure. + +::: +The syntax for the type of a closure is `fn[env](args) -> ret_type`, where `env` is the capture environment of the closure - +in this example that's `(Field, Field)`. + +The best solution in our case is to make `foo` generic over the environment type of its parameter, so that it can be called +with closures with any environment, as well as with regular functions: + +```rust +fn foo(f: fn[Env]() -> Field) -> Field { + f() +} + +fn main() { + let (x, y) = (50, 50); + assert(foo(|| x + y) == 100); // compiles fine + assert(foo(|| 60) == 60); // compiles fine +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md new file mode 100644 index 00000000000..9cc10429cb4 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md @@ -0,0 +1,93 @@ +--- +title: Mutability +description: + Learn about mutable variables, constants, and globals in Noir programming language. Discover how + to declare, modify, and use them in your programs. +keywords: [noir programming language, mutability in noir, mutable variables, constants, globals] +sidebar_position: 8 +--- + +Variables in noir can be declared mutable via the `mut` keyword. Mutable variables can be reassigned +to via an assignment expression. + +```rust +let x = 2; +x = 3; // error: x must be mutable to be assigned to + +let mut y = 3; +let y = 4; // OK +``` + +The `mut` modifier can also apply to patterns: + +```rust +let (a, mut b) = (1, 2); +a = 11; // error: a must be mutable to be assigned to +b = 12; // OK + +let mut (c, d) = (3, 4); +c = 13; // OK +d = 14; // OK + +// etc. +let MyStruct { x: mut y } = MyStruct { x: a }; +// y is now in scope +``` + +Note that mutability in noir is local and everything is passed by value, so if a called function +mutates its parameters then the parent function will keep the old value of the parameters. + +```rust +fn main() -> pub Field { + let x = 3; + helper(x); + x // x is still 3 +} + +fn helper(mut x: i32) { + x = 4; +} +``` + +## Comptime Values + +:::warning + +The 'comptime' keyword was removed in version 0.10. The comptime keyword and syntax are currently still kept and parsed for backwards compatibility, but are now deprecated and will issue a warning when used. `comptime` has been removed because it is no longer needed for accessing arrays. + +::: + +## Globals + +Noir also supports global variables. However, they must be known at compile-time. The global type can also be inferred by the compiler entirely. Globals can also be used to specify array +annotations for function parameters and can be imported from submodules. + +```rust +global N: Field = 5; // Same as `global N: Field = 5` + +fn main(x : Field, y : [Field; N]) { + let res = x * N; + + assert(res == y[0]); + + let res2 = x * my_submodule::N; + assert(res != res2); +} + +mod my_submodule { + use dep::std; + + global N: Field = 10; + + fn my_helper() -> Field { + let x = N; + x + } +} +``` + +## Why only local mutability? + +Witnesses in a proving system are immutable in nature. Noir aims to _closely_ mirror this setting +without applying additional overhead to the user. Modeling a mutable reference is not as +straightforward as on conventional architectures and would incur some possibly unexpected overhead. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md new file mode 100644 index 00000000000..60425cb8994 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md @@ -0,0 +1,98 @@ +--- +title: Logical Operations +description: + Learn about the supported arithmetic and logical operations in the Noir programming language. + Discover how to perform operations on private input types, integers, and booleans. +keywords: + [ + Noir programming language, + supported operations, + arithmetic operations, + logical operations, + predicate operators, + bitwise operations, + short-circuiting, + backend, + ] +sidebar_position: 3 +--- + +# Operations + +## Table of Supported Operations + +| Operation | Description | Requirements | +| :-------- | :------------------------------------------------------------: | -------------------------------------: | +| + | Adds two private input types together | Types must be private input | +| - | Subtracts two private input types together | Types must be private input | +| \* | Multiplies two private input types together | Types must be private input | +| / | Divides two private input types together | Types must be private input | +| ^ | XOR two private input types together | Types must be integer | +| & | AND two private input types together | Types must be integer | +| \| | OR two private input types together | Types must be integer | +| \<\< | Left shift an integer by another integer amount | Types must be integer | +| >> | Right shift an integer by another integer amount | Types must be integer | +| ! | Bitwise not of a value | Type must be integer or boolean | +| \< | returns a bool if one value is less than the other | Upper bound must have a known bit size | +| \<= | returns a bool if one value is less than or equal to the other | Upper bound must have a known bit size | +| > | returns a bool if one value is more than the other | Upper bound must have a known bit size | +| >= | returns a bool if one value is more than or equal to the other | Upper bound must have a known bit size | +| == | returns a bool if one value is equal to the other | Both types must not be constants | +| != | returns a bool if one value is not equal to the other | Both types must not be constants | + +### Predicate Operators + +`<,<=, !=, == , >, >=` are known as predicate/comparison operations because they compare two values. +This differs from the operations such as `+` where the operands are used in _computation_. + +### Bitwise Operations Example + +```rust +fn main(x : Field) { + let y = x as u32; + let z = y & y; +} +``` + +`z` is implicitly constrained to be the result of `y & y`. The `&` operand is used to denote bitwise +`&`. + +> `x & x` would not compile as `x` is a `Field` and not an integer type. + +### Logical Operators + +Noir has no support for the logical operators `||` and `&&`. This is because encoding the +short-circuiting that these operators require can be inefficient for Noir's backend. Instead you can +use the bitwise operators `|` and `&` which operate identically for booleans, just without the +short-circuiting. + +```rust +let my_val = 5; + +let mut flag = 1; +if (my_val > 6) | (my_val == 0) { + flag = 0; +} +assert(flag == 1); + +if (my_val != 10) & (my_val < 50) { + flag = 0; +} +assert(flag == 0); +``` + +### Shorthand operators + +Noir shorthand operators for most of the above operators, namely `+=, -=, *=, /=, %=, &=, |=, ^=, <<=`, and `>>=`. These allow for more concise syntax. For example: + +```rust +let mut i = 0; +i = i + 1; +``` + +could be written as: + +```rust +let mut i = 0; +i += 1; +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md new file mode 100644 index 00000000000..2e6a6818d48 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md @@ -0,0 +1,23 @@ +--- +title: Oracles +description: Dive into how Noir supports Oracles via RPC calls, and learn how to declare an Oracle in Noir with our comprehensive guide. +keywords: + - Noir + - Oracles + - RPC Calls + - Unconstrained Functions + - Programming + - Blockchain +sidebar_position: 6 +--- + +Noir has support for Oracles via RPC calls. This means Noir will make an RPC call and use the return value for proof generation. + +Since Oracles are not resolved by Noir, they are [`unconstrained` functions](./unconstrained.md) + +You can declare an Oracle through the `#[oracle()]` flag. Example: + +```rust +#[oracle(get_number_sequence)] +unconstrained fn get_number_sequence(_size: Field) -> [Field] {} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md new file mode 100644 index 00000000000..5ce6130d201 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md @@ -0,0 +1,44 @@ +--- +title: Shadowing +sidebar_position: 12 +--- + +Noir allows for inheriting variables' values and re-declaring them with the same name similar to Rust, known as shadowing. + +For example, the following function is valid in Noir: + +```rust +fn main() { + let x = 5; + + { + let x = x * 2; + assert (x == 10); + } + + assert (x == 5); +} +``` + +In this example, a variable x is first defined with the value 5. + +The local scope that follows shadows the original x, i.e. creates a local mutable x based on the value of the original x. It is given a value of 2 times the original x. + +When we return to the main scope, x once again refers to just the original x, which stays at the value of 5. + +## Temporal mutability + +One way that shadowing is useful, in addition to ergonomics across scopes, is for temporarily mutating variables. + +```rust +fn main() { + let age = 30; + // age = age + 5; // Would error as `age` is immutable by default. + + let mut age = age + 5; // Temporarily mutates `age` with a new value. + + let age = age; // Locks `age`'s mutability again. + + assert (age == 35); +} +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md new file mode 100644 index 00000000000..ef1445a5907 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md @@ -0,0 +1,389 @@ +--- +title: Traits +description: + Traits in Noir can be used to abstract out a common interface for functions across + several data types. +keywords: [noir programming language, traits, interfaces, generic, protocol] +sidebar_position: 14 +--- + +## Overview + +Traits in Noir are a useful abstraction similar to interfaces or protocols in other languages. Each trait defines +the interface of several methods contained within the trait. Types can then implement this trait by providing +implementations for these methods. For example in the program: + +```rust +struct Rectangle { + width: Field, + height: Field, +} + +impl Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +fn log_area(r: Rectangle) { + println(r.area()); +} +``` + +We have a function `log_area` to log the area of a `Rectangle`. Now how should we change the program if we want this +function to work on `Triangle`s as well?: + +```rust +struct Triangle { + width: Field, + height: Field, +} + +impl Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Making `log_area` generic over all types `T` would be invalid since not all types have an `area` method. Instead, we can +introduce a new `Area` trait and make `log_area` generic over all types `T` that implement `Area`: + +```rust +trait Area { + fn area(self) -> Field; +} + +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +We also need to explicitly implement `Area` for `Rectangle` and `Triangle`. We can do that by changing their existing +impls slightly. Note that the parameter types and return type of each of our `area` methods must match those defined +by the `Area` trait. + +```rust +impl Area for Rectangle { + fn area(self) -> Field { + self.width * self.height + } +} + +impl Area for Triangle { + fn area(self) -> Field { + self.width * self.height / 2 + } +} +``` + +Now we have a working program that is generic over any type of Shape that is used! Others can even use this program +as a library with their own types - such as `Circle` - as long as they also implement `Area` for these types. + +## Where Clauses + +As seen in `log_area` above, when we want to create a function or method that is generic over any type that implements +a trait, we can add a where clause to the generic function. + +```rust +fn log_area(shape: T) where T: Area { + println(shape.area()); +} +``` + +It is also possible to apply multiple trait constraints on the same variable at once by combining traits with the `+` +operator. Similarly, we can have multiple trait constraints by separating each with a comma: + +```rust +fn foo(elements: [T], thing: U) where + T: Default + Add + Eq, + U: Bar, +{ + let mut sum = T::default(); + + for element in elements { + sum += element; + } + + if sum == T::default() { + thing.bar(); + } +} +``` + +## Generic Implementations + +You can add generics to a trait implementation by adding the generic list after the `impl` keyword: + +```rust +trait Second { + fn second(self) -> Field; +} + +impl Second for (T, Field) { + fn second(self) -> Field { + self.1 + } +} +``` + +You can also implement a trait for every type this way: + +```rust +trait Debug { + fn debug(self); +} + +impl Debug for T { + fn debug(self) { + println(self); + } +} + +fn main() { + 1.debug(); +} +``` + +### Generic Trait Implementations With Where Clauses + +Where clauses can also be placed on trait implementations themselves to restrict generics in a similar way. +For example, while `impl Foo for T` implements the trait `Foo` for every type, `impl Foo for T where T: Bar` +will implement `Foo` only for types that also implement `Bar`. This is often used for implementing generic types. +For example, here is the implementation for array equality: + +```rust +impl Eq for [T; N] where T: Eq { + // Test if two arrays have the same elements. + // Because both arrays must have length N, we know their lengths already match. + fn eq(self, other: Self) -> bool { + let mut result = true; + + for i in 0 .. self.len() { + // The T: Eq constraint is needed to call == on the array elements here + result &= self[i] == other[i]; + } + + result + } +} +``` + +## Generic Traits + +Traits themselves can also be generic by placing the generic arguments after the trait name. These generics are in +scope of every item within the trait. + +```rust +trait Into { + // Convert `self` to type `T` + fn into(self) -> T; +} +``` + +When implementing generic traits the generic arguments of the trait must be specified. This is also true anytime +when referencing a generic trait (e.g. in a `where` clause). + +```rust +struct MyStruct { + array: [Field; 2], +} + +impl Into<[Field; 2]> for MyStruct { + fn into(self) -> [Field; 2] { + self.array + } +} + +fn as_array(x: T) -> [Field; 2] + where T: Into<[Field; 2]> +{ + x.into() +} + +fn main() { + let array = [1, 2]; + let my_struct = MyStruct { array }; + + assert_eq(as_array(my_struct), array); +} +``` + +## Trait Methods With No `self` + +A trait can contain any number of methods, each of which have access to the `Self` type which represents each type +that eventually implements the trait. Similarly, the `self` variable is available as well but is not required to be used. +For example, we can define a trait to create a default value for a type. This trait will need to return the `Self` type +but doesn't need to take any parameters: + +```rust +trait Default { + fn default() -> Self; +} +``` + +Implementing this trait can be done similarly to any other trait: + +```rust +impl Default for Field { + fn default() -> Field { + 0 + } +} + +struct MyType {} + +impl Default for MyType { + fn default() -> Field { + MyType {} + } +} +``` + +However, since there is no `self` parameter, we cannot call it via the method call syntax `object.method()`. +Instead, we'll need to refer to the function directly. This can be done either by referring to the +specific impl `MyType::default()` or referring to the trait itself `Default::default()`. In the later +case, type inference determines the impl that is selected. + +```rust +let my_struct = MyStruct::default(); + +let x: Field = Default::default(); +let result = x + Default::default(); +``` + +:::warning + +```rust +let _ = Default::default(); +``` + +If type inference cannot select which impl to use because of an ambiguous `Self` type, an impl will be +arbitrarily selected. This occurs most often when the result of a trait function call with no parameters +is unused. To avoid this, when calling a trait function with no `self` or `Self` parameters or return type, +always refer to it via the implementation type's namespace - e.g. `MyType::default()`. +This is set to change to an error in future Noir versions. + +::: + +## Default Method Implementations + +A trait can also have default implementations of its methods by giving a body to the desired functions. +Note that this body must be valid for all types that may implement the trait. As a result, the only +valid operations on `self` will be operations valid for any type or other operations on the trait itself. + +```rust +trait Numeric { + fn add(self, other: Self) -> Self; + + // Default implementation of double is (self + self) + fn double(self) -> Self { + self.add(self) + } +} +``` + +When implementing a trait with default functions, a type may choose to implement only the required functions: + +```rust +impl Numeric for Field { + fn add(self, other: Field) -> Field { + self + other + } +} +``` + +Or it may implement the optional methods as well: + +```rust +impl Numeric for u32 { + fn add(self, other: u32) -> u32 { + self + other + } + + fn double(self) -> u32 { + self * 2 + } +} +``` + +## Impl Specialization + +When implementing traits for a generic type it is possible to implement the trait for only a certain combination +of generics. This can be either as an optimization or because those specific generics are required to implement the trait. + +```rust +trait Sub { + fn sub(self, other: Self) -> Self; +} + +struct NonZero { + value: T, +} + +impl Sub for NonZero { + fn sub(self, other: Self) -> Self { + let value = self.value - other.value; + assert(value != 0); + NonZero { value } + } +} +``` + +## Overlapping Implementations + +Overlapping implementations are disallowed by Noir to ensure Noir's decision on which impl to select is never ambiguous. +This means if a trait `Foo` is already implemented +by a type `Bar` for all `T`, then we cannot also have a separate impl for `Bar` (or any other +type argument). Similarly, if there is an impl for all `T` such as `impl Debug for T`, we cannot create +any more impls to `Debug` for other types since it would be ambiguous which impl to choose for any given +method call. + +```rust +trait Trait {} + +// Previous impl defined here +impl Trait for (A, B) {} + +// error: Impl for type `(Field, Field)` overlaps with existing impl +impl Trait for (Field, Field) {} +``` + +## Trait Coherence + +Another restriction on trait implementations is coherence. This restriction ensures other crates cannot create +impls that may overlap with other impls, even if several unrelated crates are used as dependencies in the same +program. + +The coherence restriction is: to implement a trait, either the trait itself or the object type must be declared +in the crate the impl is in. + +In practice this often comes up when using types provided by libraries. If a library provides a type `Foo` that does +not implement a trait in the standard library such as `Default`, you may not `impl Default for Foo` in your own crate. +While restrictive, this prevents later issues or silent changes in the program if the `Foo` library later added its +own impl for `Default`. If you are a user of the `Foo` library in this scenario and need a trait not implemented by the +library your choices are to either submit a patch to the library or use the newtype pattern. + +### The Newtype Pattern + +The newtype pattern gets around the coherence restriction by creating a new wrapper type around the library type +that we cannot create `impl`s for. Since the new wrapper type is defined in our current crate, we can create +impls for any trait we need on it. + +```rust +struct Wrapper { + foo: dep::some_library::Foo, +} + +impl Default for Wrapper { + fn default() -> Wrapper { + Wrapper { + foo: dep::some_library::Foo::new(), + } + } +} +``` + +Since we have an impl for our own type, the behavior of this code will not change even if `some_library` is updated +to provide its own `impl Default for Foo`. The downside of this pattern is that it requires extra wrapping and +unwrapping of values when converting to and from the `Wrapper` and `Foo` types. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md new file mode 100644 index 00000000000..6b3424f7993 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md @@ -0,0 +1,95 @@ +--- +title: Unconstrained Functions +description: "Learn about what unconstrained functions in Noir are, how to use them and when you'd want to." + +keywords: [Noir programming language, unconstrained, open] +sidebar_position: 5 +--- + +Unconstrained functions are functions which do not constrain any of the included computation and allow for non-deterministic computation. + +## Why? + +Zero-knowledge (ZK) domain-specific languages (DSL) enable developers to generate ZK proofs from their programs by compiling code down to the constraints of an NP complete language (such as R1CS or PLONKish languages). However, the hard bounds of a constraint system can be very limiting to the functionality of a ZK DSL. + +Enabling a circuit language to perform unconstrained execution is a powerful tool. Said another way, unconstrained execution lets developers generate witnesses from code that does not generate any constraints. Being able to execute logic outside of a circuit is critical for both circuit performance and constructing proofs on information that is external to a circuit. + +Fetching information from somewhere external to a circuit can also be used to enable developers to improve circuit efficiency. + +A ZK DSL does not just prove computation, but proves that some computation was handled correctly. Thus, it is necessary that when we switch from performing some operation directly inside of a circuit to inside of an unconstrained environment that the appropriate constraints are still laid down elsewhere in the circuit. + +## Example + +An in depth example might help drive the point home. This example comes from the excellent [post](https://discord.com/channels/1113924620781883405/1124022445054111926/1128747641853972590) by Tom in the Noir Discord. + +Let's look at how we can optimize a function to turn a `u72` into an array of `u8`s. + +```rust +fn main(num: u72) -> pub [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8)) as u72 & 0xff) as u8; + } + + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 91 +Backend circuit size: 3619 +``` + +A lot of the operations in this function are optimized away by the compiler (all the bit-shifts turn into divisions by constants). However we can save a bunch of gates by casting to u8 a bit earlier. This automatically truncates the bit-shifted value to fit in a u8 which allows us to remove the XOR against 0xff. This saves us ~480 gates in total. + +```rust +fn main(num: u72) -> pub [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8)) as u8; + } + + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 75 +Backend circuit size: 3143 +``` + +Those are some nice savings already but we can do better. This code is all constrained so we're proving every step of calculating out using num, but we don't actually care about how we calculate this, just that it's correct. This is where brillig comes in. + +It turns out that truncating a u72 into a u8 is hard to do inside a snark, each time we do as u8 we lay down 4 ACIR opcodes which get converted into multiple gates. It's actually much easier to calculate num from out than the other way around. All we need to do is multiply each element of out by a constant and add them all together, both relatively easy operations inside a snark. + +We can then run u72_to_u8 as unconstrained brillig code in order to calculate out, then use that result in our constrained function and assert that if we were to do the reverse calculation we'd get back num. This looks a little like the below: + +```rust +fn main(num: u72) -> pub [u8; 8] { + let out = u72_to_u8(num); + + let mut reconstructed_num: u72 = 0; + for i in 0..8 { + reconstructed_num += (out[i] as u72 << (56 - (8 * i))); + } + assert(num == reconstructed_num); + out +} + +unconstrained fn u72_to_u8(num: u72) -> [u8; 8] { + let mut out: [u8; 8] = [0; 8]; + for i in 0..8 { + out[i] = (num >> (56 - (i * 8))) as u8; + } + out +} +``` + +``` +Total ACIR opcodes generated for language PLONKCSat { width: 3 }: 78 +Backend circuit size: 2902 +``` + +This ends up taking off another ~250 gates from our circuit! We've ended up with more ACIR opcodes than before but they're easier for the backend to prove (resulting in fewer gates). + +Generally we want to use brillig whenever there's something that's easy to verify but hard to compute within the circuit. For example, if you wanted to calculate a square root of a number it'll be a much better idea to calculate this in brillig and then assert that if you square the result you get back your number. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json new file mode 100644 index 00000000000..1debcfe7675 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Modules, Packages and Crates", + "position": 2, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md new file mode 100644 index 00000000000..760a463094c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md @@ -0,0 +1,43 @@ +--- +title: Crates and Packages +description: Learn how to use Crates and Packages in your Noir project +keywords: [Nargo, dependencies, package management, crates, package] +sidebar_position: 0 +--- + +## Crates + +A crate is the smallest amount of code that the Noir compiler considers at a time. +Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as we’ll see in the coming sections. + +### Crate Types + +A Noir crate can come in several forms: binaries, libraries or contracts. + +#### Binaries + +_Binary crates_ are programs which you can compile to an ACIR circuit which you can then create proofs against. Each must have a function called `main` that defines the ACIR circuit which is to be proved. + +#### Libraries + +_Library crates_ don't have a `main` function and they don't compile down to ACIR. Instead they define functionality intended to be shared with multiple projects, and eventually included in a binary crate. + +#### Contracts + +Contract crates are similar to binary crates in that they compile to ACIR which you can create proofs against. They are different in that they do not have a single `main` function, but are a collection of functions to be deployed to the [Aztec network](https://aztec.network). You can learn more about the technical details of Aztec in the [monorepo](https://github.com/AztecProtocol/aztec-packages) or contract [examples](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts). + +### Crate Root + +Every crate has a root, which is the source file that the compiler starts, this is also known as the root module. The Noir compiler does not enforce any conditions on the name of the file which is the crate root, however if you are compiling via Nargo the crate root must be called `lib.nr` or `main.nr` for library or binary crates respectively. + +## Packages + +A Nargo _package_ is a collection of one of more crates that provides a set of functionality. A package must include a Nargo.toml file. + +A package _must_ contain either a library or a binary crate, but not both. + +### Differences from Cargo Packages + +One notable difference between Rust's Cargo and Noir's Nargo is that while Cargo allows a package to contain an unlimited number of binary crates and a single library crate, Nargo currently only allows a package to contain a single crate. + +In future this restriction may be lifted to allow a Nargo package to contain both a binary and library crate or multiple binary crates. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md new file mode 100644 index 00000000000..a37dc401b7d --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md @@ -0,0 +1,124 @@ +--- +title: Dependencies +description: + Learn how to specify and manage dependencies in Nargo, allowing you to upload packages to GitHub + and use them easily in your project. +keywords: [Nargo, dependencies, GitHub, package management, versioning] +sidebar_position: 1 +--- + +Nargo allows you to upload packages to GitHub and use them as dependencies. + +## Specifying a dependency + +Specifying a dependency requires a tag to a specific commit and the git url to the url containing +the package. + +Currently, there are no requirements on the tag contents. If requirements are added, it would follow +semver 2.0 guidelines. + +> Note: Without a `tag` , there would be no versioning and dependencies would change each time you +> compile your project. + +For example, to add the [ecrecover-noir library](https://github.com/colinnielsen/ecrecover-noir) to your project, add it to `Nargo.toml`: + +```toml +# Nargo.toml + +[dependencies] +ecrecover = {tag = "v0.8.0", git = "https://github.com/colinnielsen/ecrecover-noir"} +``` + +If the module is in a subdirectory, you can define a subdirectory in your git repository, for example: + +```toml +# Nargo.toml + +[dependencies] +easy_private_token_contract = {tag ="v0.1.0-alpha62", git = "https://github.com/AztecProtocol/aztec-packages", directory = "yarn-project/noir-contracts/contracts/easy_private_token_contract"} +``` + +## Specifying a local dependency + +You can also specify dependencies that are local to your machine. + +For example, this file structure has a library and binary crate + +```tree +├── binary_crate +│   ├── Nargo.toml +│   └── src +│   └── main.nr +└── lib_a + ├── Nargo.toml + └── src + └── lib.nr +``` + +Inside of the binary crate, you can specify: + +```toml +# Nargo.toml + +[dependencies] +lib_a = { path = "../lib_a" } +``` + +## Importing dependencies + +You can import a dependency to a Noir file using the following syntax. For example, to import the +ecrecover-noir library and local lib_a referenced above: + +```rust +use dep::ecrecover; +use dep::lib_a; +``` + +You can also import only the specific parts of dependency that you want to use, like so: + +```rust +use dep::std::hash::sha256; +use dep::std::scalar_mul::fixed_base_embedded_curve; +``` + +Lastly, as demonstrated in the +[elliptic curve example](../standard_library/cryptographic_primitives/ec_primitives#examples), you +can import multiple items in the same line by enclosing them in curly braces: + +```rust +use dep::std::ec::tecurve::affine::{Curve, Point}; +``` + +We don't have a way to consume libraries from inside a [workspace](./workspaces) as external dependencies right now. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +## Dependencies of Dependencies + +Note that when you import a dependency, you also get access to all of the dependencies of that package. + +For example, the [phy_vector](https://github.com/resurgencelabs/phy_vector) library imports an [fraction](https://github.com/resurgencelabs/fraction) library. If you're importing the phy_vector library, then you can access the functions in fractions library like so: + +```rust +use dep::phy_vector; + +fn main(x : Field, y : pub Field) { + //... + let f = phy_vector::fraction::toFraction(true, 2, 1); + //... +} +``` + +## Available Libraries + +Noir does not currently have an official package manager. You can find a list of available Noir libraries in the [awesome-noir repo here](https://github.com/noir-lang/awesome-noir#libraries). + +Some libraries that are available today include: + +- [Standard Library](https://github.com/noir-lang/noir/tree/master/noir_stdlib) - the Noir Standard Library +- [Ethereum Storage Proof Verification](https://github.com/aragonzkresearch/noir-trie-proofs) - a library that contains the primitives necessary for RLP decoding (in the form of look-up table construction) and Ethereum state and storage proof verification (or verification of any trie proof involving 32-byte long keys) +- [BigInt](https://github.com/shuklaayush/noir-bigint) - a library that provides a custom BigUint56 data type, allowing for computations on large unsigned integers +- [ECrecover](https://github.com/colinnielsen/ecrecover-noir/tree/main) - a library to verify an ECDSA signature and return the source Ethereum address +- [Sparse Merkle Tree Verifier](https://github.com/vocdoni/smtverifier-noir/tree/main) - a library for verification of sparse Merkle trees +- [Signed Int](https://github.com/resurgencelabs/signed_int) - a library for accessing a custom Signed Integer data type, allowing access to negative numbers on Noir +- [Fraction](https://github.com/resurgencelabs/fraction) - a library for accessing fractional number data type in Noir, allowing results that aren't whole numbers diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md new file mode 100644 index 00000000000..ae822a1cff4 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md @@ -0,0 +1,105 @@ +--- +title: Modules +description: + Learn how to organize your files using modules in Noir, following the same convention as Rust's + module system. Examples included. +keywords: [Noir, Rust, modules, organizing files, sub-modules] +sidebar_position: 2 +--- + +Noir's module system follows the same convention as the _newer_ version of Rust's module system. + +## Purpose of Modules + +Modules are used to organize files. Without modules all of your code would need to live in a single +file. In Noir, the compiler does not automatically scan all of your files to detect modules. This +must be done explicitly by the developer. + +## Examples + +### Importing a module in the crate root + +Filename : `src/main.nr` + +```rust +mod foo; + +fn main() { + foo::hello_world(); +} +``` + +Filename : `src/foo.nr` + +```rust +fn from_foo() {} +``` + +In the above snippet, the crate root is the `src/main.nr` file. The compiler sees the module +declaration `mod foo` which prompts it to look for a foo.nr file. + +Visually this module hierarchy looks like the following : + +``` +crate + ├── main + │ + └── foo + └── from_foo + +``` + +### Importing a module throughout the tree + +All modules are accessible from the `crate::` namespace. + +``` +crate + ├── bar + ├── foo + └── main + +``` + +In the above snippet, if `bar` would like to use functions in `foo`, it can do so by `use crate::foo::function_name`. + +### Sub-modules + +Filename : `src/main.nr` + +```rust +mod foo; + +fn main() { + foo::from_foo(); +} +``` + +Filename : `src/foo.nr` + +```rust +mod bar; +fn from_foo() {} +``` + +Filename : `src/foo/bar.nr` + +```rust +fn from_bar() {} +``` + +In the above snippet, we have added an extra module to the module tree; `bar`. `bar` is a submodule +of `foo` hence we declare bar in `foo.nr` with `mod bar`. Since `foo` is not the crate root, the +compiler looks for the file associated with the `bar` module in `src/foo/bar.nr` + +Visually the module hierarchy looks as follows: + +``` +crate + ├── main + │ + └── foo + ├── from_foo + └── bar + └── from_bar +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md new file mode 100644 index 00000000000..67a1dafa372 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md @@ -0,0 +1,40 @@ +--- +title: Workspaces +sidebar_position: 3 +--- + +Workspaces are a feature of nargo that allow you to manage multiple related Noir packages in a single repository. A workspace is essentially a group of related projects that share common build output directories and configurations. + +Each Noir project (with it's own Nargo.toml file) can be thought of as a package. Each package is expected to contain exactly one "named circuit", being the "name" defined in Nargo.toml with the program logic defined in `./src/main.nr`. + +For a project with the following structure: + +```tree +├── crates +│   ├── a +│   │   ├── Nargo.toml +│   │   └── src +│   │   └── main.nr +│   └── b +│   ├── Nargo.toml +│   └── src +│   └── main.nr +├── Nargo.toml +└── Prover.toml +``` + +You can define a workspace in Nargo.toml like so: + +```toml +[workspace] +members = ["crates/a", "crates/b"] +default-member = "crates/a" +``` + +`members` indicates which packages are included in the workspace. As such, all member packages of a workspace will be processed when the `--workspace` flag is used with various commands or if a `default-member` is not specified. + +`default-member` indicates which package various commands process by default. + +Libraries can be defined in a workspace. Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. + +Inside a workspace, these are consumed as `{ path = "../to_lib" }` dependencies in Nargo.toml. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json new file mode 100644 index 00000000000..af04c0933fd --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Standard Library", + "position": 1, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md new file mode 100644 index 00000000000..4b1efbd17de --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md @@ -0,0 +1,45 @@ +--- +title: Black Box Functions +description: Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. +keywords: [noir, black box functions] +--- + +Black box functions are functions in Noir that rely on backends implementing support for specialized constraints. This makes certain zk-snark unfriendly computations cheaper than if they were implemented in Noir. + +:::warning + +It is likely that not all backends will support a particular black box function. + +::: + +Because it is not guaranteed that all backends will support black box functions, it is possible that certain Noir programs won't compile against a particular backend if they use an unsupported black box function. It is possible to fallback to less efficient implementations written in Noir/ACIR in some cases. + +Black box functions are specified with the `#[foreign(black_box_fn)]` attribute. For example, the SHA256 function in the Noir [source code](https://github.com/noir-lang/noir/blob/v0.5.1/noir_stdlib/src/hash.nr) looks like: + +```rust +#[foreign(sha256)] +fn sha256(_input : [u8; N]) -> [u8; 32] {} +``` + +## Function list + +Here is a list of the current black box functions that are supported by UltraPlonk: + +- AES +- [SHA256](./cryptographic_primitives/hashes#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr) +- [Blake2s](./cryptographic_primitives/hashes#blake2s) +- [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [Compute merkle root](./merkle_trees#compute_merkle_root) +- AND +- XOR +- RANGE +- [Keccak256](./cryptographic_primitives/hashes#keccak256) +- [Recursive proof verification](./recursion) + +Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. To ensure compatibility across backends, the ACVM has fallback implementations of `AND`, `XOR` and `RANGE` defined in its standard library which it can seamlessly fallback to if the backend doesn't support them. + +You can view the black box functions defined in the ACVM code [here](https://github.com/noir-lang/noir/blob/master/acvm-repo/acir/src/circuit/black_box_functions.rs). diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json new file mode 100644 index 00000000000..5d694210bbf --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md new file mode 100644 index 00000000000..d2b42d67b7c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md @@ -0,0 +1,102 @@ +--- +title: Elliptic Curve Primitives +keywords: [cryptographic primitives, Noir project] +sidebar_position: 4 +--- + +Data structures and methods on them that allow you to carry out computations involving elliptic +curves over the (mathematical) field corresponding to `Field`. For the field currently at our +disposal, applications would involve a curve embedded in BN254, e.g. the +[Baby Jubjub curve](https://eips.ethereum.org/EIPS/eip-2494). + +## Data structures + +### Elliptic curve configurations + +(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Curve`), i.e. the specific elliptic +curve you want to use, which would be specified using any one of the methods +`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::new` which take the coefficients in the +defining equation together with a generator point as parameters. You can find more detail in the +comments in +[`noir_stdlib/src/ec.nr`](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr), but +the gist of it is that the elliptic curves of interest are usually expressed in one of the standard +forms implemented here (Twisted Edwards, Montgomery and Short Weierstraß), and in addition to that, +you could choose to use `affine` coordinates (Cartesian coordinates - the usual (x,y) - possibly +together with a point at infinity) or `curvegroup` coordinates (some form of projective coordinates +requiring more coordinates but allowing for more efficient implementations of elliptic curve +operations). Conversions between all of these forms are provided, and under the hood these +conversions are done whenever an operation is more efficient in a different representation (or a +mixed coordinate representation is employed). + +### Points + +(`std::ec::{tecurve,montcurve,swcurve}::{affine,curvegroup}::Point`), i.e. points lying on the +elliptic curve. For a curve configuration `c` and a point `p`, it may be checked that `p` +does indeed lie on `c` by calling `c.contains(p1)`. + +## Methods + +(given a choice of curve representation, e.g. use `std::ec::tecurve::affine::Curve` and use +`std::ec::tecurve::affine::Point`) + +- The **zero element** is given by `Point::zero()`, and we can verify whether a point `p: Point` is + zero by calling `p.is_zero()`. +- **Equality**: Points `p1: Point` and `p2: Point` may be checked for equality by calling + `p1.eq(p2)`. +- **Addition**: For `c: Curve` and points `p1: Point` and `p2: Point` on the curve, adding these two + points is accomplished by calling `c.add(p1,p2)`. +- **Negation**: For a point `p: Point`, `p.negate()` is its negation. +- **Subtraction**: For `c` and `p1`, `p2` as above, subtracting `p2` from `p1` is accomplished by + calling `c.subtract(p1,p2)`. +- **Scalar multiplication**: For `c` as above, `p: Point` a point on the curve and `n: Field`, + scalar multiplication is given by `c.mul(n,p)`. If instead `n :: [u1; N]`, i.e. `n` is a bit + array, the `bit_mul` method may be used instead: `c.bit_mul(n,p)` +- **Multi-scalar multiplication**: For `c` as above and arrays `n: [Field; N]` and `p: [Point; N]`, + multi-scalar multiplication is given by `c.msm(n,p)`. +- **Coordinate representation conversions**: The `into_group` method converts a point or curve + configuration in the affine representation to one in the CurveGroup representation, and + `into_affine` goes in the other direction. +- **Curve representation conversions**: `tecurve` and `montcurve` curves and points are equivalent + and may be converted between one another by calling `into_montcurve` or `into_tecurve` on their + configurations or points. `swcurve` is more general and a curve c of one of the other two types + may be converted to this representation by calling `c.into_swcurve()`, whereas a point `p` lying + on the curve given by `c` may be mapped to its corresponding `swcurve` point by calling + `c.map_into_swcurve(p)`. +- **Map-to-curve methods**: The Elligator 2 method of mapping a field element `n: Field` into a + `tecurve` or `montcurve` with configuration `c` may be called as `c.elligator2_map(n)`. For all of + the curve configurations, the SWU map-to-curve method may be called as `c.swu_map(z,n)`, where + `z: Field` depends on `Field` and `c` and must be chosen by the user (the conditions it needs to + satisfy are specified in the comments + [here](https://github.com/noir-lang/noir/blob/master/noir_stdlib/src/ec.nr)). + +## Examples + +The +[ec_baby_jubjub test](https://github.com/noir-lang/noir/blob/master/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr) +illustrates all of the above primitives on various forms of the Baby Jubjub curve. A couple of more +interesting examples in Noir would be: + +Public-key cryptography: Given an elliptic curve and a 'base point' on it, determine the public key +from the private key. This is a matter of using scalar multiplication. In the case of Baby Jubjub, +for example, this code would do: + +```rust +use dep::std::ec::tecurve::affine::{Curve, Point}; + +fn bjj_pub_key(priv_key: Field) -> Point +{ + + let bjj = Curve::new(168700, 168696, G::new(995203441582195749578291179787384436505546430278305826713579947235728471134,5472060717959818805561601436314318772137091100104008585924551046643952123905)); + + let base_pt = Point::new(5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203); + + bjj.mul(priv_key,base_pt) +} +``` + +This would come in handy in a Merkle proof. + +- EdDSA signature verification: This is a matter of combining these primitives with a suitable hash + function. See + [feat(stdlib): EdDSA sig verification noir#1136](https://github.com/noir-lang/noir/pull/1136) for + the case of Baby Jubjub and the Poseidon hash function. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx new file mode 100644 index 00000000000..1376c51dfde --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx @@ -0,0 +1,46 @@ +--- +title: ECDSA Signature Verification +description: Learn about the cryptographic primitives regarding ECDSA over the secp256k1 and secp256r1 curves +keywords: [cryptographic primitives, Noir project, ecdsa, secp256k1, secp256r1, signatures] +sidebar_position: 3 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +Noir supports ECDSA signatures verification over the secp256k1 and secp256r1 curves. + +## ecdsa_secp256k1::verify_signature + +Verifier for ECDSA Secp256k1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +example: + +```rust +fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], signature : [u8;64]) { + let valid_signature = std::ecdsa_secp256k1::verify_signature(pub_key_x, pub_key_y, signature, hashed_message); + assert(valid_signature); +} +``` + +## ecdsa_secp256r1::verify_signature + +Verifier for ECDSA Secp256r1 signatures + +```rust +fn verify_signature(_public_key_x : [u8; 32], _public_key_y : [u8; 32], _signature: [u8; 64], _message: [u8]) -> bool +``` + +example: + +```rust +fn main(hashed_message : [u8;32], pub_key_x : [u8;32], pub_key_y : [u8;32], signature : [u8;64]) { + let valid_signature = std::ecdsa_secp256r1::verify_signature(pub_key_x, pub_key_y, signature, hashed_message); + assert(valid_signature); +} +``` + + diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx new file mode 100644 index 00000000000..a9c10da6c06 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx @@ -0,0 +1,18 @@ +--- +title: EdDSA Verification +description: Learn about the cryptographic primitives regarding EdDSA +keywords: [cryptographic primitives, Noir project, eddsa, signatures] +sidebar_position: 5 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## eddsa::eddsa_poseidon_verify + +Verifier for EdDSA signatures + +```rust +fn eddsa_poseidon_verify(public_key_x : Field, public_key_y : Field, signature_s: Field, signature_r8_x: Field, signature_r8_y: Field, message: Field) -> bool +``` + + diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx new file mode 100644 index 00000000000..3c5f7f79603 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -0,0 +1,167 @@ +--- +title: Hash methods +description: + Learn about the cryptographic primitives ready to use for any Noir project, including sha256, + blake2s, pedersen, mimc_bn254 and mimc +keywords: + [cryptographic primitives, Noir project, sha256, blake2s, pedersen, mimc_bn254, mimc, hash] +sidebar_position: 0 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## sha256 + +Given an array of bytes, returns the resulting sha256 hash. + +```rust +fn sha256(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::sha256(x); +} +``` + + + +## blake2s + +Given an array of bytes, returns an array with the Blake2 hash + +```rust +fn blake2s(_input : [u8]) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::blake2s(x); +} +``` + + + +## pedersen_hash + +Given an array of Fields, returns the Pedersen hash. + +```rust +fn pedersen_hash(_input : [Field]) -> Field +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::pedersen_hash(x); +} +``` + + + + + +## pedersen_commitment + +Given an array of Fields, returns the Pedersen commitment. + +```rust +fn pedersen_commitment(_input : [Field]) -> [Field; 2] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let commitment = std::hash::pedersen_commitment(x); +} +``` + + + +## keccak256 + +Given an array of bytes (`u8`), returns the resulting keccak hash as an array of 32 bytes +(`[u8; 32]`). Specify a message_size to hash only the first `message_size` bytes +of the input. + +```rust +fn keccak256(_input : [u8; N], _message_size: u32) -> [u8; 32] +``` + +example: + +```rust +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let message_size = 4; + let hash = std::hash::keccak256(x, message_size); +} +``` + + + +## poseidon + +Given an array of Fields, returns a new Field with the Poseidon Hash. Mind that you need to specify +how many inputs are there to your Poseidon function. + +```rust +// example for hash_1, hash_2 accepts an array of length 2, etc +fn hash_1(input: [Field; 1]) -> Field +``` + +example: + +```rust +fn main() +{ + let hash_2 = std::hash::poseidon::bn254::hash_2([1, 2]); + assert(hash2 == 0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a); +} +``` + +## mimc_bn254 and mimc + +`mimc_bn254` is `mimc`, but with hardcoded parameters for the BN254 curve. You can use it by +providing an array of Fields, and it returns a Field with the hash. You can use the `mimc` method if +you're willing to input your own constants: + +```rust +fn mimc(x: Field, k: Field, constants: [Field; N], exp : Field) -> Field +``` + +otherwise, use the `mimc_bn254` method: + +```rust +fn mimc_bn254(array: [Field; N]) -> Field +``` + +example: + +```rust + +fn main() { + let x = [163, 117, 178, 149]; // some random bytes + let hash = std::hash::mimc::mimc_bn254(x); +} +``` + +## hash_to_field + +```rust +fn hash_to_field(_input : [Field; N]) -> Field {} +``` + +Calculates the `blake2s` hash of the inputs and returns the hash modulo the field modulus to return +a value which can be represented as a `Field`. + diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md new file mode 100644 index 00000000000..650f30165d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md @@ -0,0 +1,14 @@ +--- +title: Cryptographic Primitives +description: + Learn about the cryptographic primitives ready to use for any Noir project +keywords: + [ + cryptographic primitives, + Noir project, + ] +--- + +The Noir team is progressively adding new cryptographic primitives to the standard library. Reach out for news or if you would be interested in adding more of these calculations in Noir. + +Some methods are available thanks to the Aztec backend, not being performed using Noir. When using other backends, these methods may or may not be supplied. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx new file mode 100644 index 00000000000..aa4fb8cbaed --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx @@ -0,0 +1,28 @@ +--- +title: Scalar multiplication +description: See how you can perform scalar multiplications over a fixed base in Noir +keywords: [cryptographic primitives, Noir project, scalar multiplication] +sidebar_position: 1 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## scalar_mul::fixed_base_embedded_curve + +Performs scalar multiplication over the embedded curve whose coordinates are defined by the +configured noir field. For the BN254 scalar field, this is BabyJubJub or Grumpkin. + +```rust +fn fixed_base_embedded_curve(_input : Field) -> [Field; 2] +``` + +example + +```rust +fn main(x : Field) { + let scal = std::scalar_mul::fixed_base_embedded_curve(x); + println(scal); +} +``` + + diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx new file mode 100644 index 00000000000..7a2c9c20226 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx @@ -0,0 +1,38 @@ +--- +title: Schnorr Signatures +description: Learn how you can verify Schnorr signatures using Noir +keywords: [cryptographic primitives, Noir project, schnorr, signatures] +sidebar_position: 2 +--- + +import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; + +## schnorr::verify_signature + +Verifier for Schnorr signatures over the embedded curve (for BN254 it is Grumpkin). + +```rust +fn verify_signature(_public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8]) -> bool +``` + +where `_signature` can be generated like so using the npm package +[@noir-lang/barretenberg](https://www.npmjs.com/package/@noir-lang/barretenberg) + +```js +const { BarretenbergWasm } = require('@noir-lang/barretenberg/dest/wasm'); +const { Schnorr } = require('@noir-lang/barretenberg/dest/crypto/schnorr'); + +... + +const barretenberg = await BarretenbergWasm.new(); +const schnorr = new Schnorr(barretenberg); +const pubKey = schnorr.computePublicKey(privateKey); +const message = ... +const signature = Array.from( + schnorr.constructSignature(hash, privateKey).toBuffer() +); + +... +``` + + diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md new file mode 100644 index 00000000000..db75ef9f86f --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md @@ -0,0 +1,78 @@ +--- +title: Logging +description: + Learn how to use the println statement for debugging in Noir with this tutorial. Understand the + basics of logging in Noir and how to implement it in your code. +keywords: + [ + noir logging, + println statement, + print statement, + debugging in noir, + noir std library, + logging tutorial, + basic logging in noir, + noir logging implementation, + noir debugging techniques, + rust, + ] +--- + +The standard library provides two familiar statements you can use: `println` and `print`. Despite being a limited implementation of rust's `println!` and `print!` macros, these constructs can be useful for debugging. + +You can print the output of both statements in your Noir code by using the `nargo execute` command or the `--show-output` flag when using `nargo test` (provided there are print statements in your tests). + +It is recommended to use `nargo execute` if you want to debug failing constraints with `println` or `print` statements. This is due to every input in a test being a constant rather than a witness, so we issue an error during compilation while we only print during execution (which comes after compilation). Neither `println`, nor `print` are callable for failed constraints caught at compile time. + +Both `print` and `println` are generic functions which can work on integers, fields, strings, and even structs or expressions. Note however, that slices are currently unsupported. For example: + +```rust +struct Person { + age: Field, + height: Field, +} + +fn main(age: Field, height: Field) { + let person = Person { + age: age, + height: height, + }; + println(person); + println(age + height); + println("Hello world!"); +} +``` + +You can print different types in the same statement (including strings) with a type called `fmtstr`. It can be specified in the same way as a normal string, just prepended with an "f" character: + +```rust + let fmt_str = f"i: {i}, j: {j}"; + println(fmt_str); + + let s = myStruct { y: x, x: y }; + println(s); + + println(f"i: {i}, s: {s}"); + + println(x); + println([x, y]); + + let foo = fooStruct { my_struct: s, foo: 15 }; + println(f"s: {s}, foo: {foo}"); + + println(15); // prints 0x0f, implicit Field + println(-1 as u8); // prints 255 + println(-1 as i8); // prints -1 +``` + +Examples shown above are interchangeable between the two `print` statements: + +```rust +let person = Person { age : age, height : height }; + +println(person); +print(person); + +println("Hello world!"); // Prints with a newline at the end of the input +print("Hello world!"); // Prints the input and keeps cursor on the same line +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md new file mode 100644 index 00000000000..fa488677884 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md @@ -0,0 +1,58 @@ +--- +title: Merkle Trees +description: Learn about Merkle Trees in Noir with this tutorial. Explore the basics of computing a merkle root using a proof, with examples. +keywords: + [ + Merkle trees in Noir, + Noir programming language, + check membership, + computing root from leaf, + Noir Merkle tree implementation, + Merkle tree tutorial, + Merkle tree code examples, + Noir libraries, + pedersen hash., + ] +--- + +## compute_merkle_root + +Returns the root of the tree from the provided leaf and its hash path, using a [Pedersen hash](./cryptographic_primitives/hashes.mdx#pedersen_hash). + +```rust +fn compute_merkle_root(leaf : Field, index : Field, hash_path: [Field]) -> Field +``` + +example: + +```rust +/** + // these values are for this example only + index = "0" + priv_key = "0x000000000000000000000000000000000000000000000000000000616c696365" + secret = "0x1929ea3ab8d9106a899386883d9428f8256cfedb3c4f6b66bf4aa4d28a79988f" + note_hash_path = [ + "0x1e61bdae0f027b1b2159e1f9d3f8d00fa668a952dddd822fda80dc745d6f65cc", + "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", + "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" + ] + */ +fn main(index: Field, priv_key: Field, secret: Field, note_hash_path: [Field; 3]) { + + let pubkey = std::scalar_mul::fixed_base_embedded_curve(priv_key); + let pubkey_x = pubkey[0]; + let pubkey_y = pubkey[1]; + let note_commitment = std::hash::pedersen([pubkey_x, pubkey_y, secret]); + + let root = std::merkle::compute_merkle_root(note_commitment[0], index, note_hash_path); + println(root); +} +``` + +To check merkle tree membership: + +1. Include a merkle root as a program input. +2. Compute the merkle root of a given leaf, index and hash path. +3. Assert the merkle roots are equal. + +For more info about merkle trees, see the Wikipedia [page](https://en.wikipedia.org/wiki/Merkle_tree). diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md new file mode 100644 index 00000000000..970c9cfbf11 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md @@ -0,0 +1,97 @@ +--- +title: Option Type +--- + +The `Option` type is a way to express that a value might be present (`Some(T))` or absent (`None`). It's a safer way to handle potential absence of values, compared to using nulls in many other languages. + +```rust +struct Option { + None, + Some(T), +} +``` + +The `Option` type, already imported into your Noir program, can be used directly: + +```rust +fn main() { + let none = Option::none(); + let some = Option::some(3); +} +``` + +See [this test](https://github.com/noir-lang/noir/blob/5cbfb9c4a06c8865c98ff2b594464b037d821a5c/crates/nargo_cli/tests/test_data/option/src/main.nr) for a more comprehensive set of examples of each of the methods described below. + +## Methods + +### none + +Constructs a none value. + +### some + +Constructs a some wrapper around a given value. + +### is_none + +Returns true if the Option is None. + +### is_some + +Returns true of the Option is Some. + +### unwrap + +Asserts `self.is_some()` and returns the wrapped value. + +### unwrap_unchecked + +Returns the inner value without asserting `self.is_some()`. This method can be useful within an if condition when we already know that `option.is_some()`. If the option is None, there is no guarantee what value will be returned, only that it will be of type T for an `Option`. + +### unwrap_or + +Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value. + +### unwrap_or_else + +Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return a default value. + +### map + +If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`. + +### map_or + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value. + +### map_or_else + +If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`. + +### and + +Returns None if self is None. Otherwise, this returns `other`. + +### and_then + +If self is None, this returns None. Otherwise, this calls the given function with the Some value contained within self, and returns the result of that call. In some languages this function is called `flat_map` or `bind`. + +### or + +If self is Some, return self. Otherwise, return `other`. + +### or_else + +If self is Some, return self. Otherwise, return `default()`. + +### xor + +If only one of the two Options is Some, return that option. Otherwise, if both options are Some or both are None, None is returned. + +### filter + +Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true. Otherwise, this returns `None`. + +### flatten + +Flattens an `Option>` into a `Option`. This returns `None` if the outer Option is None. Otherwise, this returns the inner Option. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md new file mode 100644 index 00000000000..67962082a8f --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md @@ -0,0 +1,90 @@ +--- +title: Recursive Proofs +description: Learn about how to write recursive proofs in Noir. +keywords: [recursion, recursive proofs, verification_key, aggregation object, verify_proof] +--- + +Noir supports recursively verifying proofs, meaning you verify the proof of a Noir program in another Noir program. This enables creating proofs of arbitrary size by doing step-wise verification of smaller components of a large proof. + +The `verify_proof` function takes a verification key, proof and public inputs for a zk program, as well as a key hash and an input aggregation object. The key hash is used to check the validity of the verification key and the input aggregation object is required by some proving systems. The `verify_proof` function returns an output aggregation object that can then be fed into future iterations of the proof verification if required. + +```rust +#[foreign(verify_proof)] +fn verify_proof(_verification_key : [Field], _proof : [Field], _public_input : Field, _key_hash : Field, _input_aggregation_object : [Field]) -> [Field] {} +``` + +:::info + +This is a black box function. Read [this section](./black_box_fns) to learn more about black box functions in Noir. + +::: + +## Example usage + +```rust +use dep::std; + +fn main( + verification_key : [Field; 114], + proof : [Field; 94], + public_inputs : [Field; 1], + key_hash : Field, + input_aggregation_object : [Field; 16], + proof_b : [Field; 94], +) -> pub [Field; 16] { + let output_aggregation_object_a = std::verify_proof( + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), + key_hash, + input_aggregation_object + ); + + let output_aggregation_object = std::verify_proof( + verification_key.as_slice(), + proof_b.as_slice(), + public_inputs.as_slice(), + key_hash, + output_aggregation_object_a + ); + + let mut output = [0; 16]; + for i in 0..16 { + output[i] = output_aggregation_object[i]; + } + output +} +``` + +## Parameters + +### `verification_key` + +The verification key for the zk program that is being verified. + +### `proof` + +The proof for the zk program that is being verified. + +### `public_inputs` + +These represent the public inputs of the proof we are verifying. They should be checked against in the circuit after construction of a new aggregation state. + +### `key_hash` + +A key hash is used to check the validity of the verification key. The circuit implementing this opcode can use this hash to ensure that the key provided to the circuit matches the key produced by the circuit creator. + +### `input_aggregation_object` + +An aggregation object is blob of data that the top-level verifier must run some proof system specific algorithm on to complete verification. The size is proof system specific and will be set by the backend integrating this opcode. The input aggregation object is only not `None` when we are verifying a previous recursive aggregation in the current circuit. If this is the first recursive aggregation there is no input aggregation object. It is left to the backend to determine how to handle when there is no input aggregation object. + +## Return value + +### `output_aggregation_object` + +This is the result of a recursive aggregation and is what will be fed into the next verifier. +The next verifier can either perform a final verification (returning true or false) or perform another recursive aggregation where this output aggregation object will be the input aggregation object of the next recursive aggregation. + +## Example + +You can see an example of how to do recursive proofs in [this example recursion demo repo](https://github.com/noir-lang/noir-examples/tree/master/recursion). diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md new file mode 100644 index 00000000000..f2960ca5080 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md @@ -0,0 +1,284 @@ +--- +title: Traits +description: Noir's stdlib provides a few commonly used traits. +keywords: [traits, trait, interface, protocol, default, add, eq] +--- + +## `std::default` + +### `std::default::Default` + +```rust +trait Default { + fn default() -> Self; +} +``` + +Constructs a default value of a type. + +Implementations: +```rust +impl Default for Field { .. } + +impl Default for i8 { .. } +impl Default for i16 { .. } +impl Default for i32 { .. } +impl Default for i64 { .. } + +impl Default for u8 { .. } +impl Default for u16 { .. } +impl Default for u32 { .. } +impl Default for u64 { .. } + +impl Default for () { .. } +impl Default for bool { .. } + +impl Default for [T; N] + where T: Default { .. } + +impl Default for (A, B) + where A: Default, B: Default { .. } + +impl Default for (A, B, C) + where A: Default, B: Default, C: Default { .. } + +impl Default for (A, B, C, D) + where A: Default, B: Default, C: Default, D: Default { .. } + +impl Default for (A, B, C, D, E) + where A: Default, B: Default, C: Default, D: Default, E: Default { .. } +``` + +For primitive integer types, the return value of `default` is `0`. Container +types such as arrays are filled with default values of their element type. + +## `std::cmp` + +### `std::cmp::Eq` + +```rust +trait Eq { + fn eq(self, other: Self) -> bool; +} +``` +Returns `true` if `self` is equal to `other`. Implementing this trait on a type +allows the type to be used with `==` and `!=`. + +Implementations: +```rust +impl Eq for Field { .. } + +impl Eq for i8 { .. } +impl Eq for i16 { .. } +impl Eq for i32 { .. } +impl Eq for i64 { .. } + +impl Eq for u8 { .. } +impl Eq for u16 { .. } +impl Eq for u32 { .. } +impl Eq for u64 { .. } + +impl Eq for () { .. } +impl Eq for bool { .. } + +impl Eq for [T; N] + where T: Eq { .. } + +impl Eq for (A, B) + where A: Eq, B: Eq { .. } + +impl Eq for (A, B, C) + where A: Eq, B: Eq, C: Eq { .. } + +impl Eq for (A, B, C, D) + where A: Eq, B: Eq, C: Eq, D: Eq { .. } + +impl Eq for (A, B, C, D, E) + where A: Eq, B: Eq, C: Eq, D: Eq, E: Eq { .. } +``` + +### `std::cmp::Cmp` + +```rust +trait Cmp { + fn cmp(self, other: Self) -> Ordering; +} +``` + +`a.cmp(b)` compares two values returning `Ordering::less()` if `a < b`, +`Ordering::equal()` if `a == b`, or `Ordering::greater()` if `a > b`. +Implementing this trait on a type allows `<`, `<=`, `>`, and `>=` to be +used on values of the type. + +Implementations: + +```rust +impl Ord for u8 { .. } +impl Ord for u16 { .. } +impl Ord for u32 { .. } +impl Ord for u64 { .. } + +impl Ord for i8 { .. } +impl Ord for i16 { .. } +impl Ord for i32 { .. } + +impl Ord for i64 { .. } + +impl Ord for () { .. } +impl Ord for bool { .. } + +impl Ord for [T; N] + where T: Ord { .. } + +impl Ord for (A, B) + where A: Ord, B: Ord { .. } + +impl Ord for (A, B, C) + where A: Ord, B: Ord, C: Ord { .. } + +impl Ord for (A, B, C, D) + where A: Ord, B: Ord, C: Ord, D: Ord { .. } + +impl Ord for (A, B, C, D, E) + where A: Ord, B: Ord, C: Ord, D: Ord, E: Ord { .. } +``` + +## `std::ops` + +### `std::ops::Add`, `std::ops::Sub`, `std::ops::Mul`, and `std::ops::Div` + +These traits abstract over addition, subtraction, multiplication, and division respectively. +Implementing these traits for a given type will also allow that type to be used with the corresponding operator +for that trait (`+` for Add, etc) in addition to the normal method names. + +```rust +trait Add { + fn add(self, other: Self) -> Self; +} + +trait Sub { + fn sub(self, other: Self) -> Self; +} + +trait Mul { + fn mul(self, other: Self) -> Self; +} + +trait Div { + fn div(self, other: Self) -> Self; +} +``` + +The implementations block below is given for the `Add` trait, but the same types that implement +`Add` also implement `Sub`, `Mul`, and `Div`. + +Implementations: +```rust +impl Add for Field { .. } + +impl Add for i8 { .. } +impl Add for i16 { .. } +impl Add for i32 { .. } +impl Add for i64 { .. } + +impl Add for u8 { .. } +impl Add for u16 { .. } +impl Add for u32 { .. } +impl Add for u64 { .. } +``` + +### `std::ops::Rem` + +```rust +trait Rem { + fn rem(self, other: Self) -> Self; +} +``` + +`Rem::rem(a, b)` is the remainder function returning the result of what is +left after dividing `a` and `b`. Implementing `Rem` allows the `%` operator +to be used with the implementation type. + +Unlike other numeric traits, `Rem` is not implemented for `Field`. + +Implementations: +```rust +impl Rem for u8 { fn rem(self, other: u8) -> u8 { self % other } } +impl Rem for u16 { fn rem(self, other: u16) -> u16 { self % other } } +impl Rem for u32 { fn rem(self, other: u32) -> u32 { self % other } } +impl Rem for u64 { fn rem(self, other: u64) -> u64 { self % other } } + +impl Rem for i8 { fn rem(self, other: i8) -> i8 { self % other } } +impl Rem for i16 { fn rem(self, other: i16) -> i16 { self % other } } +impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } +impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } +``` + +### `std::ops::{ BitOr, BitAnd, BitXor }` + +```rust +trait BitOr { + fn bitor(self, other: Self) -> Self; +} + +trait BitAnd { + fn bitand(self, other: Self) -> Self; +} + +trait BitXor { + fn bitxor(self, other: Self) -> Self; +} +``` + +Traits for the bitwise operations `|`, `&`, and `^`. + +Implementing `BitOr`, `BitAnd` or `BitXor` for a type allows the `|`, `&`, or `^` operator respectively +to be used with the type. + +The implementations block below is given for the `BitOr` trait, but the same types that implement +`BitOr` also implement `BitAnd` and `BitXor`. + +Implementations: +```rust +impl BitOr for bool { fn bitor(self, other: bool) -> bool { self | other } } + +impl BitOr for u8 { fn bitor(self, other: u8) -> u8 { self | other } } +impl BitOr for u16 { fn bitor(self, other: u16) -> u16 { self | other } } +impl BitOr for u32 { fn bitor(self, other: u32) -> u32 { self | other } } +impl BitOr for u64 { fn bitor(self, other: u64) -> u64 { self | other } } + +impl BitOr for i8 { fn bitor(self, other: i8) -> i8 { self | other } } +impl BitOr for i16 { fn bitor(self, other: i16) -> i16 { self | other } } +impl BitOr for i32 { fn bitor(self, other: i32) -> i32 { self | other } } +impl BitOr for i64 { fn bitor(self, other: i64) -> i64 { self | other } } +``` + +### `std::ops::{ Shl, Shr }` + +```rust +trait Shl { + fn shl(self, other: Self) -> Self; +} + +trait Shr { + fn shr(self, other: Self) -> Self; +} +``` + +Traits for a bit shift left and bit shift right. + +Implementing `Shl` for a type allows the left shift operator (`<<`) to be used with the implementation type. +Similarly, implementing `Shr` allows the right shift operator (`>>`) to be used with the type. + +Note that bit shifting is not currently implemented for signed types. + +The implementations block below is given for the `Shl` trait, but the same types that implement +`Shl` also implement `Shr`. + +Implementations: +```rust +impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } +impl Shl for u16 { fn shl(self, other: u16) -> u16 { self << other } } +impl Shl for u32 { fn shl(self, other: u32) -> u32 { self << other } } +impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } +``` diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md new file mode 100644 index 00000000000..97dab02dac2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md @@ -0,0 +1,25 @@ +--- +title: Zeroed Function +description: + The zeroed function returns a zeroed value of any type. +keywords: + [ + zeroed + ] +--- + +Implements `fn zeroed() -> T` to return a zeroed value of any type. This function is generally unsafe to use as the zeroed bit pattern is not guaranteed to be valid for all types. It can however, be useful in cases when the value is guaranteed not to be used such as in a BoundedVec library implementing a growable vector, up to a certain length, backed by an array. The array can be initialized with zeroed values which are guaranteed to be inaccessible until the vector is pushed to. Similarly, enumerations in noir can be implemented using this method by providing zeroed values for the unused variants. + +You can access the function at `std::unsafe::zeroed`. + +This function currently supports the following types: + +- Field +- Bool +- Uint +- Array +- String +- Tuple +- Function + +Using it on other types could result in unexpected behavior. diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..5cbe9421b92 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,185 @@ +# BarretenbergBackend + +## Implements + +- [`Backend`](../interfaces/Backend.md) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`destroy`](../interfaces/Backend.md#destroy) + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateFinalProof`](../interfaces/Backend.md#generatefinalproof) + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(witness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `witness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProof`](../interfaces/Backend.md#generateintermediateproof) + +#### Example + +```typescript +const intermediateProof = await backend.generateIntermediateProof(witness); +``` + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProofArtifacts`](../interfaces/Backend.md#generateintermediateproofartifacts) + +#### Example + +```typescript +const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyFinalProof`](../interfaces/Backend.md#verifyfinalproof) + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyIntermediateProof`](../interfaces/Backend.md#verifyintermediateproof) + +#### Example + +```typescript +const isValidIntermediate = await backend.verifyIntermediateProof(proof); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md new file mode 100644 index 00000000000..93b248b0f65 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md @@ -0,0 +1,45 @@ +# Backend Barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | + +### Interfaces + +| Interface | Description | +| :------ | :------ | +| [Backend](interfaces/Backend.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | + +## Functions + +### flattenPublicInputs() + +```ts +flattenPublicInputs(publicInputs): string[] +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `WitnessMap` | + +#### Returns + +`string`[] + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md new file mode 100644 index 00000000000..3eb9645c8d2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md @@ -0,0 +1,132 @@ +# Backend + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates an intermediate proof (meant to be verified in another circuit) + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | +| `numOfPublicInputs` | `number` | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Retrieves the artifacts from a proof in the Field format + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies an intermediate proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..266ade75d17 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,19 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..04e662c845f --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"noir_js/reference/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"}]},{"type":"category","label":"Interfaces","items":[{"type":"doc","id":"noir_js/reference/backend_barretenberg/interfaces/Backend","label":"Backend"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"noir_js/reference/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"},{"type":"doc","id":"noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"noir_js/reference/backend_barretenberg/type-aliases/ProofData","label":"ProofData"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md new file mode 100644 index 00000000000..c54468891af --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md @@ -0,0 +1,131 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `backend`? | `Backend` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateFinalProof() + +```ts +generateFinalProof(inputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateFinalProof(input) +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyFinalProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..0ba5783f0d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,29 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md new file mode 100644 index 00000000000..348453c0059 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md @@ -0,0 +1,37 @@ +# Noir JS + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [InputMap](type-aliases/InputMap.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Calculates the Blake2s256 hash of the input bytes and represents these as a single field element. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md new file mode 100644 index 00000000000..c714e999d93 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md @@ -0,0 +1,13 @@ +# InputMap + +```ts +type InputMap: object; +``` + +## Index signature + + \[`key`: `string`\]: `InputValue` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md new file mode 100644 index 00000000000..3eb360a78f1 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `WitnessMap` | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..077ebeb133e --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"noir_js/reference/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/InputMap","label":"InputMap"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/ProofData","label":"ProofData"},{"type":"doc","id":"noir_js/reference/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"noir_js/reference/noir_js/functions/and","label":"and"},{"type":"doc","id":"noir_js/reference/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"noir_js/reference/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"noir_js/reference/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"noir_js/reference/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 00000000000..5cbe9421b92 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,185 @@ +# BarretenbergBackend + +## Implements + +- [`Backend`](../interfaces/Backend.md) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`destroy`](../interfaces/Backend.md#destroy) + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateFinalProof`](../interfaces/Backend.md#generatefinalproof) + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(witness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `witness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProof`](../interfaces/Backend.md#generateintermediateproof) + +#### Example + +```typescript +const intermediateProof = await backend.generateIntermediateProof(witness); +``` + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`generateIntermediateProofArtifacts`](../interfaces/Backend.md#generateintermediateproofartifacts) + +#### Example + +```typescript +const artifacts = await backend.generateIntermediateProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyFinalProof`](../interfaces/Backend.md#verifyfinalproof) + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`verifyIntermediateProof`](../interfaces/Backend.md#verifyintermediateproof) + +#### Example + +```typescript +const isValidIntermediate = await backend.verifyIntermediateProof(proof); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md new file mode 100644 index 00000000000..e32501acb71 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md @@ -0,0 +1,46 @@ +# backend_barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | + +### Interfaces + +| Interface | Description | +| :------ | :------ | +| [Backend](interfaces/Backend.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | + +## Functions + +### publicInputsToWitnessMap() + +```ts +publicInputsToWitnessMap(publicInputs, abi): WitnessMap +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `string`[] | +| `abi` | `Abi` | + +#### Returns + +`WitnessMap` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md new file mode 100644 index 00000000000..3eb9645c8d2 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md @@ -0,0 +1,132 @@ +# Backend + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates an intermediate proof (meant to be verified in another circuit) + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | +| `numOfPublicInputs` | `number` | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Retrieves the artifacts from a proof in the Field format + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies an intermediate proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 00000000000..266ade75d17 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,19 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md new file mode 100644 index 00000000000..05cebbc4e94 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `string`[] | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 00000000000..2aaa55bccf6 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"}]},{"type":"category","label":"Interfaces","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/interfaces/Backend","label":"Backend"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/ProofData","label":"ProofData"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll new file mode 100644 index 00000000000..e2ac6616add --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md new file mode 100644 index 00000000000..34e20d99684 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md @@ -0,0 +1,132 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `backend`? | `Backend` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateFinalProof() + +```ts +generateFinalProof(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateFinalProof(input) +``` + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyFinalProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md new file mode 100644 index 00000000000..c783283e396 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md new file mode 100644 index 00000000000..7882d0da8d5 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 00000000000..5e3cd53e9d3 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 00000000000..0b20ff68957 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md new file mode 100644 index 00000000000..d10f155ce86 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md new file mode 100644 index 00000000000..6ba4ecac022 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md new file mode 100644 index 00000000000..8d762b895d3 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md new file mode 100644 index 00000000000..d600e21b299 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md @@ -0,0 +1,37 @@ +# noir_js + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [InputMap](type-aliases/InputMap.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Verifies a ECDSA signature over the secp256k1 curve. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md new file mode 100644 index 00000000000..34e0dd04205 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 00000000000..812b8b16481 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 00000000000..dd95809186a --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 00000000000..b71fb78a946 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md new file mode 100644 index 00000000000..c714e999d93 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md @@ -0,0 +1,13 @@ +# InputMap + +```ts +type InputMap: object; +``` + +## Index signature + + \[`key`: `string`\]: `InputValue` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md new file mode 100644 index 00000000000..05cebbc4e94 --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `string`[] | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 00000000000..258c46f9d0c --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs new file mode 100644 index 00000000000..fe2629ddc9f --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/InputMap","label":"InputMap"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ProofData","label":"ProofData"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_js/functions/and","label":"and"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/_category_.json b/noir/docs/versioned_docs/version-v0.23.0/reference/_category_.json new file mode 100644 index 00000000000..5b6a20a609a --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 4, + "collapsible": true, + "collapsed": true +} diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md b/noir/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md new file mode 100644 index 00000000000..fc2671b2bfc --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md @@ -0,0 +1,253 @@ +--- +title: Nargo +description: + Noir CLI Commands for Noir Prover and Verifier to create, execute, prove and verify programs, + generate Solidity verifier smart contract and compile into JSON file containing ACIR + representation and ABI of circuit. +keywords: + [ + Nargo, + Noir CLI, + Noir Prover, + Noir Verifier, + generate Solidity verifier, + compile JSON file, + ACIR representation, + ABI of circuit, + TypeScript, + ] +sidebar_position: 0 +--- + +## General options + +| Option | Description | +| -------------------- | -------------------------------------------------- | +| `--show-ssa` | Emit debug information for the intermediate SSA IR | +| `--deny-warnings` | Quit execution when warnings are emitted | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo help [subcommand]` + +Prints the list of available commands or specific information of a subcommand. + +_Arguments_ + +| Argument | Description | +| -------------- | -------------------------------------------- | +| `` | The subcommand whose help message to display | + +## `nargo backend` + +Installs and selects custom backends used to generate and verify proofs. + +### Commands + +| Command | Description | +| ----------- | --------------------------------------------------------- | +| `current` | Prints the name of the currently active backend | +| `ls` | Prints the list of currently installed backends | +| `use` | Select the backend to use | +| `install` | Install a new backend from a URL | +| `uninstall` | Uninstalls a backend | +| `help` | Print this message or the help of the given subcommand(s) | + +### Options + +| Option | Description | +| ------------ | ----------- | +| `-h, --help` | Print help | + +## `nargo check` + +Generate the `Prover.toml` and `Verifier.toml` files for specifying prover and verifier in/output +values of the Noir program respectively. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to check | +| `--workspace` | Check all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +### `nargo codegen-verifier` + +Generate a Solidity verifier smart contract for the program. + +### Options + +| Option | Description | +| --------------------- | ------------------------------------- | +| `--package ` | The name of the package to codegen | +| `--workspace` | Codegen all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo compile` + +Compile the program into a JSON build artifact file containing the ACIR representation and the ABI +of the circuit. This build artifact can then be used to generate and verify proofs. + +You can also use "build" as an alias for compile (e.g. `nargo build`). + +### Options + +| Option | Description | +| --------------------- | ------------------------------------------------------------ | +| `--package ` | The name of the package to compile | +| `--workspace` | Compile all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo new ` + +Creates a new Noir project in a new folder. + +**Arguments** + +| Argument | Description | +| -------- | -------------------------------- | +| `` | The path to save the new project | + +### Options + +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: package directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | + +## `nargo init` + +Creates a new Noir project in the current directory. + +### Options + +| Option | Description | +| --------------- | ----------------------------------------------------- | +| `--name ` | Name of the package [default: current directory name] | +| `--lib` | Use a library template | +| `--bin` | Use a binary template [default] | +| `--contract` | Use a contract template | +| `-h, --help` | Print help | + +## `nargo execute [WITNESS_NAME]` + +Runs the Noir program and prints its return value. + +**Arguments** + +| Argument | Description | +| ---------------- | ----------------------------------------- | +| `[WITNESS_NAME]` | Write the execution witness to named file | + +### Options + +| Option | Description | +| --------------------------------- | ------------------------------------------------------------------------------------ | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `--package ` | The name of the package to execute | +| `--workspace` | Execute all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `--oracle-resolver` | JSON RPC url to solve oracle calls | +| `-h, --help` | Print help | + +_Usage_ + +The inputs to the circuit are read from the `Prover.toml` file generated by `nargo check`, which +must be filled in. + +To save the witness to file, run the command with a value for the `WITNESS_NAME` argument. A +`.tr` file will then be saved in the `./target` folder. + +## `nargo prove` + +Creates a proof for the program. + +### Options + +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-p, --prover-name ` | The name of the toml file which contains the inputs for the prover [default: Prover] | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--verify` | Verify proof after proving | +| `--package ` | The name of the package to prove | +| `--workspace` | Prove all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `--oracle-resolver` | JSON RPC url to solve oracle calls | +| `-h, --help` | Print help | + +## `nargo verify` + +Given a proof and a program, verify whether the proof is valid. + +### Options + +| Option | Description | +| ------------------------------------- | ---------------------------------------------------------------------------------------- | +| `-v, --verifier-name ` | The name of the toml file which contains the inputs for the verifier [default: Verifier] | +| `--package ` | The name of the package to verify | +| `--workspace` | Verify all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `-h, --help` | Print help | + +## `nargo test [TEST_NAME]` + +Nargo will automatically compile and run any functions which have the decorator `#[test]` on them if +you run `nargo test`. To print `println` statements in tests, use the `--show-output` flag. + +Takes an optional `--exact` flag which allows you to select tests based on an exact name. + +See an example on the [testing page](../getting_started/tooling/testing.md). + +### Options + +| Option | Description | +| --------------------- | -------------------------------------- | +| `--show-output` | Display output of `println` statements | +| `--exact` | Only run tests that match exactly | +| `--package ` | The name of the package to test | +| `--workspace` | Test all packages in the workspace | +| `--print-acir` | Display the ACIR for compiled circuit | +| `--deny-warnings` | Treat all warnings as errors | +| `--silence-warnings` | Suppress warnings | +| `--oracle-resolver` | JSON RPC url to solve oracle calls | +| `-h, --help` | Print help | + +## `nargo info` + +Prints a table containing the information of the package. + +Currently the table provide + +1. The number of ACIR opcodes +2. The final number gates in the circuit used by a backend + +If the file contains a contract the table will provide the +above information about each function of the contract. + +## `nargo lsp` + +Start a long-running Language Server process that communicates over stdin/stdout. +Usually this command is not run by a user, but instead will be run by a Language Client, such as [vscode-noir](https://github.com/noir-lang/vscode-noir). + +## `nargo fmt` + +Automatically formats your Noir source code based on the default formatting settings. diff --git a/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md b/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md new file mode 100644 index 00000000000..23534795dde --- /dev/null +++ b/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md @@ -0,0 +1,279 @@ +--- +title: Building a web app with NoirJS +description: Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment. +keywords: [how to, guide, javascript, typescript, noir, barretenberg, zero-knowledge, proofs, app] +sidebar_position: 0 +pagination_next: noir/concepts/data_types/index +--- + +NoirJS is a set of packages meant to work both in a browser and a server environment. In this tutorial, we will build a simple web app using them. From here, you should get an idea on how to proceed with your own Noir projects! + +You can find the complete app code for this guide [here](https://github.com/noir-lang/tiny-noirjs-app). + +## Setup + +:::note + +Feel free to use whatever versions, just keep in mind that Nargo and the NoirJS packages are meant to be in sync. For example, Nargo 0.19.x matches `noir_js@0.19.x`, etc. + +In this guide, we will be pinned to 0.19.4. + +::: + +Before we start, we want to make sure we have Node and Nargo installed. + +We start by opening a terminal and executing `node --version`. If we don't get an output like `v20.10.0`, that means node is not installed. Let's do that by following the handy [nvm guide](https://github.com/nvm-sh/nvm?tab=readme-ov-file#install--update-script). + +As for `Nargo`, we can follow the the [Nargo guide](../getting_started/installation/index.md) to install it. If you're lazy, just paste this on a terminal and run `noirup`: + +```sh +curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash +``` + +Easy enough. Onwards! + +## Our project + +ZK is a powerful technology. An app that doesn't reveal one of the inputs to *anyone* is almost unbelievable, yet Noir makes it as easy as a single line of code. + +In fact, it's so simple that it comes nicely packaged in `nargo`. Let's do that! + +### Nargo + +Run: + +```nargo new circuit``` + +And... That's about it. Your program is ready to be compiled and run. + +To compile, let's `cd` into the `circuit` folder to enter our project, and call: + +```nargo compile``` + +This compiles our circuit into `json` format and add it to a new `target` folder. + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit <---- our working directory + ├── Nargo.toml + ├── src + │ └── main.nr + └── target + └── circuit.json +``` + +::: + +### Node and Vite + +If you want to explore Nargo, feel free to go on a side-quest now and follow the steps in the +[getting started](../getting_started/hello_noir/index.md) guide. However, we want our app to run on the browser, so we need Vite. + +Vite is a powerful tool to generate static websites. While it provides all kinds of features, let's just go barebones with some good old vanilla JS. + +To do this this, go back to the previous folder (`cd ..`) and create a new vite project by running `npm create vite` and choosing "Vanilla" and "Javascript". + +You should see `vite-project` appear in your root folder. This seems like a good time to `cd` into it and install our NoirJS packages: + +```bash +npm i @noir-lang/backend_barretenberg@0.19.4 @noir-lang/noir_js@0.19.4 +``` + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit + └── ...etc... +└── vite-project <---- our working directory + └── ...etc... +``` + +::: + +#### Some cleanup + +`npx create vite` is amazing but it creates a bunch of files we don't really need for our simple example. Actually, let's just delete everything except for `index.html`, `main.js` and `package.json`. I feel lighter already. + +![my heart is ready for you, noir.js](../../static/img/memes/titanic.jpeg) + +## HTML + +Our app won't run like this, of course. We need some working HTML, at least. Let's open our broken-hearted `index.html` and replace everything with this code snippet: + +```html + + + + + + +

Noir app

+
+ + +
+
+

Logs

+

Proof

+
+ + +``` + +It *could* be a beautiful UI... Depending on which universe you live in. + +## Some good old vanilla Javascript + +Our love for Noir needs undivided attention, so let's just open `main.js` and delete everything (this is where the romantic scenery becomes a bit creepy). + +Start by pasting in this boilerplate code: + +```js +const setup = async () => { + await Promise.all([ + import("@noir-lang/noirc_abi").then(module => + module.default(new URL("@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm", import.meta.url).toString()) + ), + import("@noir-lang/acvm_js").then(module => + module.default(new URL("@noir-lang/acvm_js/web/acvm_js_bg.wasm", import.meta.url).toString()) + ) + ]); +} + +function display(container, msg) { + const c = document.getElementById(container); + const p = document.createElement('p'); + p.textContent = msg; + c.appendChild(p); +} + +document.getElementById('submitGuess').addEventListener('click', async () => { + try { + // here's where love happens + } catch(err) { + display("logs", "Oh 💔 Wrong guess") + } +}); + +``` + +The display function doesn't do much. We're simply manipulating our website to see stuff happening. For example, if the proof fails, it will simply log a broken heart 😢 + +As for the `setup` function, it's just a sad reminder that dealing with `wasm` on the browser is not as easy as it should. Just copy, paste, and forget. + +:::info + +At this point in the tutorial, your folder structure should look like this: + +```tree +. +└── circuit + └── ...same as above +└── vite-project + ├── main.js + ├── package.json + └── index.html +``` + +You'll see other files and folders showing up (like `package-lock.json`, `node_modules`) but you shouldn't have to care about those. + +::: + +## Some NoirJS + +We're starting with the good stuff now. If you've compiled the circuit as described above, you should have a `json` file we want to import at the very top of our `main.js` file: + +```ts +import circuit from '../circuit/target/circuit.json'; +``` + +[Noir is backend-agnostic](../index.mdx#whats-new-about-noir). We write Noir, but we also need a proving backend. That's why we need to import and instantiate the two dependencies we installed above: `BarretenbergBackend` and `Noir`. Let's import them right below: + +```js +import { BarretenbergBackend } from '@noir-lang/backend_barretenberg'; +import { Noir } from '@noir-lang/noir_js'; +``` + +And instantiate them inside our try-catch block: + +```ts +// try { +const backend = new BarretenbergBackend(circuit); +const noir = new Noir(circuit, backend); +// } +``` + +:::note + +For the remainder of the tutorial, everything will be happening inside the `try` block + +::: + +## Our app + +Now for the app itself. We're capturing whatever is in the input when people press the submit button. Just add this: + +```js +const x = parseInt(document.getElementById('guessInput').value); +const input = { x, y: 2 }; +``` + +Now we're ready to prove stuff! Let's feed some inputs to our circuit and calculate the proof: + +```js +await setup(); // let's squeeze our wasm inits here + +display('logs', 'Generating proof... ⌛'); +const proof = await noir.generateFinalProof(input); +display('logs', 'Generating proof... ✅'); +display('results', proof.proof); +``` + +You're probably eager to see stuff happening, so go and run your app now! + +From your terminal, run `npm run dev`. If it doesn't open a browser for you, just visit `localhost:5173`. You should now see the worst UI ever, with an ugly input. + +![Getting Started 0](@site/static/img/noir_getting_started_1.png) + +Now, our circuit says `fn main(x: Field, y: pub Field)`. This means only the `y` value is public, and it's hardcoded above: `input = { x, y: 2 }`. In other words, you won't need to send your secret`x` to the verifier! + +By inputting any number other than 2 in the input box and clicking "submit", you should get a valid proof. Otherwise the proof won't even generate correctly. By the way, if you're human, you shouldn't be able to understand anything on the "proof" box. That's OK. We like you, human ❤️. + +## Verifying + +Time to celebrate, yes! But we shouldn't trust machines so blindly. Let's add these lines to see our proof being verified: + +```js +display('logs', 'Verifying proof... ⌛'); +const verification = await noir.verifyFinalProof(proof); +if (verification) display('logs', 'Verifying proof... ✅'); +``` + +You have successfully generated a client-side Noir web app! + +![coded app without math knowledge](../../static/img/memes/flextape.jpeg) + +## Further Reading + +You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. + +You should also check out the more advanced examples in the [noir-examples repo](https://github.com/noir-lang/noir-examples), where you'll find reference usage for some cool apps. diff --git a/noir/docs/versioned_sidebars/version-v0.23.0-sidebars.json b/noir/docs/versioned_sidebars/version-v0.23.0-sidebars.json new file mode 100644 index 00000000000..b16f79cc176 --- /dev/null +++ b/noir/docs/versioned_sidebars/version-v0.23.0-sidebars.json @@ -0,0 +1,83 @@ +{ + "sidebar": [ + { + "type": "doc", + "id": "index" + }, + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "autogenerated", + "dirName": "getting_started" + } + ] + }, + { + "type": "category", + "label": "The Noir Language", + "items": [ + { + "type": "autogenerated", + "dirName": "noir" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "category", + "label": "How To Guides", + "items": [ + { + "type": "autogenerated", + "dirName": "how_to" + } + ] + }, + { + "type": "category", + "label": "Explainers", + "items": [ + { + "type": "autogenerated", + "dirName": "explainers" + } + ] + }, + { + "type": "category", + "label": "Tutorials", + "items": [ + { + "type": "autogenerated", + "dirName": "tutorials" + } + ] + }, + { + "type": "category", + "label": "Reference", + "items": [ + { + "type": "autogenerated", + "dirName": "reference" + } + ] + }, + { + "type": "html", + "value": "
", + "defaultStyle": true + }, + { + "type": "doc", + "id": "migration_notes", + "label": "Migration notes" + } + ] +} diff --git a/noir/noir_stdlib/src/cmp.nr b/noir/noir_stdlib/src/cmp.nr index 11127494c18..b3de3e2658e 100644 --- a/noir/noir_stdlib/src/cmp.nr +++ b/noir/noir_stdlib/src/cmp.nr @@ -1,6 +1,8 @@ +// docs:start:eq-trait trait Eq { fn eq(self, other: Self) -> bool; } +// docs:end:eq-trait impl Eq for Field { fn eq(self, other: Field) -> bool { self == other } } @@ -66,7 +68,6 @@ impl Eq for Ordering { } } - // Noir doesn't have enums yet so we emulate (Lt | Eq | Gt) with a struct // that has 3 public functions for constructing the struct. struct Ordering { @@ -90,10 +91,11 @@ impl Ordering { } } - +// docs:start:ord-trait trait Ord { fn cmp(self, other: Self) -> Ordering; } +// docs:end:ord-trait // Note: Field deliberately does not implement Ord diff --git a/noir/noir_stdlib/src/convert.nr b/noir/noir_stdlib/src/convert.nr new file mode 100644 index 00000000000..814f63f1cde --- /dev/null +++ b/noir/noir_stdlib/src/convert.nr @@ -0,0 +1,61 @@ +// docs:start:from-trait +trait From { + fn from(input: T) -> Self; +} +// docs:end:from-trait + +impl From for T { + fn from(input: T) -> T { + input + } +} + +// docs:start:into-trait +trait Into { + fn into(input: Self) -> T; +} + +impl Into for U where T: From { + fn into(input: U) -> T { + T::from(input) + } +} +// docs:end:into-trait + +// docs:start:from-impls +// Unsigned integers +impl From for u16 { fn from(value: u8) -> u16 { value as u16 } } + +impl From for u32 { fn from(value: u8) -> u32 { value as u32 } } +impl From for u32 { fn from(value: u16) -> u32 { value as u32 } } + +impl From for u64 { fn from(value: u8) -> u64 { value as u64 } } +impl From for u64 { fn from(value: u16) -> u64 { value as u64 } } +impl From for u64 { fn from(value: u32) -> u64 { value as u64 } } + +impl From for Field { fn from(value: u8) -> Field { value as Field } } +impl From for Field { fn from(value: u16) -> Field { value as Field } } +impl From for Field { fn from(value: u32) -> Field { value as Field } } +impl From for Field { fn from(value: u64) -> Field { value as Field } } + +// Signed integers +impl From for i16 { fn from(value: i8) -> i16 { value as i16 } } + +impl From for i32 { fn from(value: i8) -> i32 { value as i32 } } +impl From for i32 { fn from(value: i16) -> i32 { value as i32 } } + +impl From for i64 { fn from(value: i8) -> i64 { value as i64 } } +impl From for i64 { fn from(value: i16) -> i64 { value as i64 } } +impl From for i64 { fn from(value: i32) -> i64 { value as i64 } } + +// Booleans +impl From for u8 { fn from(value: bool) -> u8 { value as u8 } } +impl From for u16 { fn from(value: bool) -> u16 { value as u16 } } +impl From for u32 { fn from(value: bool) -> u32 { value as u32 } } +impl From for u64 { fn from(value: bool) -> u64 { value as u64 } } +impl From for i8 { fn from(value: bool) -> i8 { value as i8 } } +impl From for i16 { fn from(value: bool) -> i16 { value as i16 } } +impl From for i32 { fn from(value: bool) -> i32 { value as i32 } } +impl From for i64 { fn from(value: bool) -> i64 { value as i64 } } +impl From for Field { fn from(value: bool) -> Field { value as Field } } +// docs:end:from-impls diff --git a/noir/noir_stdlib/src/default.nr b/noir/noir_stdlib/src/default.nr index 232be74489c..ba6412a834f 100644 --- a/noir/noir_stdlib/src/default.nr +++ b/noir/noir_stdlib/src/default.nr @@ -1,6 +1,8 @@ +// docs:start:default-trait trait Default { fn default() -> Self; } +// docs:end:default-trait impl Default for Field { fn default() -> Field { 0 } } diff --git a/noir/noir_stdlib/src/ecdsa_secp256k1.nr b/noir/noir_stdlib/src/ecdsa_secp256k1.nr index b1f2b12c76b..290ccba27e5 100644 --- a/noir/noir_stdlib/src/ecdsa_secp256k1.nr +++ b/noir/noir_stdlib/src/ecdsa_secp256k1.nr @@ -1,7 +1,10 @@ #[foreign(ecdsa_secp256k1)] +// docs:start:ecdsa_secp256k1 pub fn verify_signature( _public_key_x: [u8; 32], _public_key_y: [u8; 32], _signature: [u8; 64], _message_hash: [u8; N] -) -> bool {} +) -> bool +// docs:end:ecdsa_secp256k1 +{} diff --git a/noir/noir_stdlib/src/ecdsa_secp256r1.nr b/noir/noir_stdlib/src/ecdsa_secp256r1.nr index 6c3cf4d7945..390f8ed39d2 100644 --- a/noir/noir_stdlib/src/ecdsa_secp256r1.nr +++ b/noir/noir_stdlib/src/ecdsa_secp256r1.nr @@ -1,7 +1,10 @@ #[foreign(ecdsa_secp256r1)] +// docs:start:ecdsa_secp256r1 pub fn verify_signature( _public_key_x: [u8; 32], _public_key_y: [u8; 32], _signature: [u8; 64], _message_hash: [u8; N] -) -> bool {} +) -> bool +// docs:end:ecdsa_secp256r1 +{} diff --git a/noir/noir_stdlib/src/hash.nr b/noir/noir_stdlib/src/hash.nr index d53729f423f..4033e2a5365 100644 --- a/noir/noir_stdlib/src/hash.nr +++ b/noir/noir_stdlib/src/hash.nr @@ -2,20 +2,32 @@ mod poseidon; mod mimc; #[foreign(sha256)] -pub fn sha256(_input: [u8; N]) -> [u8; 32] {} +// docs:start:sha256 +pub fn sha256(_input: [u8; N]) -> [u8; 32] +// docs:end:sha256 +{} #[foreign(blake2s)] -pub fn blake2s(_input: [u8; N]) -> [u8; 32] {} +// docs:start:blake2s +pub fn blake2s(_input: [u8; N]) -> [u8; 32] +// docs:end:blake2s +{} #[foreign(blake3)] -pub fn blake3(_input: [u8; N]) -> [u8; 32] {} +// docs:start:blake3 +pub fn blake3(_input: [u8; N]) -> [u8; 32] +// docs:end:blake3 +{} +// docs:start:pedersen_commitment struct PedersenPoint { x : Field, y : Field, } -pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint { +pub fn pedersen_commitment(input: [Field; N]) -> PedersenPoint +// docs:end:pedersen_commitment +{ pedersen_commitment_with_separator(input, 0) } @@ -27,7 +39,10 @@ pub fn pedersen_commitment_with_separator(input: [Field; N], separator: u32) PedersenPoint { x: values[0], y: values[1] } } -pub fn pedersen_hash(input: [Field; N]) -> Field { +// docs:start:pedersen_hash +pub fn pedersen_hash(input: [Field; N]) -> Field +// docs:end:pedersen_hash +{ pedersen_hash_with_separator(input, 0) } @@ -49,7 +64,13 @@ pub fn hash_to_field(_input: [Field; N]) -> Field { } #[foreign(keccak256)] -pub fn keccak256(_input: [u8; N], _message_size: u32) -> [u8; 32] {} +// docs:start:keccak256 +pub fn keccak256(_input: [u8; N], _message_size: u32) -> [u8; 32] +// docs:end:keccak256 +{} #[foreign(poseidon2_permutation)] pub fn poseidon2_permutation(_input: [u8; N], _state_length: u32) -> [u8; N] {} + +#[foreign(sha256_compression)] +pub fn sha256_compression(_input: [u32; 16], _state: [u32; 8]) -> [u32; 8] {} diff --git a/noir/noir_stdlib/src/lib.nr b/noir/noir_stdlib/src/lib.nr index c7e808c1029..b7c7833277a 100644 --- a/noir/noir_stdlib/src/lib.nr +++ b/noir/noir_stdlib/src/lib.nr @@ -16,6 +16,7 @@ mod ec; mod unsafe; mod collections; mod compat; +mod convert; mod option; mod string; mod test; diff --git a/noir/noir_stdlib/src/ops.nr b/noir/noir_stdlib/src/ops.nr index 3078ac11296..50386290b8e 100644 --- a/noir/noir_stdlib/src/ops.nr +++ b/noir/noir_stdlib/src/ops.nr @@ -1,7 +1,8 @@ - +// docs:start:add-trait trait Add { fn add(self, other: Self) -> Self; } +// docs:end:add-trait impl Add for Field { fn add(self, other: Field) -> Field { self + other } } @@ -15,9 +16,11 @@ impl Add for i16 { fn add(self, other: i16) -> i16 { self + other } } impl Add for i32 { fn add(self, other: i32) -> i32 { self + other } } impl Add for i64 { fn add(self, other: i64) -> i64 { self + other } } +// docs:start:sub-trait trait Sub { fn sub(self, other: Self) -> Self; } +// docs:end:sub-trait impl Sub for Field { fn sub(self, other: Field) -> Field { self - other } } @@ -31,9 +34,11 @@ impl Sub for i16 { fn sub(self, other: i16) -> i16 { self - other } } impl Sub for i32 { fn sub(self, other: i32) -> i32 { self - other } } impl Sub for i64 { fn sub(self, other: i64) -> i64 { self - other } } +// docs:start:mul-trait trait Mul { fn mul(self, other: Self) -> Self; } +// docs:end:mul-trait impl Mul for Field { fn mul(self, other: Field) -> Field { self * other } } @@ -47,9 +52,11 @@ impl Mul for i16 { fn mul(self, other: i16) -> i16 { self * other } } impl Mul for i32 { fn mul(self, other: i32) -> i32 { self * other } } impl Mul for i64 { fn mul(self, other: i64) -> i64 { self * other } } +// docs:start:div-trait trait Div { fn div(self, other: Self) -> Self; } +// docs:end:div-trait impl Div for Field { fn div(self, other: Field) -> Field { self / other } } @@ -63,9 +70,11 @@ impl Div for i16 { fn div(self, other: i16) -> i16 { self / other } } impl Div for i32 { fn div(self, other: i32) -> i32 { self / other } } impl Div for i64 { fn div(self, other: i64) -> i64 { self / other } } -trait Rem { +// docs:start:rem-trait +trait Rem{ fn rem(self, other: Self) -> Self; } +// docs:end:rem-trait impl Rem for u8 { fn rem(self, other: u8) -> u8 { self % other } } impl Rem for u16 { fn rem(self, other: u16) -> u16 { self % other } } @@ -77,9 +86,11 @@ impl Rem for i16 { fn rem(self, other: i16) -> i16 { self % other } } impl Rem for i32 { fn rem(self, other: i32) -> i32 { self % other } } impl Rem for i64 { fn rem(self, other: i64) -> i64 { self % other } } +// docs:start:bitor-trait trait BitOr { fn bitor(self, other: Self) -> Self; } +// docs:end:bitor-trait impl BitOr for bool { fn bitor(self, other: bool) -> bool { self | other } } @@ -93,9 +104,11 @@ impl BitOr for i16 { fn bitor(self, other: i16) -> i16 { self | other } } impl BitOr for i32 { fn bitor(self, other: i32) -> i32 { self | other } } impl BitOr for i64 { fn bitor(self, other: i64) -> i64 { self | other } } +// docs:start:bitand-trait trait BitAnd { fn bitand(self, other: Self) -> Self; } +// docs:end:bitand-trait impl BitAnd for bool { fn bitand(self, other: bool) -> bool { self & other } } @@ -109,9 +122,11 @@ impl BitAnd for i16 { fn bitand(self, other: i16) -> i16 { self & other } } impl BitAnd for i32 { fn bitand(self, other: i32) -> i32 { self & other } } impl BitAnd for i64 { fn bitand(self, other: i64) -> i64 { self & other } } +// docs:start:bitxor-trait trait BitXor { fn bitxor(self, other: Self) -> Self; } +// docs:end:bitxor-trait impl BitXor for bool { fn bitxor(self, other: bool) -> bool { self ^ other } } @@ -125,9 +140,11 @@ impl BitXor for i16 { fn bitxor(self, other: i16) -> i16 { self ^ other } } impl BitXor for i32 { fn bitxor(self, other: i32) -> i32 { self ^ other } } impl BitXor for i64 { fn bitxor(self, other: i64) -> i64 { self ^ other } } +// docs:start:shl-trait trait Shl { fn shl(self, other: Self) -> Self; } +// docs:end:shl-trait impl Shl for u8 { fn shl(self, other: u8) -> u8 { self << other } } impl Shl for u16 { fn shl(self, other: u16) -> u16 { self << other } } @@ -140,9 +157,11 @@ impl Shl for u64 { fn shl(self, other: u64) -> u64 { self << other } } // impl Shl for i32 { fn shl(self, other: i32) -> i32 { self << other } } // impl Shl for i64 { fn shl(self, other: i64) -> i64 { self << other } } +// docs:start:shr-trait trait Shr { fn shr(self, other: Self) -> Self; } +// docs:end:shr-trait impl Shr for u8 { fn shr(self, other: u8) -> u8 { self >> other } } impl Shr for u16 { fn shr(self, other: u16) -> u16 { self >> other } } diff --git a/noir/noir_stdlib/src/prelude.nr b/noir/noir_stdlib/src/prelude.nr index b57ff460371..26c6a805d54 100644 --- a/noir/noir_stdlib/src/prelude.nr +++ b/noir/noir_stdlib/src/prelude.nr @@ -4,3 +4,4 @@ use crate::{print, println, assert_constant}; use crate::uint128::U128; use crate::cmp::{Eq, Ord}; use crate::default::Default; +use crate::convert::{From, Into}; diff --git a/noir/noir_stdlib/src/scalar_mul.nr b/noir/noir_stdlib/src/scalar_mul.nr index 2f852628dbb..fef2398222f 100644 --- a/noir/noir_stdlib/src/scalar_mul.nr +++ b/noir/noir_stdlib/src/scalar_mul.nr @@ -10,8 +10,9 @@ struct EmbeddedCurvePoint { // The embedded curve being used is decided by the // underlying proof system. #[foreign(fixed_base_scalar_mul)] +// docs:start:fixed_base_embedded_curve pub fn fixed_base_embedded_curve(_low: Field, _high: Field) -> [Field; 2] {} - +// docs:end:fixed_base_embedded_curve #[foreign(embedded_curve_add)] pub fn embedded_curve_add(_point1: EmbeddedCurvePoint, _point2: EmbeddedCurvePoint) -> EmbeddedCurvePoint {} diff --git a/noir/noir_stdlib/src/schnorr.nr b/noir/noir_stdlib/src/schnorr.nr index 5ed95096f97..025c3a0f921 100644 --- a/noir/noir_stdlib/src/schnorr.nr +++ b/noir/noir_stdlib/src/schnorr.nr @@ -1,7 +1,10 @@ #[foreign(schnorr_verify)] +// docs:start:schnorr_verify pub fn verify_signature( _public_key_x: Field, _public_key_y: Field, _signature: [u8; 64], _message: [u8; N] -) -> bool {} +) -> bool +// docs:end:schnorr_verify +{} diff --git a/noir/scripts/install_wasm-bindgen.sh b/noir/scripts/install_wasm-bindgen.sh index c6e85bac50b..f34ed4c0ad0 100755 --- a/noir/scripts/install_wasm-bindgen.sh +++ b/noir/scripts/install_wasm-bindgen.sh @@ -3,8 +3,12 @@ set -eu cd $(dirname "$0")/.. +# Install binstall +curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash + # Install wasm-bindgen-cli. if [ "$(wasm-bindgen --version | cut -d' ' -f2)" != "0.2.86" ]; then echo "Building wasm-bindgen..." - RUSTFLAGS="-Ctarget-feature=-crt-static" cargo install -f wasm-bindgen-cli --version 0.2.86 + cargo binstall wasm-bindgen-cli@0.2.86 --force --no-confirm fi + diff --git a/noir/test_programs/compile_failure/multiple_contracts/Nargo.toml b/noir/test_programs/compile_failure/multiple_contracts/Nargo.toml deleted file mode 100644 index d6e4e632f95..00000000000 --- a/noir/test_programs/compile_failure/multiple_contracts/Nargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[package] -name = "multiple_contracts" -type = "contract" -authors = [""] -[dependencies] diff --git a/noir/test_programs/compile_failure/multiple_contracts/src/main.nr b/noir/test_programs/compile_failure/multiple_contracts/src/main.nr deleted file mode 100644 index a6c49d75378..00000000000 --- a/noir/test_programs/compile_failure/multiple_contracts/src/main.nr +++ /dev/null @@ -1,3 +0,0 @@ -contract Foo {} - -contract Bar {} diff --git a/noir/test_programs/compile_success_empty/intrinsic_die/src/main.nr b/noir/test_programs/compile_success_empty/intrinsic_die/src/main.nr index 88f7a3634c1..8cac707dfea 100644 --- a/noir/test_programs/compile_success_empty/intrinsic_die/src/main.nr +++ b/noir/test_programs/compile_success_empty/intrinsic_die/src/main.nr @@ -1,8 +1,6 @@ use dep::std; // This test checks that we perform dead-instruction-elimination on intrinsic functions. fn main(x: Field) { - let bytes = x.to_be_bytes(32); - let hash = std::hash::pedersen_commitment([x]); let _p1 = std::scalar_mul::fixed_base_embedded_curve(x, 0); } diff --git a/noir/test_programs/compile_success_empty/trait_generics/src/main.nr b/noir/test_programs/compile_success_empty/trait_generics/src/main.nr index 9a3c54c3fa1..30b2e79d579 100644 --- a/noir/test_programs/compile_success_empty/trait_generics/src/main.nr +++ b/noir/test_programs/compile_success_empty/trait_generics/src/main.nr @@ -1,4 +1,3 @@ - fn main() { let xs: [Field; 1] = [3]; let ys: [u32; 1] = [3]; @@ -8,21 +7,21 @@ fn main() { assert_eq(15, sum_static(Data { a: 5, b: 10 })); } -fn foo(x: T, u: U) where T: Into, U: Eq { +fn foo(x: T, u: U) where T: MyInto, U: Eq { assert(x.into() == u); } -trait Into { +trait MyInto { fn into(self) -> T; } -impl Into<[U; N]> for [T; N] where T: Into { +impl MyInto<[U; N]> for [T; N] where T: MyInto { fn into(self) -> [U; N] { self.map(|x: T| x.into()) } } -impl Into for Field { +impl MyInto for Field { fn into(self) -> u32 { self as u32 } diff --git a/noir/test_programs/execution_success/databus/src/main.nr b/noir/test_programs/execution_success/databus/src/main.nr index 631331ef2d7..61a9637f5fe 100644 --- a/noir/test_programs/execution_success/databus/src/main.nr +++ b/noir/test_programs/execution_success/databus/src/main.nr @@ -1,10 +1,12 @@ -// Test unsafe integer multiplication with overflow: 12^8 = 429 981 696 -// The circuit should handle properly the growth of the bit size use dep::std; -fn main(mut x: u32, y: call_data u32, z: call_data [u32;4] ) -> return_data u32 { - -let a = z[x]; - a+y +fn main(mut x: u32, y: call_data u32, z: call_data [u32;4]) -> return_data u32 { + let a = z[x]; + a+foo(y) +} +// Use an unconstrained function to force the compiler to avoid inlining +unconstrained fn foo(x: u32) -> u32 { + x+1 } + diff --git a/noir/test_programs/execution_success/keccak256/src/main.nr b/noir/test_programs/execution_success/keccak256/src/main.nr index ff2167694d6..eb401fe614c 100644 --- a/noir/test_programs/execution_success/keccak256/src/main.nr +++ b/noir/test_programs/execution_success/keccak256/src/main.nr @@ -1,5 +1,4 @@ -// Keccak256 example -// +// docs:start:keccak256 use dep::std; fn main(x: Field, result: [u8; 32]) { @@ -7,7 +6,8 @@ fn main(x: Field, result: [u8; 32]) { // The padding is taken care of by the program let digest = std::hash::keccak256([x as u8], 1); assert(digest == result); - //#1399: variable meesage size + + //#1399: variable message size let message_size = 4; let hash_a = std::hash::keccak256([1, 2, 3, 4], message_size); let hash_b = std::hash::keccak256([1, 2, 3, 4, 0, 0, 0, 0], message_size); @@ -19,3 +19,4 @@ fn main(x: Field, result: [u8; 32]) { assert(hash_a != hash_c); } +// docs:end:keccak256 diff --git a/noir/test_programs/execution_success/pedersen_commitment/Nargo.toml b/noir/test_programs/execution_success/pedersen_commitment/Nargo.toml new file mode 100644 index 00000000000..e257ce252d8 --- /dev/null +++ b/noir/test_programs/execution_success/pedersen_commitment/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "pedersen_commitment" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/pedersen_commitment/Prover.toml b/noir/test_programs/execution_success/pedersen_commitment/Prover.toml new file mode 100644 index 00000000000..6ad8c6bca57 --- /dev/null +++ b/noir/test_programs/execution_success/pedersen_commitment/Prover.toml @@ -0,0 +1,6 @@ +x = "0" +y = "1" + +[expected_commitment] +x = "0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402" +y = "0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126" diff --git a/noir/test_programs/execution_success/pedersen_commitment/src/main.nr b/noir/test_programs/execution_success/pedersen_commitment/src/main.nr new file mode 100644 index 00000000000..83cbe20851d --- /dev/null +++ b/noir/test_programs/execution_success/pedersen_commitment/src/main.nr @@ -0,0 +1,10 @@ +// docs:start:pedersen-commitment +use dep::std; + +fn main(x: Field, y: Field, expected_commitment: std::hash::PedersenPoint) { + let commitment = std::hash::pedersen_commitment([x, y]); + assert_eq(commitment.x, expected_commitment.x); + assert_eq(commitment.y, expected_commitment.y); +} +// docs:end:pedersen-commitment + diff --git a/noir/test_programs/execution_success/pedersen_hash/Nargo.toml b/noir/test_programs/execution_success/pedersen_hash/Nargo.toml new file mode 100644 index 00000000000..6248a96b3c9 --- /dev/null +++ b/noir/test_programs/execution_success/pedersen_hash/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "pedersen_hash" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/pedersen_hash/Prover.toml b/noir/test_programs/execution_success/pedersen_hash/Prover.toml new file mode 100644 index 00000000000..931b121fa6a --- /dev/null +++ b/noir/test_programs/execution_success/pedersen_hash/Prover.toml @@ -0,0 +1,4 @@ +x = "0" +y = "1" + +expected_hash = "0x0d98561fb02ca04d00801dfdc118b2a24cea0351963587712a28d368041370e1" diff --git a/noir/test_programs/execution_success/pedersen_hash/src/main.nr b/noir/test_programs/execution_success/pedersen_hash/src/main.nr new file mode 100644 index 00000000000..20c7de12d6c --- /dev/null +++ b/noir/test_programs/execution_success/pedersen_hash/src/main.nr @@ -0,0 +1,9 @@ +// docs:start:pedersen-hash +use dep::std; + +fn main(x: Field, y: Field, expected_hash: Field) { + let hash = std::hash::pedersen_hash([x, y]); + assert_eq(hash, expected_hash); +} +// docs:end:pedersen-hash + diff --git a/noir/test_programs/execution_success/poseidon_bn254_hash/src/main.nr b/noir/test_programs/execution_success/poseidon_bn254_hash/src/main.nr index 3d30ebad279..e742a440d1c 100644 --- a/noir/test_programs/execution_success/poseidon_bn254_hash/src/main.nr +++ b/noir/test_programs/execution_success/poseidon_bn254_hash/src/main.nr @@ -1,3 +1,4 @@ +// docs:start:poseidon use dep::std::hash::poseidon; fn main(x1: [Field; 2], y1: pub Field, x2: [Field; 4], y2: pub Field) { @@ -7,3 +8,4 @@ fn main(x1: [Field; 2], y1: pub Field, x2: [Field; 4], y2: pub Field) { let hash2 = poseidon::bn254::hash_4(x2); assert(hash2 == y2); } +// docs:end:poseidon diff --git a/noir/test_programs/execution_success/regression_4088/Nargo.toml b/noir/test_programs/execution_success/regression_4088/Nargo.toml new file mode 100644 index 00000000000..a5e7832b734 --- /dev/null +++ b/noir/test_programs/execution_success/regression_4088/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "regression_4088" +type = "bin" +authors = [""] +[dependencies] diff --git a/noir/test_programs/execution_success/regression_4088/Prover.toml b/noir/test_programs/execution_success/regression_4088/Prover.toml new file mode 100644 index 00000000000..839e31e7e40 --- /dev/null +++ b/noir/test_programs/execution_success/regression_4088/Prover.toml @@ -0,0 +1,2 @@ +[note] +value = 0 diff --git a/noir/test_programs/execution_success/regression_4088/src/main.nr b/noir/test_programs/execution_success/regression_4088/src/main.nr new file mode 100644 index 00000000000..9e4d7892fc3 --- /dev/null +++ b/noir/test_programs/execution_success/regression_4088/src/main.nr @@ -0,0 +1,27 @@ +trait Serialize { + fn serialize(self) -> [Field; N]; +} + +struct ValueNote { + value: Field, +} + +impl Serialize<1> for ValueNote { + fn serialize(self) -> [Field; 1] { + [self.value] + } +} + +fn check(serialized_note: [Field; N]) { + assert(serialized_note[0] == 0); +} + +fn oopsie(note: Note) where Note: Serialize { + let serialized_note = Note::serialize(note); + + check(serialized_note) +} + +fn main(mut note: ValueNote) { + oopsie(note); +} diff --git a/noir/test_programs/execution_success/regression_4124/Nargo.toml b/noir/test_programs/execution_success/regression_4124/Nargo.toml new file mode 100644 index 00000000000..9b97d1ce087 --- /dev/null +++ b/noir/test_programs/execution_success/regression_4124/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "regression_4124" +type = "bin" +authors = [""] +compiler_version = ">=0.22.0" + +[dependencies] diff --git a/noir/test_programs/execution_success/regression_4124/Prover.toml b/noir/test_programs/execution_success/regression_4124/Prover.toml new file mode 100644 index 00000000000..533d1af92b9 --- /dev/null +++ b/noir/test_programs/execution_success/regression_4124/Prover.toml @@ -0,0 +1 @@ +value = 0 diff --git a/noir/test_programs/execution_success/regression_4124/src/main.nr b/noir/test_programs/execution_success/regression_4124/src/main.nr new file mode 100644 index 00000000000..b47bf28d461 --- /dev/null +++ b/noir/test_programs/execution_success/regression_4124/src/main.nr @@ -0,0 +1,39 @@ +use dep::std::option::Option; + +trait MyDeserialize { + fn deserialize(fields: [Field; N]) -> Self; +} + +impl MyDeserialize<1> for Field { + fn deserialize(fields: [Field; 1]) -> Self { + fields[0] + } +} + +pub fn storage_read() -> [Field; N] { + dep::std::unsafe::zeroed() +} + +struct PublicState { + storage_slot: Field, +} + +impl PublicState { + pub fn new(storage_slot: Field) -> Self { + assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); + PublicState { storage_slot } + } + + pub fn read(_self: Self) -> T where T: MyDeserialize { + // storage_read returns slice here + let fields: [Field; T_SERIALIZED_LEN] = storage_read(); + T::deserialize(fields) + } +} + +fn main(value: Field) { + let ps: PublicState = PublicState::new(27); + + // error here + assert(ps.read() == value); +} diff --git a/noir/test_programs/execution_success/to_le_bytes/Prover.toml b/noir/test_programs/execution_success/to_le_bytes/Prover.toml index 07fe857ac7c..bf58776d557 100644 --- a/noir/test_programs/execution_success/to_le_bytes/Prover.toml +++ b/noir/test_programs/execution_success/to_le_bytes/Prover.toml @@ -1 +1,2 @@ x = "2040124" +cond = false \ No newline at end of file diff --git a/noir/test_programs/execution_success/to_le_bytes/src/main.nr b/noir/test_programs/execution_success/to_le_bytes/src/main.nr index 05eefc0f143..a0b48efe528 100644 --- a/noir/test_programs/execution_success/to_le_bytes/src/main.nr +++ b/noir/test_programs/execution_success/to_le_bytes/src/main.nr @@ -1,4 +1,4 @@ -fn main(x: Field) -> pub [u8; 31] { +fn main(x: Field, cond: bool) -> pub [u8; 31] { // The result of this byte array will be little-endian let byte_array = x.to_le_bytes(31); assert(byte_array.len() == 31); @@ -7,5 +7,12 @@ fn main(x: Field) -> pub [u8; 31] { for i in 0..31 { bytes[i] = byte_array[i]; } + + if cond { + // We've set x = "2040124" so we shouldn't be able to represent this as a single byte. + let bad_byte_array = x.to_le_bytes(1); + assert_eq(bad_byte_array.len(), 1); + } + bytes } diff --git a/noir/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml b/noir/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml new file mode 100644 index 00000000000..e535c113f20 --- /dev/null +++ b/noir/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "out_of_bounds_alignment" +type = "bin" +authors = [""] +[dependencies] diff --git a/noir/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml b/noir/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/noir/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr b/noir/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr new file mode 100644 index 00000000000..a47ab37eb31 --- /dev/null +++ b/noir/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr @@ -0,0 +1,17 @@ +fn out_of_bounds(arr_1: [Field; 50]) -> Field { + arr_1[50 + 1] +} + +unconstrained fn out_of_bounds_unconstrained_wrapper(arr_1: [Field; 50], arr_2: [Field; 50]) -> Field { + out_of_bounds(arr_1) +} + +#[test(should_fail)] +fn test_acir() { + assert_eq(out_of_bounds([0; 50]), 0); +} + +#[test(should_fail)] +fn test_brillig() { + assert_eq(out_of_bounds_unconstrained_wrapper([0; 50], [0; 50]), 0); +} diff --git a/noir/test_programs/noir_test_success/regression_4080/Nargo.toml b/noir/test_programs/noir_test_success/regression_4080/Nargo.toml new file mode 100644 index 00000000000..a38baf389d6 --- /dev/null +++ b/noir/test_programs/noir_test_success/regression_4080/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "regression_4080" +type = "bin" +authors = [""] +[dependencies] diff --git a/noir/test_programs/noir_test_success/regression_4080/Prover.toml b/noir/test_programs/noir_test_success/regression_4080/Prover.toml new file mode 100644 index 00000000000..0e5dfd5638d --- /dev/null +++ b/noir/test_programs/noir_test_success/regression_4080/Prover.toml @@ -0,0 +1 @@ +x = "5" diff --git a/noir/test_programs/noir_test_success/regression_4080/src/main.nr b/noir/test_programs/noir_test_success/regression_4080/src/main.nr new file mode 100644 index 00000000000..781d3e33ea3 --- /dev/null +++ b/noir/test_programs/noir_test_success/regression_4080/src/main.nr @@ -0,0 +1,8 @@ +// This test checks that `var^var` is assigned the correct type. +// https://github.com/noir-lang/noir/issues/4080 + +#[test(should_fail_with = "attempt to add with overflow")] +fn main() { + let var1: u8 = ((255 + 1) ^ (255 + 1)) - ((255 + 1) - (255 + 1)); + assert_eq(var1, 0); +} diff --git a/noir/tooling/debugger/src/repl.rs b/noir/tooling/debugger/src/repl.rs index b1af2bc2686..40ee6efdb86 100644 --- a/noir/tooling/debugger/src/repl.rs +++ b/noir/tooling/debugger/src/repl.rs @@ -53,7 +53,15 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { Some(location) => { match location { OpcodeLocation::Acir(ip) => { - println!("At opcode {}: {}", ip, opcodes[ip]) + // Default Brillig display is too bloated for this context, + // so we limit it to denoting it's the start of a Brillig + // block. The user can still use the `opcodes` command to + // take a look at the whole block. + let opcode_summary = match opcodes[ip] { + Opcode::Brillig(..) => "BRILLIG: ...".into(), + _ => format!("{}", opcodes[ip]), + }; + println!("At opcode {}: {}", ip, opcode_summary); } OpcodeLocation::Brillig { acir_index, brillig_index } => { let Opcode::Brillig(ref brillig) = opcodes[acir_index] else { diff --git a/noir/tooling/lsp/src/lib.rs b/noir/tooling/lsp/src/lib.rs index b64fc474b0b..a0e024c70fd 100644 --- a/noir/tooling/lsp/src/lib.rs +++ b/noir/tooling/lsp/src/lib.rs @@ -4,11 +4,12 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies, unused_extern_crates))] use std::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, future::Future, ops::{self, ControlFlow}, path::{Path, PathBuf}, pin::Pin, + str::FromStr, task::{self, Poll}, }; @@ -20,7 +21,11 @@ use async_lsp::{ use fm::{codespan_files as files, FileManager}; use fxhash::FxHashSet; use lsp_types::CodeLens; -use nargo::{parse_all, workspace::Workspace}; +use nargo::{ + package::{Package, PackageType}, + parse_all, + workspace::Workspace, +}; use nargo_toml::{find_file_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{file_manager_with_stdlib, prepare_crate, NOIR_ARTIFACT_VERSION_STRING}; use noirc_frontend::{ @@ -209,23 +214,38 @@ fn byte_span_to_range<'a, F: files::Files<'a> + ?Sized>( } pub(crate) fn resolve_workspace_for_source_path(file_path: &Path) -> Result { - let package_root = find_file_manifest(file_path); - - let toml_path = package_root.ok_or_else(|| { - LspError::WorkspaceResolutionError(format!( - "Nargo.toml not found for file: {:?}", - file_path - )) - })?; - - let workspace = resolve_workspace_from_toml( - &toml_path, - PackageSelection::All, - Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), - ) - .map_err(|err| LspError::WorkspaceResolutionError(err.to_string()))?; - - Ok(workspace) + if let Some(toml_path) = find_file_manifest(file_path) { + resolve_workspace_from_toml( + &toml_path, + PackageSelection::All, + Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), + ) + .map_err(|err| LspError::WorkspaceResolutionError(err.to_string())) + } else { + let Some(parent_folder) = file_path.parent().and_then(|f| f.file_name()).and_then(|file_name_os_str| file_name_os_str.to_str()) else { + return Err(LspError::WorkspaceResolutionError(format!( + "Could not resolve parent folder for file: {:?}", + file_path + ))) + }; + let assumed_package = Package { + version: None, + compiler_required_version: Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), + root_dir: PathBuf::from(parent_folder), + package_type: PackageType::Binary, + entry_path: PathBuf::from(file_path), + name: CrateName::from_str(parent_folder) + .map_err(|err| LspError::WorkspaceResolutionError(err.to_string()))?, + dependencies: BTreeMap::new(), + }; + let workspace = Workspace { + root_dir: PathBuf::from(parent_folder), + members: vec![assumed_package], + selected_package_index: Some(0), + is_assumed: true, + }; + Ok(workspace) + } } /// Prepares a package from a source string diff --git a/noir/tooling/lsp/src/requests/profile_run.rs b/noir/tooling/lsp/src/requests/profile_run.rs index 8ba91338f55..d866be8988b 100644 --- a/noir/tooling/lsp/src/requests/profile_run.rs +++ b/noir/tooling/lsp/src/requests/profile_run.rs @@ -64,26 +64,32 @@ fn on_profile_run_request_inner( &workspace_file_manager, &parsed_files, &workspace, - expression_width, &CompileOptions::default(), ) .map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?; let mut opcodes_counts: HashMap = HashMap::new(); let mut file_map: BTreeMap = BTreeMap::new(); - for compiled_program in &compiled_programs { + for compiled_program in compiled_programs { + let compiled_program = + nargo::ops::transform_program(compiled_program, expression_width); + let span_opcodes = compiled_program.debug.count_span_opcodes(); let debug_artifact: DebugArtifact = compiled_program.clone().into(); opcodes_counts.extend(span_opcodes); file_map.extend(debug_artifact.file_map); } - for compiled_contract in &compiled_contracts { - let functions = &compiled_contract.functions; - let debug_artifact: DebugArtifact = compiled_contract.clone().into(); + for compiled_contract in compiled_contracts { + let compiled_contract = + nargo::ops::transform_contract(compiled_contract, expression_width); + + let function_debug_info: Vec<_> = + compiled_contract.functions.iter().map(|func| &func.debug).cloned().collect(); + let debug_artifact: DebugArtifact = compiled_contract.into(); file_map.extend(debug_artifact.file_map); - for contract_function in functions { - let span_opcodes = contract_function.debug.count_span_opcodes(); + for contract_function_debug in function_debug_info { + let span_opcodes = contract_function_debug.count_span_opcodes(); opcodes_counts.extend(span_opcodes); } } diff --git a/noir/tooling/nargo/src/artifacts/debug.rs b/noir/tooling/nargo/src/artifacts/debug.rs index 3f5df801b66..2e2d98f279e 100644 --- a/noir/tooling/nargo/src/artifacts/debug.rs +++ b/noir/tooling/nargo/src/artifacts/debug.rs @@ -126,18 +126,18 @@ impl From for DebugArtifact { } } -impl From<&CompiledContract> for DebugArtifact { - fn from(compiled_artifact: &CompiledContract) -> Self { +impl From for DebugArtifact { + fn from(compiled_artifact: CompiledContract) -> Self { let all_functions_debug: Vec = compiled_artifact .functions - .iter() - .map(|contract_function| contract_function.debug.clone()) + .into_iter() + .map(|contract_function| contract_function.debug) .collect(); DebugArtifact { debug_symbols: all_functions_debug, - file_map: compiled_artifact.file_map.clone(), - warnings: compiled_artifact.warnings.clone(), + file_map: compiled_artifact.file_map, + warnings: compiled_artifact.warnings, } } } diff --git a/noir/tooling/nargo/src/ops/compile.rs b/noir/tooling/nargo/src/ops/compile.rs index 866bfe39d7b..dccd2cedbf5 100644 --- a/noir/tooling/nargo/src/ops/compile.rs +++ b/noir/tooling/nargo/src/ops/compile.rs @@ -1,4 +1,3 @@ -use acvm::ExpressionWidth; use fm::FileManager; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; use noirc_frontend::hir::ParsedFiles; @@ -18,7 +17,6 @@ pub fn compile_workspace( file_manager: &FileManager, parsed_files: &ParsedFiles, workspace: &Workspace, - expression_width: ExpressionWidth, compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CompileError> { let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace @@ -30,22 +28,11 @@ pub fn compile_workspace( // Compile all of the packages in parallel. let program_results: Vec> = binary_packages .par_iter() - .map(|package| { - compile_program( - file_manager, - parsed_files, - package, - compile_options, - expression_width, - None, - ) - }) + .map(|package| compile_program(file_manager, parsed_files, package, compile_options, None)) .collect(); let contract_results: Vec> = contract_packages .par_iter() - .map(|package| { - compile_contract(file_manager, parsed_files, package, compile_options, expression_width) - }) + .map(|package| compile_contract(file_manager, parsed_files, package, compile_options)) .collect(); // Report any warnings/errors which were encountered during compilation. @@ -80,18 +67,10 @@ pub fn compile_program( parsed_files: &ParsedFiles, package: &Package, compile_options: &CompileOptions, - expression_width: ExpressionWidth, cached_program: Option, ) -> CompilationResult { let (mut context, crate_id) = prepare_package(file_manager, parsed_files, package); - - let (program, warnings) = - noirc_driver::compile_main(&mut context, crate_id, compile_options, cached_program)?; - - // Apply backend specific optimizations. - let optimized_program = crate::ops::optimize_program(program, expression_width); - - Ok((optimized_program, warnings)) + noirc_driver::compile_main(&mut context, crate_id, compile_options, cached_program) } pub fn compile_contract( @@ -99,15 +78,9 @@ pub fn compile_contract( parsed_files: &ParsedFiles, package: &Package, compile_options: &CompileOptions, - expression_width: ExpressionWidth, ) -> CompilationResult { let (mut context, crate_id) = prepare_package(file_manager, parsed_files, package); - let (contract, warnings) = - noirc_driver::compile_contract(&mut context, crate_id, compile_options)?; - - let optimized_contract = crate::ops::optimize_contract(contract, expression_width); - - Ok((optimized_contract, warnings)) + noirc_driver::compile_contract(&mut context, crate_id, compile_options) } pub(crate) fn report_errors( diff --git a/noir/tooling/nargo/src/ops/foreign_calls.rs b/noir/tooling/nargo/src/ops/foreign_calls.rs index cbe40c92b4e..e3a3174f8dc 100644 --- a/noir/tooling/nargo/src/ops/foreign_calls.rs +++ b/noir/tooling/nargo/src/ops/foreign_calls.rs @@ -82,8 +82,8 @@ impl MockedCall { } impl MockedCall { - fn matches(&self, name: &str, params: &Vec) -> bool { - self.name == name && (self.params.is_none() || self.params.as_ref() == Some(params)) + fn matches(&self, name: &str, params: &[ForeignCallParam]) -> bool { + self.name == name && (self.params.is_none() || self.params.as_deref() == Some(params)) } } diff --git a/noir/tooling/nargo/src/ops/mod.rs b/noir/tooling/nargo/src/ops/mod.rs index 4912c84839e..4f92faa73a4 100644 --- a/noir/tooling/nargo/src/ops/mod.rs +++ b/noir/tooling/nargo/src/ops/mod.rs @@ -2,6 +2,8 @@ pub use self::compile::{compile_contract, compile_program, compile_workspace}; pub use self::execute::execute_circuit; pub use self::foreign_calls::{DefaultForeignCallExecutor, ForeignCallExecutor}; pub use self::optimize::{optimize_contract, optimize_program}; +pub use self::transform::{transform_contract, transform_program}; + pub use self::test::{run_test, TestStatus}; mod compile; @@ -9,3 +11,4 @@ mod execute; mod foreign_calls; mod optimize; mod test; +mod transform; diff --git a/noir/tooling/nargo/src/ops/optimize.rs b/noir/tooling/nargo/src/ops/optimize.rs index d3a36dd65ac..2d0c4c43d25 100644 --- a/noir/tooling/nargo/src/ops/optimize.rs +++ b/noir/tooling/nargo/src/ops/optimize.rs @@ -1,26 +1,16 @@ -use acvm::ExpressionWidth; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; -pub fn optimize_program( - mut program: CompiledProgram, - expression_width: ExpressionWidth, -) -> CompiledProgram { - let (optimized_circuit, location_map) = - acvm::compiler::compile(program.circuit, expression_width); - +pub fn optimize_program(mut program: CompiledProgram) -> CompiledProgram { + let (optimized_circuit, location_map) = acvm::compiler::optimize(program.circuit); program.circuit = optimized_circuit; program.debug.update_acir(location_map); program } -pub fn optimize_contract( - contract: CompiledContract, - expression_width: ExpressionWidth, -) -> CompiledContract { +pub fn optimize_contract(contract: CompiledContract) -> CompiledContract { let functions = vecmap(contract.functions, |mut func| { - let (optimized_bytecode, location_map) = - acvm::compiler::compile(func.bytecode, expression_width); + let (optimized_bytecode, location_map) = acvm::compiler::optimize(func.bytecode); func.bytecode = optimized_bytecode; func.debug.update_acir(location_map); func diff --git a/noir/tooling/nargo/src/ops/transform.rs b/noir/tooling/nargo/src/ops/transform.rs new file mode 100644 index 00000000000..f3efd82333e --- /dev/null +++ b/noir/tooling/nargo/src/ops/transform.rs @@ -0,0 +1,30 @@ +use acvm::ExpressionWidth; +use iter_extended::vecmap; +use noirc_driver::{CompiledContract, CompiledProgram}; + +pub fn transform_program( + mut program: CompiledProgram, + expression_width: ExpressionWidth, +) -> CompiledProgram { + let (optimized_circuit, location_map) = + acvm::compiler::compile(program.circuit, expression_width); + + program.circuit = optimized_circuit; + program.debug.update_acir(location_map); + program +} + +pub fn transform_contract( + contract: CompiledContract, + expression_width: ExpressionWidth, +) -> CompiledContract { + let functions = vecmap(contract.functions, |mut func| { + let (optimized_bytecode, location_map) = + acvm::compiler::compile(func.bytecode, expression_width); + func.bytecode = optimized_bytecode; + func.debug.update_acir(location_map); + func + }); + + CompiledContract { functions, ..contract } +} diff --git a/noir/tooling/nargo/src/workspace.rs b/noir/tooling/nargo/src/workspace.rs index 5696a758531..0795ffd9304 100644 --- a/noir/tooling/nargo/src/workspace.rs +++ b/noir/tooling/nargo/src/workspace.rs @@ -20,6 +20,8 @@ pub struct Workspace { pub members: Vec, // If `Some()`, the `selected_package_index` is used to select the only `Package` when iterating a Workspace pub selected_package_index: Option, + /// If we could not resolve the workspace we would inform the user we have assumed it (ie. from lsp file path given) + pub is_assumed: bool, } impl Workspace { diff --git a/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index 8bf12ee4100..63d27e30836 100644 --- a/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -1,12 +1,11 @@ +use super::fs::{create_named_dir, write_to_file}; use super::NargoConfig; -use super::{ - compile_cmd::compile_bin_package, - fs::{create_named_dir, write_to_file}, -}; use crate::backends::Backend; +use crate::cli::compile_cmd::report_errors; use crate::errors::CliError; use clap::Args; +use nargo::ops::compile_program; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{file_manager_with_stdlib, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; @@ -47,15 +46,25 @@ pub(crate) fn run( let parsed_files = parse_all(&workspace_file_manager); let expression_width = backend.get_backend_info()?; - for package in &workspace { - let program = compile_bin_package( + let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); + for package in binary_packages { + let compilation_result = compile_program( &workspace_file_manager, &parsed_files, package, &args.compile_options, - expression_width, + None, + ); + + let program = report_errors( + compilation_result, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; + let program = nargo::ops::transform_program(program, expression_width); + let smart_contract_string = backend.eth_contract(&program.circuit)?; let contract_dir = workspace.contracts_directory_path(package); diff --git a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/tooling/nargo_cli/src/cli/compile_cmd.rs index aa9a46f39ef..34fb05249b5 100644 --- a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,7 +1,5 @@ use std::path::Path; -use acvm::ExpressionWidth; - use fm::FileManager; use nargo::artifacts::program::ProgramArtifact; use nargo::errors::CompileError; @@ -63,12 +61,14 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info_or_default(); + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let (compiled_program, compiled_contracts) = compile_workspace( &workspace_file_manager, &parsed_files, &workspace, - expression_width, &args.compile_options, )?; @@ -81,9 +81,11 @@ pub(crate) fn run( // Save build artifacts to disk. let only_acir = args.compile_options.only_acir; for (package, program) in binary_packages.into_iter().zip(compiled_program) { + let program = nargo::ops::transform_program(program, expression_width); save_program(program.clone(), &package, &workspace.target_directory_path(), only_acir); } for (package, contract) in contract_packages.into_iter().zip(compiled_contracts) { + let contract = nargo::ops::transform_contract(contract, expression_width); save_contract(contract, &package, &circuit_dir); } @@ -94,7 +96,6 @@ pub(super) fn compile_workspace( file_manager: &FileManager, parsed_files: &ParsedFiles, workspace: &Workspace, - expression_width: ExpressionWidth, compile_options: &CompileOptions, ) -> Result<(Vec, Vec), CliError> { let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace @@ -114,21 +115,12 @@ pub(super) fn compile_workspace( .filter(|p| p.noir_version == NOIR_ARTIFACT_VERSION_STRING) .map(|p| p.into()); - compile_program( - file_manager, - parsed_files, - package, - compile_options, - expression_width, - cached_program, - ) + compile_program(file_manager, parsed_files, package, compile_options, cached_program) }) .collect(); let contract_results: Vec> = contract_packages .par_iter() - .map(|package| { - compile_contract(file_manager, parsed_files, package, compile_options, expression_width) - }) + .map(|package| compile_contract(file_manager, parsed_files, package, compile_options)) .collect(); // Report any warnings/errors which were encountered during compilation. @@ -158,36 +150,6 @@ pub(super) fn compile_workspace( Ok((compiled_programs, compiled_contracts)) } -pub(crate) fn compile_bin_package( - file_manager: &FileManager, - parsed_files: &ParsedFiles, - package: &Package, - compile_options: &CompileOptions, - expression_width: ExpressionWidth, -) -> Result { - if package.is_library() { - return Err(CompileError::LibraryCrate(package.name.clone()).into()); - } - - let compilation_result = compile_program( - file_manager, - parsed_files, - package, - compile_options, - expression_width, - None, - ); - - let program = report_errors( - compilation_result, - file_manager, - compile_options.deny_warnings, - compile_options.silence_warnings, - )?; - - Ok(program) -} - pub(super) fn save_program( program: CompiledProgram, package: &Package, diff --git a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs b/noir/tooling/nargo_cli/src/cli/dap_cmd.rs index 9798cbedfeb..67322b1873e 100644 --- a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -1,7 +1,9 @@ use acvm::acir::native_types::WitnessMap; +use acvm::ExpressionWidth; use backend_interface::Backend; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; +use nargo::ops::compile_program; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -21,14 +23,28 @@ use dap::server::Server; use dap::types::Capabilities; use serde_json::Value; -use super::compile_cmd::compile_bin_package; +use super::compile_cmd::report_errors; use super::fs::inputs::read_inputs_from_file; use crate::errors::CliError; use super::NargoConfig; #[derive(Debug, Clone, Args)] -pub(crate) struct DapCommand; +pub(crate) struct DapCommand { + /// Override the expression width requested by the backend. + #[arg(long, value_parser = parse_expression_width)] + expression_width: Option, +} + +fn parse_expression_width(input: &str) -> Result { + use std::io::{Error, ErrorKind}; + + let width = input + .parse::() + .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; + + Ok(ExpressionWidth::from(width)) +} struct LoadError(&'static str); @@ -53,16 +69,14 @@ fn find_workspace(project_folder: &str, package: Option<&str>) -> Option, prover_name: &str, + expression_width: ExpressionWidth, ) -> Result<(CompiledProgram, WitnessMap), LoadError> { let workspace = find_workspace(project_folder, package).ok_or(LoadError("Cannot open workspace"))?; - let expression_width = - backend.get_backend_info().map_err(|_| LoadError("Failed to get backend info"))?; let package = workspace .into_iter() .find(|p| p.is_binary()) @@ -72,15 +86,20 @@ fn load_and_compile_project( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let compiled_program = compile_bin_package( + let compile_options = CompileOptions::default(); + let compilation_result = + compile_program(&workspace_file_manager, &parsed_files, package, &compile_options, None); + + let compiled_program = report_errors( + compilation_result, &workspace_file_manager, - &parsed_files, - package, - &CompileOptions::default(), - expression_width, + compile_options.deny_warnings, + compile_options.silence_warnings, ) .map_err(|_| LoadError("Failed to compile project"))?; + let compiled_program = nargo::ops::transform_program(compiled_program, expression_width); + let (inputs_map, _) = read_inputs_from_file(&package.root_dir, prover_name, Format::Toml, &compiled_program.abi) .map_err(|_| LoadError("Failed to read program inputs"))?; @@ -94,7 +113,7 @@ fn load_and_compile_project( fn loop_uninitialized_dap( mut server: Server, - backend: &Backend, + expression_width: ExpressionWidth, ) -> Result<(), ServerError> { loop { let req = match server.poll_request()? { @@ -134,7 +153,12 @@ fn loop_uninitialized_dap( eprintln!("Package: {}", package.unwrap_or("(default)")); eprintln!("Prover name: {}", prover_name); - match load_and_compile_project(backend, project_folder, package, prover_name) { + match load_and_compile_project( + project_folder, + package, + prover_name, + expression_width, + ) { Ok((compiled_program, initial_witness)) => { server.respond(req.ack()?)?; @@ -170,12 +194,15 @@ fn loop_uninitialized_dap( pub(crate) fn run( backend: &Backend, - _args: DapCommand, + args: DapCommand, _config: NargoConfig, ) -> Result<(), CliError> { let output = BufWriter::new(std::io::stdout()); let input = BufReader::new(std::io::stdin()); let server = Server::new(input, output); - loop_uninitialized_dap(server, backend).map_err(CliError::DapError) + let expression_width = + args.expression_width.unwrap_or_else(|| backend.get_backend_info_or_default()); + + loop_uninitialized_dap(server, expression_width).map_err(CliError::DapError) } diff --git a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs b/noir/tooling/nargo_cli/src/cli/debug_cmd.rs index e62cbc11ec8..a0bac3bdac1 100644 --- a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -6,6 +6,7 @@ use clap::Args; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; +use nargo::ops::compile_program; use nargo::package::Package; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -16,7 +17,7 @@ use noirc_driver::{ }; use noirc_frontend::graph::CrateName; -use super::compile_cmd::compile_bin_package; +use super::compile_cmd::report_errors; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; use super::NargoConfig; use crate::backends::Backend; @@ -53,7 +54,10 @@ pub(crate) fn run( Some(NOIR_ARTIFACT_VERSION_STRING.to_string()), )?; let target_dir = &workspace.target_directory_path(); - let expression_width = backend.get_backend_info()?; + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let mut workspace_file_manager = file_manager_with_stdlib(std::path::Path::new("")); insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); @@ -66,14 +70,23 @@ pub(crate) fn run( return Ok(()); }; - let compiled_program = compile_bin_package( + let compilation_result = compile_program( &workspace_file_manager, &parsed_files, package, &args.compile_options, - expression_width, + None, + ); + + let compiled_program = report_errors( + compilation_result, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; + let compiled_program = nargo::ops::transform_program(compiled_program, expression_width); + run_async(package, compiled_program, &args.prover_name, &args.witness_name, target_dir) } diff --git a/noir/tooling/nargo_cli/src/cli/execute_cmd.rs b/noir/tooling/nargo_cli/src/cli/execute_cmd.rs index cf0d46a0718..a3fcebab94f 100644 --- a/noir/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -5,7 +5,7 @@ use clap::Args; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; use nargo::errors::try_to_diagnose_runtime_error; -use nargo::ops::DefaultForeignCallExecutor; +use nargo::ops::{compile_program, DefaultForeignCallExecutor}; use nargo::package::Package; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -16,10 +16,10 @@ use noirc_driver::{ }; use noirc_frontend::graph::CrateName; -use super::compile_cmd::compile_bin_package; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; use super::NargoConfig; use crate::backends::Backend; +use crate::cli::compile_cmd::report_errors; use crate::errors::CliError; /// Executes a circuit to calculate its return value @@ -68,16 +68,29 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info_or_default(); - for package in &workspace { - let compiled_program = compile_bin_package( + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); + let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); + for package in binary_packages { + let compilation_result = compile_program( &workspace_file_manager, &parsed_files, package, &args.compile_options, - expression_width, + None, + ); + + let compiled_program = report_errors( + compilation_result, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; + let compiled_program = nargo::ops::transform_program(compiled_program, expression_width); + let (return_value, solved_witness) = execute_program_and_decode( compiled_program, package, diff --git a/noir/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/tooling/nargo_cli/src/cli/info_cmd.rs index 8dfff67b47f..131fd6ad214 100644 --- a/noir/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/info_cmd.rs @@ -69,24 +69,33 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info_or_default(); + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); let (compiled_programs, compiled_contracts) = compile_workspace( &workspace_file_manager, &parsed_files, &workspace, - expression_width, &args.compile_options, )?; + let compiled_programs = vecmap(compiled_programs, |program| { + nargo::ops::transform_program(program, expression_width) + }); + let compiled_contracts = vecmap(compiled_contracts, |contract| { + nargo::ops::transform_contract(contract, expression_width) + }); + if args.profile_info { for compiled_program in &compiled_programs { let span_opcodes = compiled_program.debug.count_span_opcodes(); - let debug_artifact: DebugArtifact = compiled_program.clone().into(); + let debug_artifact = DebugArtifact::from(compiled_program.clone()); print_span_opcodes(span_opcodes, &debug_artifact); } for compiled_contract in &compiled_contracts { - let debug_artifact: DebugArtifact = compiled_contract.clone().into(); + let debug_artifact = DebugArtifact::from(compiled_contract.clone()); let functions = &compiled_contract.functions; for contract_function in functions { let span_opcodes = contract_function.debug.count_span_opcodes(); diff --git a/noir/tooling/nargo_cli/src/cli/prove_cmd.rs b/noir/tooling/nargo_cli/src/cli/prove_cmd.rs index d02464fd6df..1d20e97af85 100644 --- a/noir/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -1,5 +1,6 @@ use clap::Args; use nargo::constants::{PROVER_INPUT_FILE, VERIFIER_INPUT_FILE}; +use nargo::ops::compile_program; use nargo::package::Package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; @@ -10,7 +11,7 @@ use noirc_driver::{ }; use noirc_frontend::graph::CrateName; -use super::compile_cmd::compile_bin_package; +use super::compile_cmd::report_errors; use super::fs::{ inputs::{read_inputs_from_file, write_inputs_to_file}, proof::save_proof_to_dir, @@ -68,21 +69,34 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info()?; - for package in &workspace { - let program = compile_bin_package( + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); + let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); + for package in binary_packages { + let compilation_result = compile_program( &workspace_file_manager, &parsed_files, package, &args.compile_options, - expression_width, + None, + ); + + let compiled_program = report_errors( + compilation_result, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; + let compiled_program = nargo::ops::transform_program(compiled_program, expression_width); + prove_package( backend, &workspace, package, - program, + compiled_program, &args.prover_name, &args.verifier_name, args.verify, diff --git a/noir/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/tooling/nargo_cli/src/cli/test_cmd.rs index 5db842609e5..9fee27b9172 100644 --- a/noir/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/test_cmd.rs @@ -83,22 +83,44 @@ pub(crate) fn run( }; let blackbox_solver = Bn254BlackBoxSolver::new(); - for package in &workspace { - // By unwrapping here with `?`, we stop the test runner upon a package failing - // TODO: We should run the whole suite even if there are failures in a package - run_tests( - &workspace_file_manager, - &parsed_files, - &blackbox_solver, - package, - pattern, - args.show_output, - args.oracle_resolver.as_deref(), - &args.compile_options, - )?; + + let test_reports: Vec> = workspace + .into_iter() + .map(|package| { + run_tests( + &workspace_file_manager, + &parsed_files, + &blackbox_solver, + package, + pattern, + args.show_output, + args.oracle_resolver.as_deref(), + &args.compile_options, + ) + }) + .collect::>()?; + let test_report: Vec<(String, TestStatus)> = test_reports.into_iter().flatten().collect(); + + if test_report.is_empty() { + match &pattern { + FunctionNameMatch::Exact(pattern) => { + return Err(CliError::Generic( + format!("Found 0 tests matching input '{pattern}'.",), + )) + } + FunctionNameMatch::Contains(pattern) => { + return Err(CliError::Generic(format!("Found 0 tests containing '{pattern}'.",))) + } + // If we are running all tests in a crate, having none is not an error + FunctionNameMatch::Anything => {} + }; } - Ok(()) + if test_report.iter().any(|(_, status)| !matches!(status, TestStatus::Fail { .. })) { + Ok(()) + } else { + Err(CliError::Generic(String::new())) + } } #[allow(clippy::too_many_arguments)] @@ -111,7 +133,7 @@ fn run_tests( show_output: bool, foreign_call_resolver_url: Option<&str>, compile_options: &CompileOptions, -) -> Result<(), CliError> { +) -> Result, CliError> { let (mut context, crate_id) = prepare_package(file_manager, parsed_files, package); check_crate_and_report_errors( &mut context, @@ -123,45 +145,29 @@ fn run_tests( let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, fn_name); let count_all = test_functions.len(); - if count_all == 0 { - match &fn_name { - FunctionNameMatch::Exact(pattern) => { - return Err(CliError::Generic(format!( - "[{}] Found 0 tests matching input '{pattern}'.", - package.name - ))) - } - FunctionNameMatch::Contains(pattern) => { - return Err(CliError::Generic(format!( - "[{}] Found 0 tests containing '{pattern}'.", - package.name - ))) - } - // If we are running all tests in a crate, having none is not an error - FunctionNameMatch::Anything => {} - }; - } let plural = if count_all == 1 { "" } else { "s" }; println!("[{}] Running {count_all} test function{plural}", package.name); - let mut count_failed = 0; let writer = StandardStream::stderr(ColorChoice::Always); let mut writer = writer.lock(); + let mut test_report: Vec<(String, TestStatus)> = Vec::new(); for (test_name, test_function) in test_functions { write!(writer, "[{}] Testing {test_name}... ", package.name) .expect("Failed to write to stderr"); writer.flush().expect("Failed to flush writer"); - match run_test( + let test_status = run_test( blackbox_solver, &context, test_function, show_output, foreign_call_resolver_url, compile_options, - ) { + ); + + match &test_status { TestStatus::Pass { .. } => { writer .set_color(ColorSpec::new().set_fg(Some(Color::Green))) @@ -176,35 +182,36 @@ fn run_tests( if let Some(diag) = error_diagnostic { noirc_errors::reporter::report_all( context.file_manager.as_file_map(), - &[diag], + &[diag.clone()], compile_options.deny_warnings, compile_options.silence_warnings, ); } - count_failed += 1; } TestStatus::CompileError(err) => { noirc_errors::reporter::report_all( context.file_manager.as_file_map(), - &[err], + &[err.clone()], compile_options.deny_warnings, compile_options.silence_warnings, ); - count_failed += 1; } } + + test_report.push((test_name, test_status)); + writer.reset().expect("Failed to reset writer"); } write!(writer, "[{}] ", package.name).expect("Failed to write to stderr"); + let count_failed = + test_report.iter().filter(|(_, status)| !matches!(status, TestStatus::Pass)).count(); if count_failed == 0 { writer.set_color(ColorSpec::new().set_fg(Some(Color::Green))).expect("Failed to set color"); write!(writer, "{count_all} test{plural} passed").expect("Failed to write to stderr"); writer.reset().expect("Failed to reset writer"); writeln!(writer).expect("Failed to write to stderr"); - - Ok(()) } else { let count_passed = count_all - count_failed; let plural_failed = if count_failed == 1 { "" } else { "s" }; @@ -219,11 +226,10 @@ fn run_tests( } writer.set_color(ColorSpec::new().set_fg(Some(Color::Red))).expect("Failed to set color"); - write!(writer, "{count_failed} test{plural_failed} failed") + writeln!(writer, "{count_failed} test{plural_failed} failed") .expect("Failed to write to stderr"); writer.reset().expect("Failed to reset writer"); - - // Writes final newline. - Err(CliError::Generic(String::new())) } + + Ok(test_report) } diff --git a/noir/tooling/nargo_cli/src/cli/verify_cmd.rs b/noir/tooling/nargo_cli/src/cli/verify_cmd.rs index 1701b9e063c..ea4aaa051bb 100644 --- a/noir/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -1,12 +1,11 @@ +use super::compile_cmd::report_errors; +use super::fs::{inputs::read_inputs_from_file, load_hex_data}; use super::NargoConfig; -use super::{ - compile_cmd::compile_bin_package, - fs::{inputs::read_inputs_from_file, load_hex_data}, -}; use crate::{backends::Backend, errors::CliError}; use clap::Args; use nargo::constants::{PROOF_EXT, VERIFIER_INPUT_FILE}; +use nargo::ops::compile_program; use nargo::package::Package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; @@ -55,17 +54,30 @@ pub(crate) fn run( insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = backend.get_backend_info()?; - for package in &workspace { - let program = compile_bin_package( + let expression_width = args + .compile_options + .expression_width + .unwrap_or_else(|| backend.get_backend_info_or_default()); + let binary_packages = workspace.into_iter().filter(|package| package.is_binary()); + for package in binary_packages { + let compilation_result = compile_program( &workspace_file_manager, &parsed_files, package, &args.compile_options, - expression_width, + None, + ); + + let compiled_program = report_errors( + compilation_result, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; - verify_package(backend, &workspace, package, program, &args.verifier_name)?; + let compiled_program = nargo::ops::transform_program(compiled_program, expression_width); + + verify_package(backend, &workspace, package, compiled_program, &args.verifier_name)?; } Ok(()) diff --git a/noir/tooling/nargo_toml/src/lib.rs b/noir/tooling/nargo_toml/src/lib.rs index cecc3f7e26a..985cb30dc24 100644 --- a/noir/tooling/nargo_toml/src/lib.rs +++ b/noir/tooling/nargo_toml/src/lib.rs @@ -345,6 +345,7 @@ fn toml_to_workspace( root_dir: nargo_toml.root_dir, selected_package_index: Some(0), members: vec![member], + is_assumed: false, }, } } @@ -392,7 +393,12 @@ fn toml_to_workspace( PackageSelection::All => (), } - Workspace { root_dir: nargo_toml.root_dir, members, selected_package_index } + Workspace { + root_dir: nargo_toml.root_dir, + members, + selected_package_index, + is_assumed: false, + } } }; diff --git a/noir/tooling/noir_js_backend_barretenberg/src/index.ts b/noir/tooling/noir_js_backend_barretenberg/src/index.ts index 6e619fd59cf..61094a3451f 100644 --- a/noir/tooling/noir_js_backend_barretenberg/src/index.ts +++ b/noir/tooling/noir_js_backend_barretenberg/src/index.ts @@ -1,11 +1,12 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import { decompressSync as gunzip } from 'fflate'; import { acirToUint8Array } from './serialize.js'; import { Backend, CompiledCircuit, ProofData } from '@noir-lang/types'; import { BackendOptions } from './types.js'; import { deflattenPublicInputs, flattenPublicInputsAsArray } from './public_inputs.js'; +import { type Barretenberg } from '@aztec/bb.js'; export { publicInputsToWitnessMap } from './public_inputs.js'; + // This is the number of bytes in a UltraPlonk proof // minus the public inputs. const numBytesInProofWithoutPublicInputs: number = 2144; @@ -15,12 +16,14 @@ export class BarretenbergBackend implements Backend { // have to initialize `api` and `acirComposer` in the constructor. // These are initialized asynchronously in the `init` function, // constructors cannot be asynchronous which is why we do this. - private api: any; + + private api!: Barretenberg; + // eslint-disable-next-line @typescript-eslint/no-explicit-any private acirComposer: any; private acirUncompressedBytecode: Uint8Array; constructor( - private acirCircuit: CompiledCircuit, + acirCircuit: CompiledCircuit, private options: BackendOptions = { threads: 1 }, ) { const acirBytecodeBase64 = acirCircuit.bytecode; @@ -30,8 +33,6 @@ export class BarretenbergBackend implements Backend { /** @ignore */ async instantiate(): Promise { if (!this.api) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore const { Barretenberg, RawBuffer, Crs } = await import('@aztec/bb.js'); const api = await Barretenberg.new({ threads: this.options.threads }); @@ -46,29 +47,25 @@ export class BarretenbergBackend implements Backend { } } - // Generate an outer proof. This is the proof for the circuit which will verify - // inner proofs and or can be seen as the proof created for regular circuits. - // - // The settings for this proof are the same as the settings for a "normal" proof - // ie one that is not in the recursive setting. + /** + * Generate a final proof. This is the proof for the circuit which will verify + * intermediate proofs and or can be seen as the proof created for regular circuits. + */ async generateFinalProof(decompressedWitness: Uint8Array): Promise { + // The settings for this proof are the same as the settings for a "normal" proof + // i.e. one that is not in the recursive setting. const makeEasyToVerifyInCircuit = false; return this.generateProof(decompressedWitness, makeEasyToVerifyInCircuit); } - // Generates an inner proof. This is the proof that will be verified - // in another circuit. - // - // This is sometimes referred to as a recursive proof. - // We avoid this terminology as the only property of this proof - // that matters, is the fact that it is easy to verify in another - // circuit. We _could_ choose to verify this proof in the CLI. - // - // We set `makeEasyToVerifyInCircuit` to true, which will tell the backend to - // generate the proof using components that will make the proof - // easier to verify in a circuit. - /** + * Generates an intermediate proof. This is the proof that can be verified + * in another circuit. + * + * This is sometimes referred to as a recursive proof. + * We avoid this terminology as the only property of this proof + * that matters is the fact that it is easy to verify in another circuit. + * We _could_ choose to verify this proof outside of a circuit just as easily. * * @example * ```typescript @@ -76,6 +73,9 @@ export class BarretenbergBackend implements Backend { * ``` */ async generateIntermediateProof(witness: Uint8Array): Promise { + // We set `makeEasyToVerifyInCircuit` to true, which will tell the backend to + // generate the proof using components that will make the proof + // easier to verify in a circuit. const makeEasyToVerifyInCircuit = true; return this.generateProof(witness, makeEasyToVerifyInCircuit); } @@ -99,17 +99,16 @@ export class BarretenbergBackend implements Backend { return { proof, publicInputs }; } - // Generates artifacts that will be passed to a circuit that will verify this proof. - // - // Instead of passing the proof and verification key as a byte array, we pass them - // as fields which makes it cheaper to verify in a circuit. - // - // The proof that is passed here will have been created using the `generateInnerProof` - // method. - // - // The number of public inputs denotes how many public inputs are in the inner proof. - /** + * Generates artifacts that will be passed to a circuit that will verify this proof. + * + * Instead of passing the proof and verification key as a byte array, we pass them + * as fields which makes it cheaper to verify in a circuit. + * + * The proof that is passed here will have been created using the `generateIntermediateProof` + * method. + * + * The number of public inputs denotes how many public inputs are in the inner proof. * * @example * ```typescript diff --git a/noir/tooling/noirc_abi/src/lib.rs b/noir/tooling/noirc_abi/src/lib.rs index 066b1635ced..1fc257c1676 100644 --- a/noir/tooling/noirc_abi/src/lib.rs +++ b/noir/tooling/noirc_abi/src/lib.rs @@ -512,7 +512,7 @@ fn decode_string_value(field_elements: &[FieldElement]) -> String { final_string.to_owned() } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ContractEvent { /// Event name name: String, diff --git a/yarn-project/Dockerfile.prod b/yarn-project/Dockerfile.prod index 8073db145d5..b5e324a8ad3 100644 --- a/yarn-project/Dockerfile.prod +++ b/yarn-project/Dockerfile.prod @@ -11,13 +11,13 @@ WORKDIR /usr/src/yarn-project ARG COMMIT_TAG="" RUN ./scripts/version_packages.sh # Productionify. See comment in yarn-project-base/Dockerfile. -RUN yarn workspaces focus @aztec/cli @aztec/aztec-sandbox @aztec/aztec-faucet @aztec/aztec.js --production && \ - yarn cache clean && \ - rm -rf /usr/src/barretenberg/ts/src && \ - # TODO: Fix by extracting noir code out of yarn-project. - # This was just a "rm -rf ./**/src". - # Due to the mess of us needing to find noir code in noir-protocol-circuits/src/crates we have to do this... - find . -maxdepth 2 -name src -type d | grep -v "./noir-protocol-circuits" | xargs rm -rf +RUN yarn workspaces focus @aztec/cli @aztec/aztec @aztec/aztec-faucet @aztec/aztec.js --production && \ + yarn cache clean && \ + rm -rf /usr/src/barretenberg/ts/src && \ + # TODO: Fix by extracting noir code out of yarn-project. + # This was just a "rm -rf ./**/src". + # Due to the mess of us needing to find noir code in noir-protocol-circuits/src/crates we have to do this... + find . -maxdepth 2 -name src -type d | grep -v "./noir-protocol-circuits" | xargs rm -rf # We no longer need nargo. RUN rm -rf /usr/src/noir/target @@ -34,32 +34,32 @@ ENV COMMIT_TAG=$COMMIT_TAG RUN apt update && apt install -y curl && rm -rf /var/lib/apt/lists/* && apt-get clean ENV NODE_VERSION=18.19.0 RUN ARCH= && \ - dpkgArch="$(dpkg --print-architecture)" && \ - case "${dpkgArch##*-}" in \ - amd64) ARCH='x64';; \ - arm64) ARCH='arm64';; \ - *) echo "unsupported architecture"; exit 1 ;; \ - esac && \ - curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.gz" && \ - tar zxf "node-v$NODE_VERSION-linux-$ARCH.tar.gz" -C /usr --strip-components=1 --no-same-owner \ - --exclude "*/share/*" \ - --exclude "*/bin/corepack" \ - --exclude "*/bin/npx" \ - --exclude "*/bin/npm" \ - --exclude "*/corepack/*" \ - --exclude "*/npm/man/*" \ - --exclude "*/npm/docs/*" \ - --exclude "*/include/*" && \ - rm "node-v$NODE_VERSION-linux-$ARCH.tar.gz" && \ - node --version + dpkgArch="$(dpkg --print-architecture)" && \ + case "${dpkgArch##*-}" in \ + amd64) ARCH='x64';; \ + arm64) ARCH='arm64';; \ + *) echo "unsupported architecture"; exit 1 ;; \ + esac && \ + curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.gz" && \ + tar zxf "node-v$NODE_VERSION-linux-$ARCH.tar.gz" -C /usr --strip-components=1 --no-same-owner \ + --exclude "*/share/*" \ + --exclude "*/bin/corepack" \ + --exclude "*/bin/npx" \ + --exclude "*/bin/npm" \ + --exclude "*/corepack/*" \ + --exclude "*/npm/man/*" \ + --exclude "*/npm/docs/*" \ + --exclude "*/include/*" && \ + rm "node-v$NODE_VERSION-linux-$ARCH.tar.gz" && \ + node --version # Yarn is used for unboxing. -ENV YARN_VERSION=1.22.19 +ENV YARN_VERSION=1.22.19 RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" && \ - mkdir -p /opt && \ - tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ && \ - ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn && \ - ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg && \ - rm yarn-v$YARN_VERSION.tar.gz && \ - yarn --version + mkdir -p /opt && \ + tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ && \ + ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn && \ + ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg && \ + rm yarn-v$YARN_VERSION.tar.gz && \ + yarn --version COPY --from=builder /usr/src /usr/src ENTRYPOINT ["/usr/bin/node"] diff --git a/yarn-project/accounts/src/defaults/index.ts b/yarn-project/accounts/src/defaults/index.ts index a194b8c848e..df6428faaac 100644 --- a/yarn-project/accounts/src/defaults/index.ts +++ b/yarn-project/accounts/src/defaults/index.ts @@ -1,7 +1,7 @@ /** * The `@aztec/accounts/defaults` export provides the base class {@link DefaultAccountContract} for implementing account contracts that use the default entrypoint payload module. * - * Read more in {@link https://docs.aztec.network/dev_docs/wallets/writing_an_account_contract | Writing an account contract}. + * Read more in {@link https://docs.aztec.network/developers/wallets/writing_an_account_contract | Writing an account contract}. * * @packageDocumentation */ diff --git a/yarn-project/acir-simulator/package.json b/yarn-project/acir-simulator/package.json index 9a3a0361d72..ccd51b8ba54 100644 --- a/yarn-project/acir-simulator/package.json +++ b/yarn-project/acir-simulator/package.json @@ -39,6 +39,7 @@ "tslib": "^2.4.0" }, "devDependencies": { + "@aztec/kv-store": "workspace:^", "@aztec/merkle-tree": "workspace:^", "@aztec/noir-contracts": "workspace:^", "@jest/globals": "^29.5.0", diff --git a/yarn-project/acir-simulator/src/acvm/deserialize.ts b/yarn-project/acir-simulator/src/acvm/deserialize.ts index d8d9866454f..5e30a72afd5 100644 --- a/yarn-project/acir-simulator/src/acvm/deserialize.ts +++ b/yarn-project/acir-simulator/src/acvm/deserialize.ts @@ -4,16 +4,17 @@ import { ContractDeploymentData, ContractStorageRead, ContractStorageUpdateRequest, - FunctionSelector, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, + NullifierKeyValidationRequest, PrivateCircuitPublicInputs, PublicCircuitPublicInputs, RETURN_VALUES_LENGTH, @@ -23,40 +24,19 @@ import { import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr, Point } from '@aztec/foundation/fields'; -import { Tuple } from '@aztec/foundation/serialize'; +import { FieldReader, Tuple } from '@aztec/foundation/serialize'; import { getReturnWitness } from '@noir-lang/acvm_js'; import { ACVMField, ACVMWitness } from './acvm_types.js'; -/** - * Converts an ACVM field to a Buffer. - * @param field - The ACVM field to convert. - * @returns The Buffer. - */ -export function convertACVMFieldToBuffer(field: ACVMField): Buffer { - return Buffer.from(field.slice(2), 'hex'); -} - /** * Converts an ACVM field to a Fr. * @param field - The ACVM field to convert. * @returns The Fr. */ export function fromACVMField(field: ACVMField): Fr { - return Fr.fromBuffer(convertACVMFieldToBuffer(field)); -} - -// Utilities to read TS classes from ACVM Field arrays -// In the order that the ACVM provides them - -/** - * Converts a field to an Aztec address. - * @param fr - The field to convert. - * @returns The Aztec address. - */ -export function frToAztecAddress(fr: Fr): AztecAddress { - return new AztecAddress(fr.toBuffer()); + return Fr.fromBuffer(Buffer.from(field.slice(2), 'hex')); } /** @@ -68,88 +48,24 @@ export function frToNumber(fr: Fr): number { return Number(fr.value); } -/** - * Converts a field to a boolean. - * @param fr - The field to convert. - * @returns The boolean. - */ -export function frToBoolean(fr: Fr): boolean { - const buf = fr.toBuffer(); - return buf[buf.length - 1] !== 0; -} - /** * Extracts the return fields of a given partial witness. * @param acir - The bytecode of the function. * @param partialWitness - The witness to extract from. * @returns The return values. */ -export function extractReturnWitness(acir: Buffer, partialWitness: ACVMWitness): ACVMField[] { +export function extractReturnWitness(acir: Buffer, partialWitness: ACVMWitness): Fr[] { const returnWitness = getReturnWitness(acir, partialWitness); const sortedKeys = [...returnWitness.keys()].sort((a, b) => a - b); - return sortedKeys.map(key => returnWitness.get(key)!); + return sortedKeys.map(key => returnWitness.get(key)!).map(fromACVMField); } /** - * A utility reader for the public inputs of the ACVM generated partial witness. + * Create a reader for the public inputs of the ACVM generated partial witness. */ -export class PublicInputsReader { - private publicInputs: ACVMField[]; - - constructor(witness: ACVMWitness, acir: Buffer) { - this.publicInputs = extractReturnWitness(acir, witness); - } - - /** - * Reads a field from the public inputs. - * @returns The field. - */ - public readField(): Fr { - const acvmField = this.publicInputs.shift(); - if (!acvmField) { - throw new Error('Not enough public inputs'); - } - return fromACVMField(acvmField); - } - - /** - * Reads an array of fields from the public inputs. - * @param length - The length of the array. - * @returns The array of fields. - */ - public readFieldArray(length: N): Tuple { - const array: Fr[] = []; - for (let i = 0; i < length; i++) { - array.push(this.readField()); - } - return array as Tuple; - } - - /** - * Reads an array of SideEffects from the public inputs. - * @param length - The length of the array. - * @returns The array of SideEffects. - */ - public readSideEffectArray(length: N): Tuple { - const array: SideEffect[] = []; - for (let i = 0; i < length; i++) { - array.push(new SideEffect(this.readField(), this.readField())); - } - return array as Tuple; - } - - /** - * Reads an array of SideEffectLinkedToNoteHashes from the public inputs. - * @param length - The length of the array. - * @returns The array of SideEffectLinkedToNoteHashes. - */ - public readSideEffectLinkedToNoteHashArray(length: N): Tuple { - const array: SideEffectLinkedToNoteHash[] = []; - for (let i = 0; i < length; i++) { - array.push(new SideEffectLinkedToNoteHash(this.readField(), this.readField(), this.readField())); - } - return array as Tuple; - } +function createPublicInputsReader(witness: ACVMWitness, acir: Buffer) { + const fields = extractReturnWitness(acir, witness); + return new FieldReader(fields); } /** @@ -162,24 +78,18 @@ export function extractPrivateCircuitPublicInputs( partialWitness: ACVMWitness, acir: Buffer, ): PrivateCircuitPublicInputs { - const witnessReader = new PublicInputsReader(partialWitness, acir); - - const callContext = new CallContext( - frToAztecAddress(witnessReader.readField()), - frToAztecAddress(witnessReader.readField()), - witnessReader.readField(), - FunctionSelector.fromField(witnessReader.readField()), - frToBoolean(witnessReader.readField()), - frToBoolean(witnessReader.readField()), - frToBoolean(witnessReader.readField()), - frToNumber(witnessReader.readField()), - ); + const witnessReader = createPublicInputsReader(partialWitness, acir); + const callContext = witnessReader.readObject(CallContext); const argsHash = witnessReader.readField(); const returnValues = witnessReader.readFieldArray(RETURN_VALUES_LENGTH); - const readRequests = witnessReader.readSideEffectArray(MAX_READ_REQUESTS_PER_CALL); - const newCommitments = witnessReader.readSideEffectArray(MAX_NEW_COMMITMENTS_PER_CALL); - const newNullifiers = witnessReader.readSideEffectLinkedToNoteHashArray(MAX_NEW_NULLIFIERS_PER_CALL); + const readRequests = witnessReader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect); + const nullifierKeyValidationRequests = witnessReader.readArray( + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + NullifierKeyValidationRequest, + ); + const newCommitments = witnessReader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect); + const newNullifiers = witnessReader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash); const privateCallStack = witnessReader.readFieldArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL); const publicCallStack = witnessReader.readFieldArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL); const newL2ToL1Msgs = witnessReader.readFieldArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL); @@ -217,6 +127,7 @@ export function extractPrivateCircuitPublicInputs( argsHash, returnValues, readRequests, + nullifierKeyValidationRequests, newCommitments, newNullifiers, privateCallStack, @@ -241,18 +152,9 @@ export function extractPrivateCircuitPublicInputs( * @returns The public inputs. */ export function extractPublicCircuitPublicInputs(partialWitness: ACVMWitness, acir: Buffer): PublicCircuitPublicInputs { - const witnessReader = new PublicInputsReader(partialWitness, acir); + const witnessReader = createPublicInputsReader(partialWitness, acir); - const callContext = new CallContext( - frToAztecAddress(witnessReader.readField()), - frToAztecAddress(witnessReader.readField()), - witnessReader.readField(), - FunctionSelector.fromField(witnessReader.readField()), - frToBoolean(witnessReader.readField()), - frToBoolean(witnessReader.readField()), - frToBoolean(witnessReader.readField()), - frToNumber(witnessReader.readField()), - ); + const callContext = witnessReader.readObject(CallContext); const argsHash = witnessReader.readField(); const returnValues = witnessReader.readFieldArray(RETURN_VALUES_LENGTH); @@ -275,8 +177,8 @@ export function extractPublicCircuitPublicInputs(partialWitness: ACVMWitness, ac } const publicCallStack = witnessReader.readFieldArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL); - const newCommitments = witnessReader.readSideEffectArray(MAX_NEW_COMMITMENTS_PER_CALL); - const newNullifiers = witnessReader.readSideEffectLinkedToNoteHashArray(MAX_NEW_NULLIFIERS_PER_CALL); + const newCommitments = witnessReader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect); + const newNullifiers = witnessReader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash); const newL2ToL1Msgs = witnessReader.readFieldArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL); const unencryptedLogsHash = witnessReader.readFieldArray(NUM_FIELDS_PER_SHA256); diff --git a/yarn-project/acir-simulator/src/acvm/serialize.ts b/yarn-project/acir-simulator/src/acvm/serialize.ts index 5e844ff8a7c..7ec36695a3d 100644 --- a/yarn-project/acir-simulator/src/acvm/serialize.ts +++ b/yarn-project/acir-simulator/src/acvm/serialize.ts @@ -143,9 +143,10 @@ export function toACVMPublicInputs(publicInputs: PrivateCircuitPublicInputs): AC toACVMField(publicInputs.argsHash), ...publicInputs.returnValues.map(toACVMField), - ...publicInputs.readRequests.flatMap(x => x.toFieldArray()).map(toACVMField), - ...publicInputs.newCommitments.flatMap(x => x.toFieldArray()).map(toACVMField), - ...publicInputs.newNullifiers.flatMap(x => x.toFieldArray()).map(toACVMField), + ...publicInputs.readRequests.flatMap(x => x.toFields()).map(toACVMField), + ...publicInputs.nullifierKeyValidationRequests.flatMap(x => x.toFields()).map(toACVMField), + ...publicInputs.newCommitments.flatMap(x => x.toFields()).map(toACVMField), + ...publicInputs.newNullifiers.flatMap(x => x.toFields()).map(toACVMField), ...publicInputs.privateCallStackHashes.map(toACVMField), ...publicInputs.publicCallStackHashes.map(toACVMField), ...publicInputs.newL2ToL1Msgs.map(toACVMField), 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 6c921bd08e9..6a87f62d87b 100644 --- a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts @@ -10,31 +10,30 @@ import { Fr } from '@aztec/foundation/fields'; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): gas not implemented export class AvmExecutionEnvironment { 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, - /** - */ + public readonly globals: GlobalVariables, - /** - */ + public readonly isStaticCall: boolean, - /** - */ + public readonly isDelegateCall: boolean, - /** - */ + public readonly calldata: Fr[], ) {} 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 dc1ce28aa23..4d9fa6bb7fe 100644 --- a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts +++ b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts @@ -15,7 +15,6 @@ export class AvmMachineState { private returnData: Fr[]; - /** - */ public readonly memory: TaggedMemory; /** @@ -24,9 +23,8 @@ export class AvmMachineState { */ public internalCallStack: number[]; - /** - */ public pc: number; - /** - */ + public callStack: number[]; /** @@ -60,7 +58,6 @@ export class AvmMachineState { Object.freeze(returnData); } - /** - */ public getReturnData(): Fr[] { return this.returnData; } diff --git a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts b/yarn-project/acir-simulator/src/avm/avm_memory_types.ts index 69ed95c4a66..6967a58fd8f 100644 --- a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/acir-simulator/src/avm/avm_memory_types.ts @@ -2,31 +2,38 @@ import { Fr } from '@aztec/foundation/fields'; import { strict as assert } from 'assert'; -export interface MemoryValue { - add(rhs: MemoryValue): MemoryValue; - sub(rhs: MemoryValue): MemoryValue; - mul(rhs: MemoryValue): MemoryValue; - div(rhs: MemoryValue): MemoryValue; +export abstract class MemoryValue { + public abstract add(rhs: MemoryValue): MemoryValue; + public abstract sub(rhs: MemoryValue): MemoryValue; + public abstract mul(rhs: MemoryValue): MemoryValue; + public abstract div(rhs: MemoryValue): MemoryValue; + + public abstract equals(rhs: MemoryValue): boolean; + public abstract lt(rhs: MemoryValue): boolean; + + // We need this to be able to build an instance of the subclasses. + public abstract build(n: bigint): MemoryValue; // Use sparingly. - toBigInt(): bigint; + public abstract toBigInt(): bigint; } -export interface IntegralValue extends MemoryValue { - shl(rhs: IntegralValue): IntegralValue; - shr(rhs: IntegralValue): IntegralValue; - and(rhs: IntegralValue): IntegralValue; - or(rhs: IntegralValue): IntegralValue; - xor(rhs: IntegralValue): IntegralValue; - not(): IntegralValue; +export abstract class IntegralValue extends MemoryValue { + public abstract shl(rhs: IntegralValue): IntegralValue; + public abstract shr(rhs: IntegralValue): IntegralValue; + public abstract and(rhs: IntegralValue): IntegralValue; + public abstract or(rhs: IntegralValue): IntegralValue; + public abstract xor(rhs: IntegralValue): IntegralValue; + public abstract not(): IntegralValue; } // TODO: Optimize calculation of mod, etc. Can only do once per class? -abstract class UnsignedInteger implements IntegralValue { +abstract class UnsignedInteger extends IntegralValue { private readonly bitmask: bigint; private readonly mod: bigint; protected constructor(private n: bigint, private bits: bigint) { + super(); assert(bits > 0); // x % 2^n == x & (2^n - 1) this.mod = 1n << bits; @@ -34,9 +41,7 @@ abstract class UnsignedInteger implements IntegralValue { assert(n < this.mod); } - // We need this to be able to build an instance of the subclass - // and not of type UnsignedInteger. - protected abstract build(n: bigint): UnsignedInteger; + public abstract build(n: bigint): UnsignedInteger; public add(rhs: UnsignedInteger): UnsignedInteger { assert(this.bits == rhs.bits); @@ -90,12 +95,18 @@ abstract class UnsignedInteger implements IntegralValue { return this.build(~this.n & this.bitmask); } - public toBigInt(): bigint { - return this.n; + public equals(rhs: UnsignedInteger): boolean { + assert(this.bits == rhs.bits); + return this.n === rhs.n; + } + + public lt(rhs: UnsignedInteger): boolean { + assert(this.bits == rhs.bits); + return this.n < rhs.n; } - public equals(rhs: UnsignedInteger) { - return this.bits == rhs.bits && this.toBigInt() == rhs.toBigInt(); + public toBigInt(): bigint { + return this.n; } } @@ -104,7 +115,7 @@ export class Uint8 extends UnsignedInteger { super(BigInt(n), 8n); } - protected build(n: bigint): Uint8 { + public build(n: bigint): Uint8 { return new Uint8(n); } } @@ -114,7 +125,7 @@ export class Uint16 extends UnsignedInteger { super(BigInt(n), 16n); } - protected build(n: bigint): Uint16 { + public build(n: bigint): Uint16 { return new Uint16(n); } } @@ -124,7 +135,7 @@ export class Uint32 extends UnsignedInteger { super(BigInt(n), 32n); } - protected build(n: bigint): Uint32 { + public build(n: bigint): Uint32 { return new Uint32(n); } } @@ -134,7 +145,7 @@ export class Uint64 extends UnsignedInteger { super(BigInt(n), 64n); } - protected build(n: bigint): Uint64 { + public build(n: bigint): Uint64 { return new Uint64(n); } } @@ -144,19 +155,24 @@ export class Uint128 extends UnsignedInteger { super(BigInt(n), 128n); } - protected build(n: bigint): Uint128 { + public build(n: bigint): Uint128 { return new Uint128(n); } } -export class Field implements MemoryValue { +export class Field extends MemoryValue { public static readonly MODULUS: bigint = Fr.MODULUS; private readonly rep: Fr; constructor(v: number | bigint | Fr) { + super(); this.rep = new Fr(v); } + public build(n: bigint): Field { + return new Field(n); + } + public add(rhs: Field): Field { return new Field(this.rep.add(rhs.rep)); } @@ -173,6 +189,14 @@ export class Field implements MemoryValue { return new Field(this.rep.div(rhs.rep)); } + public equals(rhs: Field): boolean { + return this.rep.equals(rhs.rep); + } + + public lt(rhs: Field): boolean { + return this.rep.lt(rhs.rep); + } + public toBigInt(): bigint { return this.rep.toBigInt(); } @@ -204,8 +228,8 @@ export class TaggedMemory { public getAs(offset: number): T { assert(offset < TaggedMemory.MAX_MEMORY_SIZE); - const e = this._mem[offset]; - return e; + const word = this._mem[offset]; + return word as T; } public getSlice(offset: number, size: number): MemoryValue[] { @@ -258,6 +282,7 @@ export class TaggedMemory { // Truncates the value to fit the type. public static integralFromTag(v: bigint, tag: TypeTag): IntegralValue { + v = BigInt(v); // FIXME: not sure why this cast is needed, but this errors otherwise switch (tag) { case TypeTag.UINT8: return new Uint8(v & ((1n << 8n) - 1n)); diff --git a/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts b/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts index e2290e4fa6d..713a306b3e9 100644 --- a/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts +++ b/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts @@ -4,9 +4,8 @@ import { Fr } from '@aztec/foundation/fields'; * AVM message call result. */ export class AvmMessageCallResult { - /** - */ public readonly reverted: boolean; - /** - */ + public readonly revertReason: Error | undefined; /** .- */ public readonly output: Fr[]; diff --git a/yarn-project/acir-simulator/src/avm/fixtures/index.ts b/yarn-project/acir-simulator/src/avm/fixtures/index.ts index fb16ebf4ee3..e97dc3fa2ce 100644 --- a/yarn-project/acir-simulator/src/avm/fixtures/index.ts +++ b/yarn-project/acir-simulator/src/avm/fixtures/index.ts @@ -10,31 +10,30 @@ import { AvmExecutionEnvironment } from '../avm_execution_environment.js'; * 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[]; } 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 7ecaf130942..79b814da07c 100644 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts @@ -22,8 +22,8 @@ describe('interpreter', () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; const instructions: Instruction[] = [ - new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 2, /*destOffset=*/ 0), - new Add(/*aOffset=*/ 0, /*bOffset=*/ 1, /*destOffset=*/ 2), + new CalldataCopy(/*cdOffset=*/ 0, /*copySize=*/ 2, /*dstOffset=*/ 0), + new Add(/*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), new Return(/*returnOffset=*/ 2, /*copySize=*/ 1), ]; diff --git a/yarn-project/acir-simulator/src/avm/journal/host_storage.ts b/yarn-project/acir-simulator/src/avm/journal/host_storage.ts index fcd9d27f722..b12e14f9c20 100644 --- a/yarn-project/acir-simulator/src/avm/journal/host_storage.ts +++ b/yarn-project/acir-simulator/src/avm/journal/host_storage.ts @@ -6,11 +6,10 @@ import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js' * A wrapper around the node dbs */ export class HostStorage { - /** - */ public readonly publicStateDb: PublicStateDB; - /** - */ + public readonly contractsDb: PublicContractsDB; - /** - */ + public readonly commitmentsDb: CommitmentsDB; constructor(publicStateDb: PublicStateDB, contractsDb: PublicContractsDB, commitmentsDb: CommitmentsDB) { diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.ts b/yarn-project/acir-simulator/src/avm/journal/journal.ts index 62670b8f2f7..4d5b92fec6b 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.ts @@ -7,11 +7,10 @@ import { HostStorage } from './host_storage.js'; * Data held within the journal */ export type JournalData = { - /** - */ newCommitments: Fr[]; - /** - */ + newL1Messages: Fr[]; - /** - */ + newNullifiers: Fr[]; /** contract address -\> key -\> value */ storageWrites: Map>; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts new file mode 100644 index 00000000000..e69de29bb2d 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 123e0a0a064..a9911f8d82d 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts @@ -30,7 +30,7 @@ describe('Arithmetic Instructions', () => { expect(actual).toEqual(expected); }); - it('Should wrap around on addition',async () => { + it('Should wrap around on addition', async () => { const a = new Field(1n); const b = new Field(Field.MODULUS - 1n); @@ -46,7 +46,7 @@ describe('Arithmetic Instructions', () => { }); describe('Sub', () => { - it('Should subtract correctly over field elements',async () => { + it('Should subtract correctly over field elements', async () => { const a = new Field(1n); const b = new Field(2n); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts index 507430feae7..0b1910f0dd7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts @@ -6,7 +6,7 @@ export class Add extends Instruction { static type: string = 'ADD'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -15,7 +15,7 @@ export class Add extends Instruction { const b = machineState.memory.get(this.bOffset); const dest = a.add(b); - machineState.memory.set(this.destOffset, dest); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } @@ -25,7 +25,7 @@ export class Sub extends Instruction { static type: string = 'SUB'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -34,7 +34,7 @@ export class Sub extends Instruction { const b = machineState.memory.get(this.bOffset); const dest = a.sub(b); - machineState.memory.set(this.destOffset, dest); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } @@ -44,7 +44,7 @@ export class Mul extends Instruction { static type: string = 'MUL'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -53,18 +53,17 @@ export class Mul extends Instruction { const b = machineState.memory.get(this.bOffset); const dest = a.mul(b); - machineState.memory.set(this.destOffset, dest); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } } -/** -*/ export class Div extends Instruction { static type: string = 'DIV'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -73,7 +72,7 @@ export class Div extends Instruction { const b = machineState.memory.get(this.bOffset); const dest = a.div(b); - machineState.memory.set(this.destOffset, dest); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } 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 bb7831b8d5f..ae8ce802724 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts @@ -19,34 +19,34 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, new Uint32(0b11111110010011100100n)); machineState.memory.set(1, new Uint32(0b11100100111001001111n)); - await new And(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new And(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const actual = machineState.memory.get(2); expect(actual).toEqual(new Uint32(0b11100100010001000100n)); }); - it('Should OR correctly over integral types', () => { + it('Should OR correctly over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); machineState.memory.set(0, a); machineState.memory.set(1, b); - new Or(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Or(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = new Uint32(0b11111110111011101111n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should XOR correctly over integral types',async () => { + it('Should XOR correctly over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Xor(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Xor(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = new Uint32(0b00011010101010101011n); const actual = machineState.memory.get(2); @@ -54,41 +54,42 @@ describe('Bitwise instructions', () => { }); describe('SHR', () => { - it('Should shift correctly 0 positions over integral types',async () => { + it('Should shift correctly 0 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0n); machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shr(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = a; const actual = machineState.memory.get(2); + expect(actual).toEqual(expected); }); - it('Should shift correctly 2 positions over integral types',async () => { + it('Should shift correctly 2 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shr(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = new Uint32(0b00111111100100111001n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should shift correctly 19 positions over integral types',async () => { + it('Should shift correctly 19 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(19n); machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shr(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shr(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = new Uint32(0b01n); const actual = machineState.memory.get(2); @@ -104,21 +105,21 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shl(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = a; const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should shift correctly 2 positions over integral types',async () => { + it('Should shift correctly 2 positions over integral types', async () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shl(0, 1, 2, TypeTag.UINT32).execute(machineState, journal); + await new Shl(TypeTag.UINT32, 0, 1, 2).execute(machineState, journal); const expected = new Uint32(0b1111111001001110010000n); const actual = machineState.memory.get(2); @@ -132,21 +133,21 @@ describe('Bitwise instructions', () => { machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); + await new Shl(TypeTag.UINT16, 0, 1, 2).execute(machineState, journal); const expected = new Uint16(0n); const actual = machineState.memory.get(2); expect(actual).toEqual(expected); }); - it('Should truncate when shifting over bit size over integral types',async () => { + it('Should truncate when shifting over bit size over integral types', async () => { const a = new Uint16(0b1110010011100111n); const b = new Uint16(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); - await new Shl(0, 1, 2, TypeTag.UINT16).execute(machineState, journal); + await new Shl(TypeTag.UINT16, 0, 1, 2).execute(machineState, journal); const expected = new Uint16(0b1001001110011100n); const actual = machineState.memory.get(2); @@ -154,12 +155,12 @@ describe('Bitwise instructions', () => { }); }); - it('Should NOT correctly over integral types',async () => { + it('Should NOT correctly over integral types', async () => { const a = new Uint16(0b0110010011100100n); machineState.memory.set(0, a); - await new Not(0, 1, TypeTag.UINT16).execute(machineState, journal); + await new Not(TypeTag.UINT16, 0, 1).execute(machineState, journal); const expected = new Uint16(0b1001101100011011n); // high bits! const actual = machineState.memory.get(1); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts index 31420d0b3bc..e439a8bd447 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts @@ -7,7 +7,7 @@ export class And extends Instruction { static type: string = 'AND'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number, private inTag: TypeTag) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -18,7 +18,7 @@ export class And extends Instruction { const b = machineState.memory.getAs(this.bOffset); const res = a.and(b); - machineState.memory.set(this.destOffset, res); + machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState); } @@ -28,7 +28,7 @@ export class Or extends Instruction { static type: string = 'OR'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number, private inTag: TypeTag) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -39,7 +39,7 @@ export class Or extends Instruction { const b = machineState.memory.getAs(this.bOffset); const res = a.or(b); - machineState.memory.set(this.destOffset, res); + machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState); } @@ -49,7 +49,7 @@ export class Xor extends Instruction { static type: string = 'XOR'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number, private inTag: TypeTag) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -60,7 +60,7 @@ export class Xor extends Instruction { const b = machineState.memory.getAs(this.bOffset); const res = a.xor(b); - machineState.memory.set(this.destOffset, res); + machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState); } @@ -70,7 +70,7 @@ export class Not extends Instruction { static type: string = 'NOT'; static numberOfOperands = 2; - constructor(private aOffset: number, private destOffset: number, private inTag: TypeTag) { + constructor(private inTag: TypeTag, private aOffset: number, private dstOffset: number) { super(); } @@ -80,7 +80,7 @@ export class Not extends Instruction { const a = machineState.memory.getAs(this.aOffset); const res = a.not(); - machineState.memory.set(this.destOffset, res); + machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState); } @@ -90,7 +90,7 @@ export class Shl extends Instruction { static type: string = 'SHL'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number, private inTag: TypeTag) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -101,7 +101,7 @@ export class Shl extends Instruction { const b = machineState.memory.getAs(this.bOffset); const res = a.shl(b); - machineState.memory.set(this.destOffset, res); + machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState); } @@ -111,7 +111,7 @@ export class Shr extends Instruction { static type: string = 'SHR'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number, private inTag: TypeTag) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } @@ -122,7 +122,7 @@ export class Shr extends Instruction { const b = machineState.memory.getAs(this.bOffset); const res = a.shr(b); - machineState.memory.set(this.destOffset, res); + machineState.memory.set(this.dstOffset, res); this.incrementPc(machineState); } diff --git a/yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts new file mode 100644 index 00000000000..ff604dbf2cb --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts @@ -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; + + beforeEach(async () => { + machineState = new AvmMachineState(initExecutionEnvironment()); + journal = mock(); + }); + + 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); + } + }); + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts index 8bdb406f9c6..f89d450dbb9 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts @@ -1,5 +1,5 @@ import { AvmMachineState } from '../avm_machine_state.js'; -import { Field } from '../avm_memory_types.js'; +import { TypeTag } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/index.js'; import { Instruction } from './instruction.js'; @@ -7,16 +7,19 @@ export class Eq extends Instruction { static type: string = 'EQ'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { + Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); + const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); - const dest = new Field(a.toBigInt() == b.toBigInt() ? 1 : 0); - machineState.memory.set(this.destOffset, dest); + // Result will be of the same type as 'a'. + const dest = a.build(a.equals(b) ? 1n : 0n); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } @@ -26,16 +29,19 @@ export class Lt extends Instruction { static type: string = 'Lt'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { + Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); + const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); - const dest = new Field(a.toBigInt() < b.toBigInt() ? 1 : 0); - machineState.memory.set(this.destOffset, dest); + // Result will be of the same type as 'a'. + const dest = a.build(a.lt(b) ? 1n : 0n); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } @@ -45,16 +51,19 @@ export class Lte extends Instruction { static type: string = 'LTE'; static numberOfOperands = 3; - constructor(private aOffset: number, private bOffset: number, private destOffset: number) { + constructor(private inTag: TypeTag, private aOffset: number, private bOffset: number, private dstOffset: number) { super(); } async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { + Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); + const a = machineState.memory.get(this.aOffset); const b = machineState.memory.get(this.bOffset); - const dest = new Field(a.toBigInt() < b.toBigInt() ? 1 : 0); - machineState.memory.set(this.destOffset, dest); + // Result will be of the same type as 'a'. + const dest = a.build(a.equals(b) || a.lt(b) ? 1n : 0n); + machineState.memory.set(this.dstOffset, dest); this.incrementPc(machineState); } 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 ca4cdd45a5c..59e24adb042 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 @@ -121,20 +121,20 @@ describe('Control Flow Opcodes', () => { new Add(0, 1, 2), new Sub(0, 1, 2), new Mul(0, 1, 2), - new Lt(0, 1, 2), - new Lte(0, 1, 2), - new Eq(0, 1, 2), - new Xor(0, 1, 2, TypeTag.UINT16), - new And(0, 1, 2, TypeTag.UINT16), - new Or(0, 1, 2, TypeTag.UINT16), - new Shl(0, 1, 2, TypeTag.UINT16), - new Shr(0, 1, 2, TypeTag.UINT16), - new Not(0, 2, TypeTag.UINT16), + new Lt(TypeTag.UINT16, 0, 1, 2), + new Lte(TypeTag.UINT16, 0, 1, 2), + new Eq(TypeTag.UINT16, 0, 1, 2), + new Xor(TypeTag.UINT16, 0, 1, 2), + new And(TypeTag.UINT16, 0, 1, 2), + new Or(TypeTag.UINT16, 0, 1, 2), + new Shl(TypeTag.UINT16, 0, 1, 2), + new Shr(TypeTag.UINT16, 0, 1, 2), + new Not(TypeTag.UINT16, 0, 2), new CalldataCopy(0, 1, 2), - new Set(0n, 1, TypeTag.UINT16), + new Set(TypeTag.UINT16, 0n, 1), new Mov(0, 1), new CMov(0, 1, 2, 3), - new Cast(0, 1, TypeTag.UINT16), + new Cast(TypeTag.UINT16, 0, 1), ]; for (const instruction of instructions) { diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts index 518b987a1de..6bbee244cbb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts @@ -16,7 +16,7 @@ export class Return extends Instruction { async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { const returnData = machineState.memory .getSlice(this.returnOffset, this.copySize) - .map(fvt => new Fr(fvt.toBigInt())); + .map(word => new Fr(word.toBigInt())); machineState.setReturnData(returnData); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/decode_bytecode.ts b/yarn-project/acir-simulator/src/avm/opcodes/decode_bytecode.ts index 624546cfbeb..33533f31abb 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/decode_bytecode.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/decode_bytecode.ts @@ -17,17 +17,18 @@ export function decodeBytecode(bytecode: Buffer): Instruction[] { const opcodeByte = bytecode[bytePtr]; bytePtr += AVM_OPCODE_BYTE_LENGTH; if (!(opcodeByte in Opcode)) { - throw new Error(`Opcode ${opcodeByte} not implemented`); + throw new Error(`Opcode 0x${opcodeByte.toString(16)} not implemented`); } const opcode = opcodeByte as Opcode; const instructionType = INSTRUCTION_SET.get(opcode); if (instructionType === undefined) { - throw new Error(`Opcode ${opcode} not implemented`); + throw new Error(`Opcode 0x${opcode.toString(16)} not implemented`); } const numberOfOperands = instructionType.numberOfOperands; const operands: number[] = []; for (let i = 0; i < numberOfOperands; i++) { + // TODO: support constants which might not be u32s const operand = bytecode.readUInt32BE(bytePtr); bytePtr += AVM_OPERAND_BYTE_LENGTH; operands.push(operand); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/encode_to_bytecode.ts b/yarn-project/acir-simulator/src/avm/opcodes/encode_to_bytecode.ts index 186706847d3..105c0f808ab 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/encode_to_bytecode.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/encode_to_bytecode.ts @@ -11,12 +11,14 @@ import { Opcode } from './opcodes.js'; export function encodeToBytecode(opcode: Opcode, args: number[]): Buffer { const instructionType = INSTRUCTION_SET.get(opcode); if (instructionType === undefined) { - throw new Error(`Opcode ${opcode} not implemented`); + throw new Error(`Opcode 0x${opcode.toString(16)} not implemented`); } const numberOfOperands = instructionType.numberOfOperands; if (args.length !== numberOfOperands) { - throw new Error(`Opcode ${opcode} expects ${numberOfOperands} arguments, but ${args.length} were provided`); + throw new Error( + `Opcode 0x${opcode.toString(16)} expects ${numberOfOperands} arguments, but ${args.length} were provided`, + ); } const bytecode = Buffer.alloc(AVM_OPCODE_BYTE_LENGTH + numberOfOperands * AVM_OPERAND_BYTE_LENGTH); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts index 33919aba032..1d91c3bc405 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts @@ -5,6 +5,7 @@ import { MockProxy, mock } from 'jest-mock-extended'; import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { HostStorage } from '../journal/host_storage.js'; import { AvmJournal } from '../journal/journal.js'; @@ -39,7 +40,7 @@ describe('External Calls', () => { const addr = new Fr(123456n); const argsOffset = 2; - const args = [new Fr(1n), new Fr(2n), new Fr(3n)]; + const args = [new Field(1n), new Field(2n), new Field(3n)]; const argsSize = args.length; const retOffset = 8; @@ -47,13 +48,13 @@ describe('External Calls', () => { const successOffset = 7; - machineState.memory.set(0, gas); - machineState.memory.set(1, addr); + machineState.memory.set(0, new Field(gas)); + machineState.memory.set(1, new Field(addr)); machineState.memory.setSlice(2, args); const otherContextInstructions: [Opcode, any[]][] = [ // Place [1,2,3] into memory - [Opcode.CALLDATACOPY, [/*value=*/ 0, /*copySize=*/ argsSize, /*destOffset=*/ 0]], + [Opcode.CALLDATACOPY, [/*value=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0]], // Store 1 into slot 1 [Opcode.SSTORE, [/*slotOffset=*/ 0, /*dataOffset=*/ 0]], // Return [1,2] from memory @@ -71,10 +72,10 @@ describe('External Calls', () => { await instruction.execute(machineState, journal); const successValue = machineState.memory.get(successOffset); - expect(successValue).toEqual(new Fr(1n)); + expect(successValue).toEqual(new Field(1n)); const retValue = machineState.memory.getSlice(retOffset, retSize); - expect(retValue).toEqual([new Fr(1n), new Fr(2n)]); + expect(retValue).toEqual([new Field(1n), new Field(2n)]); // Check that the storage call has been merged into the parent journal const { storageWrites } = journal.flush(); @@ -92,11 +93,11 @@ describe('External Calls', () => { describe('Static Call', () => { it('Should fail if a static call attempts to touch storage', async () => { const gasOffset = 0; - const gas = Fr.zero(); + const gas = new Field(0); const addrOffset = 1; - const addr = new Fr(123456n); + const addr = new Field(123456n); const argsOffset = 2; - const args = [new Fr(1n), new Fr(2n), new Fr(3n)]; + const args = [new Field(1n), new Field(2n), new Field(3n)]; const argsSize = args.length; const retOffset = 8; @@ -108,8 +109,9 @@ describe('External Calls', () => { machineState.memory.setSlice(2, args); const otherContextInstructions: [Opcode, any[]][] = [ - [Opcode.SET, [/* value */ 1, /* destOffset */ 1]], - [Opcode.SSTORE, [/* slotOffset */ 1, /* dataOffset */ 0]], + // Place [1,2,3] into memory + [Opcode.CALLDATACOPY, [/*value=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0]], + [Opcode.SSTORE, [/*slotOffset*/ 1, /*dataOffset=*/ 0]], ]; const otherContextInstructionsBytecode = Buffer.concat( @@ -124,7 +126,7 @@ describe('External Calls', () => { // No revert has occurred, but the nested execution has failed const successValue = machineState.memory.get(successOffset); - expect(successValue).toEqual(new Fr(0n)); + expect(successValue).toEqual(new Field(0n)); }); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts index 38180dce916..280b1284f02 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts @@ -2,9 +2,9 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmContext } from '../avm_context.js'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; -import { Field } from '../avm_memory_types.js'; export class Call extends Instruction { static type: string = 'CALL'; @@ -39,10 +39,11 @@ export class Call extends Instruction { // We only take as much data as was specified in the return size -> TODO: should we be reverting here const returnData = returnObject.output.slice(0, this.retSize); + const convertedReturnData = returnData.map(f => new Field(f)); // Write our return data into memory - machineState.memory.set(this.successOffset, new Fr(success)); - machineState.memory.setSlice(this.retOffset, returnData); + machineState.memory.set(this.successOffset, new Field(success ? 1 : 0)); + machineState.memory.setSlice(this.retOffset, convertedReturnData); if (success) { avmContext.mergeJournal(); @@ -84,10 +85,11 @@ export class StaticCall extends Instruction { // We only take as much data as was specified in the return size -> TODO: should we be reverting here const returnData = returnObject.output.slice(0, this.retSize); + const convertedReturnData = returnData.map(f => new Field(f)); // Write our return data into memory - machineState.memory.set(this.successOffset, new Fr(success)); - machineState.memory.setSlice(this.retOffset, returnData); + machineState.memory.set(this.successOffset, new Field(success ? 1 : 0)); + machineState.memory.setSlice(this.retOffset, convertedReturnData); if (success) { avmContext.mergeJournal(); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts index 4878019b5f0..cccef0861fe 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts @@ -2,8 +2,8 @@ import { AvmMachineState } from '../avm_machine_state.js'; import { TypeTag } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/index.js'; -export const AVM_OPERAND_BYTE_LENGTH = 4; -export const AVM_OPCODE_BYTE_LENGTH = 1; +export const AVM_OPERAND_BYTE_LENGTH = 4; // Keep in sync with cpp code +export const AVM_OPCODE_BYTE_LENGTH = 1; // Keep in sync with cpp code /** * Opcode base class 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 9ea66060ae3..e63fe02dc20 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction_set.ts @@ -8,11 +8,9 @@ import { Opcode } from './opcodes.js'; //import { Eq, Lt, Lte } from './comparators.js'; import { SLoad, SStore } from './storage.js'; -/** - */ type InstructionConstructor = new (...args: any[]) => Instruction; -/** - */ + type InstructionConstructorAndMembers = InstructionConstructor & { - /** - */ numberOfOperands: number; }; 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 65cb6a64eba..1a10c5be15b 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts @@ -18,8 +18,8 @@ describe('Memory instructions', () => { }); describe('SET', () => { - it('should correctly set value and tag (uninitialized)',async () => { - await new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT16).execute(machineState, journal); + it('should correctly set value and tag (uninitialized)', async () => { + await new Set(TypeTag.UINT16, /*value=*/ 1234n, /*offset=*/ 1).execute(machineState, journal); const actual = machineState.memory.get(1); const tag = machineState.memory.getTag(1); @@ -31,7 +31,7 @@ describe('Memory instructions', () => { it('should correctly set value and tag (overwriting)', async () => { machineState.memory.set(1, new Field(27)); - await new Set(/*value=*/ 1234n, /*offset=*/ 1, TypeTag.UINT32).execute(machineState, journal); + await new Set(TypeTag.UINT32, /*value=*/ 1234n, /*offset=*/ 1).execute(machineState, journal); const actual = machineState.memory.get(1); const tag = machineState.memory.getTag(1); @@ -50,11 +50,11 @@ describe('Memory instructions', () => { machineState.memory.set(4, new Uint128(1n << 100n)); [ - new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 10, TypeTag.UINT16), - new Cast(/*aOffset=*/ 1, /*dstOffset=*/ 11, TypeTag.UINT32), - new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.UINT64), - new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.UINT128), - new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.UINT128), + new Cast(TypeTag.UINT16, /*aOffset=*/ 0, /*dstOffset=*/ 10), + new Cast(TypeTag.UINT32, /*aOffset=*/ 1, /*dstOffset=*/ 11), + new Cast(TypeTag.UINT64, /*aOffset=*/ 2, /*dstOffset=*/ 12), + new Cast(TypeTag.UINT128, /*aOffset=*/ 3, /*dstOffset=*/ 13), + new Cast(TypeTag.UINT128, /*aOffset=*/ 4, /*dstOffset=*/ 14), ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); @@ -77,11 +77,11 @@ describe('Memory instructions', () => { machineState.memory.set(4, new Uint128((1n << 100n) - 1n)); [ - new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 10, TypeTag.UINT8), - new Cast(/*aOffset=*/ 1, /*dstOffset=*/ 11, TypeTag.UINT8), - new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.UINT16), - new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.UINT32), - new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.UINT64), + new Cast(TypeTag.UINT8, /*aOffset=*/ 0, /*dstOffset=*/ 10), + new Cast(TypeTag.UINT8, /*aOffset=*/ 1, /*dstOffset=*/ 11), + new Cast(TypeTag.UINT16, /*aOffset=*/ 2, /*dstOffset=*/ 12), + new Cast(TypeTag.UINT32, /*aOffset=*/ 3, /*dstOffset=*/ 13), + new Cast(TypeTag.UINT64, /*aOffset=*/ 4, /*dstOffset=*/ 14), ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); @@ -104,11 +104,11 @@ describe('Memory instructions', () => { machineState.memory.set(4, new Uint128(1n << 100n)); [ - new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 10, TypeTag.FIELD), - new Cast(/*aOffset=*/ 1, /*dstOffset=*/ 11, TypeTag.FIELD), - new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.FIELD), - new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.FIELD), - new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.FIELD), + new Cast(TypeTag.FIELD, /*aOffset=*/ 0, /*dstOffset=*/ 10), + new Cast(TypeTag.FIELD, /*aOffset=*/ 1, /*dstOffset=*/ 11), + new Cast(TypeTag.FIELD, /*aOffset=*/ 2, /*dstOffset=*/ 12), + new Cast(TypeTag.FIELD, /*aOffset=*/ 3, /*dstOffset=*/ 13), + new Cast(TypeTag.FIELD, /*aOffset=*/ 4, /*dstOffset=*/ 14), ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); @@ -131,11 +131,11 @@ describe('Memory instructions', () => { machineState.memory.set(4, new Field((1n << 200n) - 1n)); [ - new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 10, TypeTag.UINT8), - new Cast(/*aOffset=*/ 1, /*dstOffset=*/ 11, TypeTag.UINT16), - new Cast(/*aOffset=*/ 2, /*dstOffset=*/ 12, TypeTag.UINT32), - new Cast(/*aOffset=*/ 3, /*dstOffset=*/ 13, TypeTag.UINT64), - new Cast(/*aOffset=*/ 4, /*dstOffset=*/ 14, TypeTag.UINT128), + new Cast(TypeTag.UINT8, /*aOffset=*/ 0, /*dstOffset=*/ 10), + new Cast(TypeTag.UINT16, /*aOffset=*/ 1, /*dstOffset=*/ 11), + new Cast(TypeTag.UINT32, /*aOffset=*/ 2, /*dstOffset=*/ 12), + new Cast(TypeTag.UINT64, /*aOffset=*/ 3, /*dstOffset=*/ 13), + new Cast(TypeTag.UINT128, /*aOffset=*/ 4, /*dstOffset=*/ 14), ].forEach(i => i.execute(machineState, journal)); const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); @@ -150,10 +150,10 @@ describe('Memory instructions', () => { expect(tags).toEqual([TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128]); }); - it('Should cast between field elements',async () => { + it('Should cast between field elements', async () => { machineState.memory.set(0, new Field(12345678n)); - await new Cast(/*aOffset=*/ 0, /*dstOffset=*/ 1, TypeTag.FIELD).execute(machineState, journal); + await new Cast(TypeTag.FIELD, /*aOffset=*/ 0, /*dstOffset=*/ 1).execute(machineState, journal); const actual = machineState.memory.get(1); expect(actual).toEqual(new Field(12345678n)); @@ -174,7 +174,7 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('Should move field elements on different memory cells',async () => { + it('Should move field elements on different memory cells', async () => { machineState.memory.set(1, new Field(27)); await new Mov(/*offsetA=*/ 1, /*offsetA=*/ 2).execute(machineState, journal); @@ -187,7 +187,7 @@ describe('Memory instructions', () => { }); describe('CMOV', () => { - it('Should move A if COND is true, on different memory cells (integral condition)',async () => { + it('Should move A if COND is true, on different memory cells (integral condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(2)); // Condition @@ -203,7 +203,7 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT32); }); - it('Should move B if COND is false, on different memory cells (integral condition)',async () => { + it('Should move B if COND is false, on different memory cells (integral condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Uint8(0)); // Condition @@ -219,12 +219,15 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT16); }); - it('Should move A if COND is true, on different memory cells (field condition)',async () => { + it('Should move A if COND is true, on different memory cells (field condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(1)); // Condition - await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( + machineState, + journal, + ); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -232,12 +235,15 @@ describe('Memory instructions', () => { expect(tag).toEqual(TypeTag.UINT32); }); - it('Should move B if COND is false, on different memory cells (integral condition)',async () => { + it('Should move B if COND is false, on different memory cells (integral condition)', async () => { machineState.memory.set(0, new Uint32(123)); // A machineState.memory.set(1, new Uint16(456)); // B machineState.memory.set(2, new Field(0)); // Condition - await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute(machineState, journal); + await new CMov(/*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( + machineState, + journal, + ); const actual = machineState.memory.get(3); const tag = machineState.memory.getTag(3); @@ -247,7 +253,7 @@ describe('Memory instructions', () => { }); describe('CALLDATACOPY', () => { - it('Writes nothing if size is 0',async () => { + it('Writes nothing if size is 0', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten @@ -258,7 +264,7 @@ describe('Memory instructions', () => { expect(actual).toEqual(new Uint16(12)); }); - it('Copies all calldata',async () => { + it('Copies all calldata', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten @@ -269,7 +275,7 @@ describe('Memory instructions', () => { expect(actual).toEqual([new Field(1), new Field(2), new Field(3)]); }); - it('Copies slice of calldata',async () => { + it('Copies slice of calldata', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts index 3ba63a633a7..2524684dc02 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts @@ -5,14 +5,14 @@ import { Instruction } from './instruction.js'; export class Set extends Instruction { static type: string = 'SET'; - static numberOfOperands = 2; + static numberOfOperands = 3; - constructor(private value: bigint, private dstOffset: number, private dstTag: TypeTag) { + constructor(private inTag: TypeTag, private value: bigint, private dstOffset: number) { super(); } async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const res = TaggedMemory.integralFromTag(this.value, this.dstTag); + const res = TaggedMemory.integralFromTag(this.value, this.inTag); machineState.memory.set(this.dstOffset, res); @@ -22,9 +22,9 @@ export class Set extends Instruction { export class Cast extends Instruction { static type: string = 'CAST'; - static numberOfOperands = 2; + static numberOfOperands = 3; - constructor(private aOffset: number, private dstOffset: number, private dstTag: TypeTag) { + constructor(private dstTag: TypeTag, private aOffset: number, private dstOffset: number) { super(); } diff --git a/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts b/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts index 6f3f3709007..97bdfa3181d 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/opcodes.ts @@ -1,5 +1,5 @@ /** - * All AVM opcodes. + * All AVM opcodes. (Keep in sync with cpp counterpart code AvmMini_opcode.hpp). * Source: https://yp-aztec.netlify.app/docs/public-vm/instruction-set */ export enum Opcode { 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 aadbbbb69f1..e62b0abc561 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts @@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/fields'; import { MockProxy, mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { AvmJournal } from '../journal/journal.js'; import { SLoad, SStore, StaticCallStorageAlterError } from './storage.js'; @@ -21,23 +22,23 @@ describe('Storage Instructions', () => { }); it('Sstore should Write into storage', async () => { - const a = new Fr(1n); - const b = new Fr(2n); + const a = new Field(1n); + const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); await new SStore(0, 1).execute(machineState, journal); - expect(journal.writeStorage).toBeCalledWith(address, a, b); + expect(journal.writeStorage).toBeCalledWith(address, new Fr(a.toBigInt()), new Fr(b.toBigInt())); }); it('Should not be able to write to storage in a static call', async () => { const executionEnvironment = initExecutionEnvironment({ isStaticCall: true }); machineState = new AvmMachineState(executionEnvironment); - const a = new Fr(1n); - const b = new Fr(2n); + const a = new Field(1n); + const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); @@ -51,17 +52,17 @@ describe('Storage Instructions', () => { const expectedResult = new Fr(1n); journal.readStorage.mockReturnValueOnce(Promise.resolve(expectedResult)); - const a = new Fr(1n); - const b = new Fr(2n); + const a = new Field(1n); + const b = new Field(2n); machineState.memory.set(0, a); machineState.memory.set(1, b); await new SLoad(0, 1).execute(machineState, journal); - expect(journal.readStorage).toBeCalledWith(address, a); + expect(journal.readStorage).toBeCalledWith(address, new Fr(a.toBigInt())); const actual = machineState.memory.get(1); - expect(actual).toEqual(expectedResult); + expect(actual).toEqual(new Field(expectedResult)); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts index a452b0c422a..c226522b3db 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/storage.ts @@ -1,11 +1,11 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { AvmInterpreterError } from '../interpreter/interpreter.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; -/** - */ export class SStore extends Instruction { static type: string = 'SSTORE'; static numberOfOperands = 2; @@ -15,6 +15,10 @@ export class SStore extends Instruction { } async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + if (machineState.executionEnvironment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + const slot = machineState.memory.get(this.slotOffset); const data = machineState.memory.get(this.dataOffset); @@ -28,21 +32,23 @@ export class SStore extends Instruction { } } -/** - */ export class SLoad extends Instruction { static type: string = 'SLOAD'; static numberOfOperands = 2; - constructor(private slotOffset: number, private destOffset: number) { + constructor(private slotOffset: number, private dstOffset: number) { super(); } async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { const slot = machineState.memory.get(this.slotOffset); - const data = journal.readStorage(machineState.executionEnvironment.storageAddress, new Fr(slot.toBigInt())); + const data: Fr = await journal.readStorage( + machineState.executionEnvironment.storageAddress, + new Fr(slot.toBigInt()), + ); - machineState.memory.set(this.destOffset, await data); + machineState.memory.set(this.dstOffset, new Field(data)); this.incrementPc(machineState); } diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index 775433dbeb8..338810e9477 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -37,6 +37,7 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { FieldsOf } from '@aztec/foundation/types'; +import { AztecLmdbStore } from '@aztec/kv-store'; import { AppendOnlyTree, Pedersen, StandardTree, newTree } from '@aztec/merkle-tree'; import { ChildContractArtifact, @@ -50,8 +51,6 @@ import { import { jest } from '@jest/globals'; import { MockProxy, mock } from 'jest-mock-extended'; -import { default as levelup } from 'levelup'; -import { type MemDown, default as memdown } from 'memdown'; import { getFunctionSelector } from 'viem'; import { KeyPair } from '../acvm/index.js'; @@ -62,8 +61,6 @@ import { AcirSimulator } from './simulator.js'; jest.setTimeout(60_000); -const createMemDown = () => (memdown as any)() as MemDown; - describe('Private Execution test suite', () => { let oracle: MockProxy; let acirSimulator: AcirSimulator; @@ -136,7 +133,7 @@ describe('Private Execution test suite', () => { throw new Error(`Unknown tree ${name}`); } if (!trees[name]) { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const pedersen = new Pedersen(); trees[name] = await newTree(StandardTree, db, pedersen, name, treeHeights[name]); } diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts index 7d7f3d264b7..26fa87f0846 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts @@ -5,7 +5,7 @@ import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { extractReturnWitness } from '../acvm/deserialize.js'; -import { ACVMField, Oracle, acvm, extractCallStack, fromACVMField, toACVMWitness } from '../acvm/index.js'; +import { Oracle, acvm, extractCallStack, toACVMWitness } from '../acvm/index.js'; import { ExecutionError } from '../common/errors.js'; import { AcirSimulator } from '../index.js'; import { ViewDataOracle } from './view_data_oracle.js'; @@ -43,6 +43,5 @@ export async function executeUnconstrainedFunction( ); }); - const returnValues: ACVMField[] = extractReturnWitness(acir, partialWitness); - return decodeReturnValues(artifact, returnValues.map(fromACVMField)); + return decodeReturnValues(artifact, extractReturnWitness(acir, partialWitness)); } diff --git a/yarn-project/acir-simulator/tsconfig.json b/yarn-project/acir-simulator/tsconfig.json index da0e524126f..ce07b84cd9e 100644 --- a/yarn-project/acir-simulator/tsconfig.json +++ b/yarn-project/acir-simulator/tsconfig.json @@ -15,6 +15,9 @@ { "path": "../foundation" }, + { + "path": "../kv-store" + }, { "path": "../merkle-tree" }, diff --git a/yarn-project/archiver/package.json b/yarn-project/archiver/package.json index 6a6048af0d3..226a990ee5e 100644 --- a/yarn-project/archiver/package.json +++ b/yarn-project/archiver/package.json @@ -43,7 +43,7 @@ "@aztec/l1-artifacts": "workspace:^", "@aztec/types": "workspace:^", "debug": "^4.3.4", - "lmdb": "^2.9.1", + "lmdb": "^2.9.2", "lodash.omit": "^4.5.0", "tsc-watch": "^6.0.0", "tslib": "^2.5.0", diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 780020a012c..0269d6bfe80 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -42,12 +42,17 @@ import { retrieveNewPendingL1ToL2Messages, } from './data_retrieval.js'; +/** + * Helper interface to combine all sources this archiver implementation provides. + */ +export type ArchiveSource = L2BlockSource & L2LogsSource & ContractDataSource & L1ToL2MessageSource; + /** * Pulls L2 blocks in a non-blocking manner and provides interface for their retrieval. * Responsible for handling robust L1 polling so that other components do not need to * concern themselves with it. */ -export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource, L1ToL2MessageSource { +export class Archiver implements ArchiveSource { /** * A promise in which we will be continually fetching new L2 blocks. */ diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 3a2446fa0d5..db38f09866a 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -28,10 +28,10 @@ export class BlockStore { #log = createDebugLogger('aztec:archiver:block_store'); constructor(private db: AztecKVStore) { - this.#blocks = db.createMap('archiver_blocks'); + this.#blocks = db.openMap('archiver_blocks'); - this.#txIndex = db.createMap('archiver_tx_index'); - this.#contractIndex = db.createMap('archiver_contract_index'); + this.#txIndex = db.openMap('archiver_tx_index'); + this.#contractIndex = db.openMap('archiver_contract_index'); } /** diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts index 6cd56d90e4d..686514aa1b7 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts @@ -9,7 +9,7 @@ export class ContractClassStore { #contractClasses: AztecMap; constructor(db: AztecKVStore) { - this.#contractClasses = db.createMap('archiver_contract_classes'); + this.#contractClasses = db.openMap('archiver_contract_classes'); } addContractClass(contractClass: ContractClassWithId): Promise { diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_instance_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_instance_store.ts index 7842b54f2f4..fb020eb3c35 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_instance_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_instance_store.ts @@ -9,7 +9,7 @@ export class ContractInstanceStore { #contractInstances: AztecMap; constructor(db: AztecKVStore) { - this.#contractInstances = db.createMap('archiver_contract_instances'); + this.#contractInstances = db.openMap('archiver_contract_instances'); } addContractInstance(contractInstance: ContractInstanceWithAddress): Promise { diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts index 055b25af20d..0c2f117ed92 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts @@ -14,7 +14,7 @@ export class ContractStore { #log = createDebugLogger('aztec:archiver:contract_store'); constructor(private db: AztecKVStore, blockStore: BlockStore) { - this.#extendedContractData = db.createMap('archiver_extended_contract_data'); + this.#extendedContractData = db.openMap('archiver_extended_contract_data'); this.#blockStore = blockStore; } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts index 2903ea6fe9c..520ac236d05 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts @@ -1,4 +1,3 @@ -import { EthAddress } from '@aztec/circuits.js'; import { AztecLmdbStore } from '@aztec/kv-store'; import { describeArchiverDataStore } from '../archiver_store_test_suite.js'; @@ -8,7 +7,7 @@ describe('KVArchiverDataStore', () => { let archiverStore: KVArchiverDataStore; beforeEach(async () => { - archiverStore = new KVArchiverDataStore(await AztecLmdbStore.create(EthAddress.random())); + archiverStore = new KVArchiverDataStore(await AztecLmdbStore.openTmp()); }); describeArchiverDataStore('ArchiverStore', () => archiverStore); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts index afab800fb48..b29e3d67818 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts @@ -23,8 +23,8 @@ export class LogStore { #log = createDebugLogger('aztec:archiver:log_store'); constructor(private db: AztecKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) { - this.#encryptedLogs = db.createMap('archiver_encrypted_logs'); - this.#unencryptedLogs = db.createMap('archiver_unencrypted_logs'); + this.#encryptedLogs = db.openMap('archiver_encrypted_logs'); + this.#unencryptedLogs = db.openMap('archiver_unencrypted_logs'); this.#logsMaxPageSize = logsMaxPageSize; } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts index 81a83e21560..642c90edde3 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts @@ -27,10 +27,10 @@ export class MessageStore { #log = createDebugLogger('aztec:archiver:message_store'); constructor(private db: AztecKVStore) { - this.#messages = db.createMap('archiver_l1_to_l2_messages'); - this.#pendingMessagesByFee = db.createCounter('archiver_messages_by_fee'); - this.#lastL1BlockAddingMessages = db.createSingleton('archiver_last_l1_block_adding_messages'); - this.#lastL1BlockCancellingMessages = db.createSingleton('archiver_last_l1_block_cancelling_messages'); + this.#messages = db.openMap('archiver_l1_to_l2_messages'); + this.#pendingMessagesByFee = db.openCounter('archiver_messages_by_fee'); + this.#lastL1BlockAddingMessages = db.openSingleton('archiver_last_l1_block_adding_messages'); + this.#lastL1BlockCancellingMessages = db.openSingleton('archiver_last_l1_block_cancelling_messages'); } /** diff --git a/yarn-project/archiver/src/index.ts b/yarn-project/archiver/src/index.ts index c2f0d128be8..e47ee3fcc37 100644 --- a/yarn-project/archiver/src/index.ts +++ b/yarn-project/archiver/src/index.ts @@ -8,6 +8,7 @@ import { Archiver, getConfigEnvVars } from './archiver/index.js'; import { MemoryArchiverStore } from './archiver/memory_archiver_store/memory_archiver_store.js'; export * from './archiver/index.js'; +export * from './rpc/index.js'; const log = createDebugLogger('aztec:archiver'); diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts new file mode 100644 index 00000000000..89b9c4bb127 --- /dev/null +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -0,0 +1,33 @@ +import { + ContractData, + EncodedContractFunction, + ExtendedContractData, + ExtendedUnencryptedL2Log, + L1ToL2Message, + L2Block, + L2BlockL2Logs, +} from '@aztec/circuit-types'; +import { EthAddress, Fr } from '@aztec/circuits.js'; +import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client'; + +import { ArchiveSource } from '../index.js'; + +export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], true)): ArchiveSource => + createJsonRpcClient( + url, + { + ContractData, + EncodedContractFunction, + EthAddress, + ExtendedContractData, + ExtendedUnencryptedL2Log, + Fr, + L1ToL2Message, + L2Block, + L2BlockL2Logs, + }, + {}, + false, + 'archiver', + fetch, + ); diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts new file mode 100644 index 00000000000..7c011e5d242 --- /dev/null +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -0,0 +1,37 @@ +import { + ContractData, + EncodedContractFunction, + ExtendedContractData, + ExtendedUnencryptedL2Log, + L1ToL2Message, + L2Block, + L2BlockL2Logs, +} from '@aztec/circuit-types'; +import { EthAddress, Fr } from '@aztec/circuits.js'; +import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; + +import { Archiver } from '../index.js'; + +/** + * Wrap an Archiver instance with a JSON RPC HTTP server. + * @param archiverService - The Archiver instance + * @returns An JSON-RPC HTTP server + */ +export function createArchiverRpcServer(archiverService: Archiver): JsonRpcServer { + return new JsonRpcServer( + archiverService, + { + ContractData, + EncodedContractFunction, + EthAddress, + ExtendedContractData, + ExtendedUnencryptedL2Log, + Fr, + L1ToL2Message, + L2Block, + L2BlockL2Logs, + }, + {}, + ['start', 'stop'], + ); +} diff --git a/yarn-project/archiver/src/rpc/index.ts b/yarn-project/archiver/src/rpc/index.ts new file mode 100644 index 00000000000..726d9120af8 --- /dev/null +++ b/yarn-project/archiver/src/rpc/index.ts @@ -0,0 +1,2 @@ +export * from './archiver_client.js'; +export * from './archiver_server.js'; diff --git a/yarn-project/aztec-node/package.json b/yarn-project/aztec-node/package.json index a2e602a03ff..2c0dd26296c 100644 --- a/yarn-project/aztec-node/package.json +++ b/yarn-project/aztec-node/package.json @@ -47,17 +47,11 @@ "@aztec/world-state": "workspace:^", "koa": "^2.14.2", "koa-router": "^12.0.0", - "levelup": "^5.1.1", - "lmdb": "^2.9.1", - "memdown": "^6.1.1", "tslib": "^2.4.0" }, "devDependencies": { "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", - "@types/leveldown": "^4.0.4", - "@types/levelup": "^5.1.2", - "@types/memdown": "^3.0.0", "@types/node": "^18.7.23", "jest": "^29.5.0", "ts-jest": "^29.1.0", diff --git a/yarn-project/aztec-node/src/aztec-node/config.ts b/yarn-project/aztec-node/src/aztec-node/config.ts index 185bd3d8b6b..73f14115804 100644 --- a/yarn-project/aztec-node/src/aztec-node/config.ts +++ b/yarn-project/aztec-node/src/aztec-node/config.ts @@ -11,6 +11,9 @@ export type AztecNodeConfig = ArchiverConfig & P2PConfig & { /** Whether the sequencer is disabled for this node. */ disableSequencer: boolean; + + /** A URL for an archiver service that the node will use. */ + archiverUrl?: string; }; /** @@ -25,6 +28,7 @@ export function getConfigEnvVars(): AztecNodeConfig { ...getP2PConfigEnvVars(), ...getWorldStateVars(), disableSequencer: !!SEQ_DISABLED, + archiverUrl: process.env.ARCHIVER_URL, }; return allEnvVars; diff --git a/yarn-project/aztec-node/src/aztec-node/db.ts b/yarn-project/aztec-node/src/aztec-node/db.ts deleted file mode 100644 index 9b5be428781..00000000000 --- a/yarn-project/aztec-node/src/aztec-node/db.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { LogFn } from '@aztec/foundation/log'; - -import { LevelDown, default as leveldown } from 'leveldown'; -import { LevelUp, default as levelup } from 'levelup'; -import { RootDatabase, open } from 'lmdb'; -import { MemDown, default as memdown } from 'memdown'; -import { mkdir } from 'node:fs/promises'; -import { join } from 'node:path'; - -import { AztecNodeConfig } from './config.js'; - -export const createMemDown = () => (memdown as any)() as MemDown; -export const createLevelDown = (path: string) => (leveldown as any)(path) as LevelDown; - -const DB_SUBDIR = 'aztec-node-db'; -const WORLD_STATE_SUBDIR = 'aztec-world-state-db'; -const NODE_METADATA_KEY = '@@aztec_node_metadata'; - -/** - * The metadata for an aztec node. - */ -type NodeMetadata = { - /** - * The address of the rollup contract on L1 - */ - rollupContractAddress: string; -}; - -/** - * Opens the database for the aztec node. If a data directory is specified, then this attempts to create it. - * @param config - The configuration to be used by the aztec node. - * @throws If `config.dataDirectory` is set and the directory cannot be created. - * @returns The database for the aztec node. - */ -export async function openDb( - config: AztecNodeConfig, - log: LogFn, -): Promise<[nodeDb: RootDatabase, worldStateDb: LevelUp]> { - const nodeMetadata: NodeMetadata = { - rollupContractAddress: config.l1Contracts.rollupAddress.toString(), - }; - - let nodeDb: RootDatabase; - let worldStateDb: LevelUp; - - if (config.dataDirectory) { - const nodeDir = join(config.dataDirectory, DB_SUBDIR); - const worldStateDir = join(config.dataDirectory, WORLD_STATE_SUBDIR); - // this throws if we don't have permissions to create the directory - await mkdir(nodeDir, { recursive: true }); - await mkdir(worldStateDir, { recursive: true }); - - log(`Opening aztec-node database at ${nodeDir}`); - nodeDb = open(nodeDir, {}); - - log(`Opening world-state database at ${worldStateDir}`); - worldStateDb = levelup(createLevelDown(worldStateDir)); - } else { - log('Opening temporary databases'); - // not passing a path will use a temp file that gets deleted when the process exits - nodeDb = open({}); - worldStateDb = levelup(createMemDown()); - } - - await checkNodeMetadataAndClear(nodeDb, worldStateDb, nodeMetadata, log); - return [nodeDb, worldStateDb]; -} - -/** - * Checks the node metadata and clears the database if the rollup contract address has changed. - * @param nodeDb - The database for the aztec node. - * @param nodeMetadata - The metadata for the aztec node. - */ -async function checkNodeMetadataAndClear( - nodeDb: RootDatabase, - worldStateDb: LevelUp, - nodeMetadata: NodeMetadata, - log: LogFn, -): Promise { - const metadataDB = nodeDb.openDB('metadata', {}); - try { - const existing = metadataDB.get(NODE_METADATA_KEY); - // if the rollup addresses are different, wipe the local database and start over - if (!existing || existing.rollupContractAddress !== nodeMetadata.rollupContractAddress) { - log('Rollup contract address has changed, clearing databases'); - await Promise.all([nodeDb.clearAsync(), worldStateDb.clear()]); - } - await metadataDB.put(NODE_METADATA_KEY, nodeMetadata); - } finally { - await metadataDB.close(); - } -} diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index f5e99becbde..e7a3f80a802 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -43,7 +43,6 @@ export function createAztecNodeRpcServer(node: AztecNode) { L1ToL2MessageAndIndex, }, { Tx, L2BlockL2Logs }, - false, // disable methods not part of the AztecNode interface ['start', 'stop'], ); diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 0c65a9c488d..d94668e5d46 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -1,4 +1,4 @@ -import { Archiver, KVArchiverDataStore } from '@aztec/archiver'; +import { ArchiveSource, Archiver, KVArchiverDataStore, createArchiverClient } from '@aztec/archiver'; import { AztecNode, ContractData, @@ -39,7 +39,7 @@ import { computeGlobalsHash, computePublicDataTreeLeafSlot } from '@aztec/circui import { L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { AztecKVTxPool, P2P, createP2PClient } from '@aztec/p2p'; import { GlobalVariableBuilder, @@ -56,10 +56,7 @@ import { getConfigEnvVars as getWorldStateConfig, } from '@aztec/world-state'; -import { LevelUp } from 'levelup'; - import { AztecNodeConfig } from './config.js'; -import { openDb } from './db.js'; /** * The aztec node. @@ -78,7 +75,7 @@ export class AztecNodeService implements AztecNode { protected readonly chainId: number, protected readonly version: number, protected readonly globalVariableBuilder: GlobalVariableBuilder, - protected readonly merkleTreesDb: LevelUp, + protected readonly merkleTreesDb: AztecKVStore, private log = createDebugLogger('aztec:node'), ) { const message = @@ -106,12 +103,16 @@ export class AztecNodeService implements AztecNode { } const log = createDebugLogger('aztec:node'); - const store = await AztecLmdbStore.create(config.l1Contracts.rollupAddress, config.dataDirectory); - const [_, worldStateDb] = await openDb(config, log); + const store = await AztecLmdbStore.open(config.l1Contracts.rollupAddress, config.dataDirectory); - // first create and sync the archiver - const archiverStore = new KVArchiverDataStore(store, config.maxLogs); - const archiver = await Archiver.createAndSync(config, archiverStore, true); + let archiver: ArchiveSource; + if (!config.archiverUrl) { + // first create and sync the archiver + const archiverStore = new KVArchiverDataStore(store, config.maxLogs); + archiver = await Archiver.createAndSync(config, archiverStore, true); + } else { + archiver = createArchiverClient(config.archiverUrl); + } // we identify the P2P transaction protocol by using the rollup contract address. // this may well change in future @@ -121,14 +122,9 @@ export class AztecNodeService implements AztecNode { const p2pClient = await createP2PClient(store, config, new AztecKVTxPool(store), archiver); // now create the merkle trees and the world state synchronizer - const merkleTrees = await MerkleTrees.new(worldStateDb); + const merkleTrees = await MerkleTrees.new(store); const worldStateConfig: WorldStateConfig = getWorldStateConfig(); - const worldStateSynchronizer = await ServerWorldStateSynchronizer.new( - worldStateDb, - merkleTrees, - archiver, - worldStateConfig, - ); + const worldStateSynchronizer = new ServerWorldStateSynchronizer(store, merkleTrees, archiver, worldStateConfig); // start both and wait for them to sync from the block source await Promise.all([p2pClient.start(), worldStateSynchronizer.start()]); @@ -151,7 +147,7 @@ export class AztecNodeService implements AztecNode { ethereumChain.chainInfo.id, config.version, getGlobalVariableBuilder(config), - worldStateDb, + store, log, ); } @@ -285,8 +281,6 @@ export class AztecNodeService implements AztecNode { await this.p2pClient.stop(); await this.worldStateSynchronizer.stop(); await this.blockSource.stop(); - this.log('Closing Merkle Trees'); - await this.merkleTreesDb.close(); this.log.info(`Stopped`); } diff --git a/yarn-project/aztec-node/src/declaration.d.ts b/yarn-project/aztec-node/src/declaration.d.ts deleted file mode 100644 index d7367c50ba8..00000000000 --- a/yarn-project/aztec-node/src/declaration.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { RootDatabaseOptionsWithPath } from 'lmdb'; - -// The problem is this snippet `nodeDb = open({});` in src/aztec-node/db.ts -// tsc compiles this code fine, but ts-jest can't. -// This is a mixture for two bugs: -// - the first in ts-jest, it gets confused by packages with mixed CJS and ESM type exports - https://github.com/kulshekhar/ts-jest/issues/4221 -// - the second in lmdb, it outputs different CJS and ESM types - https://github.com/kriszyp/lmdb-js/issues/243#issuecomment-1823585586 - -declare module 'lmdb' { - /* eslint-disable jsdoc/require-jsdoc */ - interface RootDatabaseOptionsWithPath { - path?: string; - } - /* eslint-enable jsdoc/require-jsdoc */ -} diff --git a/yarn-project/aztec-node/terraform/main.tf b/yarn-project/aztec-node/terraform/main.tf index becb03ad1b5..a65230f6a16 100644 --- a/yarn-project/aztec-node/terraform/main.tf +++ b/yarn-project/aztec-node/terraform/main.tf @@ -62,7 +62,7 @@ locals { "/dns4/${var.DEPLOY_TAG}-p2p-bootstrap-${i + 1}.local/tcp/${var.BOOTNODE_LISTEN_PORT + i}/p2p/${local.bootnode_ids[i]}" ] combined_bootnodes = join(",", local.bootnodes) - data_dir = "/usr/src/yarn-project/aztec-sandbox/data" + data_dir = "/usr/src/yarn-project/aztec/data" } resource "aws_cloudwatch_log_group" "aztec-node-log-group" { @@ -154,7 +154,7 @@ resource "aws_ecs_task_definition" "aztec-node" { [ { "name": "${var.DEPLOY_TAG}-aztec-node-${count.index + 1}", - "image": "${var.DOCKERHUB_ACCOUNT}/aztec-sandbox:${var.DEPLOY_TAG}", + "image": "${var.DOCKERHUB_ACCOUNT}/aztec:${var.DEPLOY_TAG}", "essential": true, "memoryReservation": 3776, "portMappings": [ diff --git a/yarn-project/aztec-nr/.gitrepo b/yarn-project/aztec-nr/.gitrepo index 15591491fd9..38f265c1fec 100644 --- a/yarn-project/aztec-nr/.gitrepo +++ b/yarn-project/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = 566955a76d9aa4ce026d80f1858ff02bed20dc63 + commit = 149196954fc67dc9c2899eb6a82f50342ed0e020 method = merge cmdver = 0.4.6 - parent = 054763e81fad7a0ea5cba34b6fcebc2f64485524 + parent = 7185271839cad3e66d42db5619c8e70c315b5f3f diff --git a/yarn-project/aztec-nr/aztec/src/context.nr b/yarn-project/aztec-nr/aztec/src/context.nr index 6329a9d541f..fe10eb047fe 100644 --- a/yarn-project/aztec-nr/aztec/src/context.nr +++ b/yarn-project/aztec-nr/aztec/src/context.nr @@ -12,7 +12,7 @@ use crate::{ enqueue_public_function_call::enqueue_public_function_call_internal, context::get_portal_address, get_block_header::get_block_header, - nullifier_key::get_nullifier_key_pair, + nullifier_key::{get_nullifier_key_pair, NullifierKeyPair}, }, types::vec::BoundedVec, utils::Reader, @@ -23,6 +23,7 @@ use dep::protocol_types::{ call_context::CallContext, function_data::FunctionData, function_selector::FunctionSelector, + nullifier_key_validation_request::NullifierKeyValidationRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, public_circuit_public_inputs::PublicCircuitPublicInputs, call_stack_item::PrivateCallStackItem, @@ -42,6 +43,7 @@ use dep::protocol_types::{ MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH, }, @@ -50,11 +52,11 @@ use dep::protocol_types::{ storage_read::StorageRead, storage_update_request::StorageUpdateRequest, }, - hash::hash_args, grumpkin_point::GrumpkinPoint, + grumpkin_private_key::GrumpkinPrivateKey, + hash::hash_args, }; use dep::std::{ - grumpkin_scalar::GrumpkinScalar, option::Option, }; @@ -71,6 +73,7 @@ struct PrivateContext { return_values : BoundedVec, read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, new_commitments: BoundedVec, new_nullifiers: BoundedVec, @@ -85,6 +88,8 @@ struct PrivateContext { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) // encrypted_logs_preimages: Vec, // unencrypted_logs_preimages: Vec, + + nullifier_key: Option, } impl PrivateContext { @@ -97,6 +102,7 @@ impl PrivateContext { return_values: BoundedVec::new(0), read_requests: BoundedVec::new(SideEffect::empty()), + nullifier_key_validation_requests: BoundedVec::new(NullifierKeyValidationRequest::empty()), new_commitments: BoundedVec::new(SideEffect::empty()), new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), @@ -110,6 +116,8 @@ impl PrivateContext { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) // encrypted_logs_preimages: Vec::new(), // unencrypted_logs_preimages: Vec::new(), + + nullifier_key: Option::none(), } } @@ -153,6 +161,7 @@ impl PrivateContext { args_hash: self.args_hash, return_values: self.return_values.storage, read_requests: self.read_requests.storage, + nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, private_call_stack_hashes: self.private_call_stack_hashes.storage, @@ -199,11 +208,21 @@ impl PrivateContext { self.side_effect_counter = self.side_effect_counter + 1; } - pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinScalar { - let key_pair = get_nullifier_key_pair(account); - validate_nullifier_key_against_address(account, key_pair.public_key, key_pair.secret_key); - // TODO: Add request to context. - // self.context.push_nullifier_key_validation_request(public_key, secret_key); + pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinPrivateKey { + let key_pair = if self.nullifier_key.is_none() { + let key_pair = get_nullifier_key_pair(account); + validate_nullifier_key_against_address(account, key_pair.public_key); + let request = NullifierKeyValidationRequest { public_key: key_pair.public_key, secret_key: key_pair.secret_key }; + self.nullifier_key_validation_requests.push(request); + self.nullifier_key = Option::some(key_pair); + key_pair + } else { + let key_pair = self.nullifier_key.unwrap_unchecked(); + // If MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is larger than 1, need to update the way the key pair is cached. + assert(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL == 1); + assert(key_pair.account == account, "Cannot query nullifier key for more than one account per call"); + key_pair + }; key_pair.secret_key } @@ -300,6 +319,7 @@ impl PrivateContext { args_hash: reader.read(), return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), // +1 read_requests: reader.read_struct_array(SideEffect::deserialise, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), + nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialise, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), new_commitments: reader.read_struct_array(SideEffect::deserialise, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialise, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), private_call_stack_hashes: reader.read_array([0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), diff --git a/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr index d156618d326..61e1541e820 100644 --- a/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr @@ -3,7 +3,7 @@ use dep::std::merkle::compute_merkle_root; use crate::{ context::PrivateContext, note::{ - utils::compute_unique_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, note_header::NoteHeader, note_interface::NoteInterface, }, @@ -35,7 +35,7 @@ pub fn prove_note_inclusion( block_number: u32, // The block at which we'll prove that the note exists context: PrivateContext ) { - let note_commitment = compute_unique_siloed_note_hash(note_interface, note_with_header); + let note_commitment = compute_note_hash_for_read_or_nullify(note_interface, note_with_header); prove_note_commitment_inclusion(note_commitment, block_number, context); } diff --git a/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr b/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr index 3f07dba4b2c..0b93dc87b77 100644 --- a/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr +++ b/yarn-project/aztec-nr/aztec/src/key/nullifier_key.nr @@ -1,24 +1,8 @@ -use crate::oracle::get_public_key::get_public_key; use dep::protocol_types::{ address::AztecAddress, grumpkin_point::GrumpkinPoint, }; -use dep::std::{ - grumpkin_scalar::GrumpkinScalar, - grumpkin_scalar_mul::grumpkin_fixed_base, -}; -pub fn validate_nullifier_key_against_address( - address: AztecAddress, - nullifier_public_key: GrumpkinPoint, - nullifier_secret_key: GrumpkinScalar -) { +pub fn validate_nullifier_key_against_address(_address: AztecAddress, _nullifier_public_key: GrumpkinPoint) { // TODO: Nullifier public key should be part of the address. - // Validation of the secret key should happen in the kernel circuit. - let owner_public_key = get_public_key(address); - assert(owner_public_key.x == nullifier_public_key.x); - assert(owner_public_key.y == nullifier_public_key.y); - let computed_public_key = grumpkin_fixed_base(nullifier_secret_key); - assert(owner_public_key.x == computed_public_key[0]); - assert(owner_public_key.y == computed_public_key[1]); } diff --git a/yarn-project/aztec-nr/aztec/src/note.nr b/yarn-project/aztec-nr/aztec/src/note.nr index 5df51e71dd4..b457a126b2d 100644 --- a/yarn-project/aztec-nr/aztec/src/note.nr +++ b/yarn-project/aztec-nr/aztec/src/note.nr @@ -1,7 +1,6 @@ mod lifecycle; mod note_getter; mod note_getter_options; -mod note_hash; mod note_header; mod note_interface; mod note_viewer_options; diff --git a/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr b/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr index ec741e6dbae..d91154e72d8 100644 --- a/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr +++ b/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr @@ -6,7 +6,7 @@ use crate::context::{ use crate::note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_inner_note_hash, + utils::compute_note_hash_for_read_or_nullify, }; use crate::oracle::notes::{notify_created_note, notify_nullified_note}; @@ -22,7 +22,8 @@ pub fn create_note( let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; let set_header = note_interface.set_header; set_header(note, header); - let inner_note_hash = compute_inner_note_hash(note_interface, *note); + // As `is_transient` is true, this will compute the inner note hsah + let inner_note_hash = compute_note_hash_for_read_or_nullify(note_interface, *note); let serialize = note_interface.serialize; let serialized_note = serialize(*note); @@ -47,7 +48,7 @@ pub fn create_note_hash_from_public( let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; let set_header = note_interface.set_header; set_header(note, header); - let inner_note_hash = compute_inner_note_hash(note_interface, *note); + let inner_note_hash = compute_note_hash_for_read_or_nullify(note_interface, *note); context.push_new_note_hash(inner_note_hash); } @@ -72,7 +73,7 @@ pub fn destroy_note( // just siloes and forwards the nullifier to its output. if (header.is_transient) { // TODO(1718): Can we reuse the note commitment computed in `compute_nullifier`? - nullified_commitment = compute_inner_note_hash(note_interface, note); + nullified_commitment = compute_note_hash_for_read_or_nullify(note_interface, note); } assert(notify_nullified_note(nullifier, nullified_commitment) == 0); diff --git a/yarn-project/aztec-nr/aztec/src/note/note_hash.nr b/yarn-project/aztec-nr/aztec/src/note/note_hash.nr deleted file mode 100644 index 8f0abd7d3db..00000000000 --- a/yarn-project/aztec-nr/aztec/src/note/note_hash.nr +++ /dev/null @@ -1,23 +0,0 @@ -use dep::protocol_types::{ - address::AztecAddress, - constants::{ - GENERATOR_INDEX__UNIQUE_COMMITMENT, - GENERATOR_INDEX__SILOED_COMMITMENT, - }, - hash::pedersen_hash, -}; - -pub fn compute_inner_hash(storage_slot: Field, note_hash: Field) -> Field { - // TODO(#1205) Do we need a generator index here? - pedersen_hash([storage_slot, note_hash], 0) -} - -pub fn compute_siloed_hash(contract_address: AztecAddress, inner_note_hash: Field) -> Field { - let inputs = [contract_address.to_field(), inner_note_hash]; - pedersen_hash(inputs, GENERATOR_INDEX__SILOED_COMMITMENT) -} - -pub fn compute_unique_hash(nonce: Field, siloed_note_hash: Field) -> Field { - let inputs = [nonce, siloed_note_hash]; - pedersen_hash(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT) -} diff --git a/yarn-project/aztec-nr/aztec/src/note/utils.nr b/yarn-project/aztec-nr/aztec/src/note/utils.nr index 5d88d904a77..e38a141e6cd 100644 --- a/yarn-project/aztec-nr/aztec/src/note/utils.nr +++ b/yarn-project/aztec-nr/aztec/src/note/utils.nr @@ -1,18 +1,38 @@ -use dep::protocol_types::{ - constants::GENERATOR_INDEX__OUTER_NULLIFIER, - hash::pedersen_hash, -}; use crate::{ context::PrivateContext, note::{ - note_hash::{compute_inner_hash, compute_siloed_hash, compute_unique_hash}, note_header::NoteHeader, note_interface::NoteInterface, }, utils::arr_copy_slice, }; -pub fn compute_inner_note_hash(note_interface: NoteInterface, note: Note) -> Field { +use dep::protocol_types::{ + address::AztecAddress, + constants::{ + GENERATOR_INDEX__OUTER_NULLIFIER, + GENERATOR_INDEX__UNIQUE_COMMITMENT, + GENERATOR_INDEX__SILOED_COMMITMENT, + }, + hash::pedersen_hash, +}; + +fn compute_inner_hash(storage_slot: Field, note_hash: Field) -> Field { + // TODO(#1205) Do we need a generator index here? + pedersen_hash([storage_slot, note_hash], 0) +} + +fn compute_siloed_hash(contract_address: AztecAddress, inner_note_hash: Field) -> Field { + let inputs = [contract_address.to_field(), inner_note_hash]; + pedersen_hash(inputs, GENERATOR_INDEX__SILOED_COMMITMENT) +} + +fn compute_unique_hash(nonce: Field, siloed_note_hash: Field) -> Field { + let inputs = [nonce, siloed_note_hash]; + pedersen_hash(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT) +} + +fn compute_inner_note_hash(note_interface: NoteInterface, note: Note) -> Field { let get_header = note_interface.get_header; let header = get_header(note); @@ -22,7 +42,7 @@ pub fn compute_inner_note_hash(note_interface: NoteInterface, compute_inner_hash(header.storage_slot, note_hash) } -pub fn compute_siloed_note_hash(note_interface: NoteInterface, note_with_header: Note) -> Field { +fn compute_siloed_note_hash(note_interface: NoteInterface, note_with_header: Note) -> Field { let get_header = note_interface.get_header; let header = get_header(note_with_header); @@ -31,7 +51,7 @@ pub fn compute_siloed_note_hash(note_interface: NoteInterface, compute_siloed_hash(header.contract_address, inner_note_hash) } -pub fn compute_unique_siloed_note_hash(note_interface: NoteInterface, note_with_header: Note) -> Field { +fn compute_unique_siloed_note_hash(note_interface: NoteInterface, note_with_header: Note) -> Field { let get_header = note_interface.get_header; let header = get_header(note_with_header); diff --git a/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr b/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr index b97b2d651a3..a99b946752f 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/nullifier_key.nr @@ -1,29 +1,31 @@ use dep::protocol_types::{ address::AztecAddress, grumpkin_point::GrumpkinPoint, + grumpkin_private_key::GrumpkinPrivateKey, }; -use dep::std::grumpkin_scalar::GrumpkinScalar; -struct KeyPair { +struct NullifierKeyPair { + account: AztecAddress, public_key: GrumpkinPoint, - secret_key: GrumpkinScalar, + secret_key: GrumpkinPrivateKey, } #[oracle(getNullifierKeyPair)] fn get_nullifier_key_pair_oracle(_account: AztecAddress) -> [Field; 4] {} -unconstrained fn get_nullifier_key_pair_internal(account: AztecAddress) -> KeyPair { +unconstrained fn get_nullifier_key_pair_internal(account: AztecAddress) -> NullifierKeyPair { let result = get_nullifier_key_pair_oracle(account); - KeyPair { + NullifierKeyPair { + account, public_key: GrumpkinPoint { x: result[0], y: result[1] }, - secret_key: GrumpkinScalar { high: result[2], low: result[3] } + secret_key: GrumpkinPrivateKey { high: result[2], low: result[3] } } } -pub fn get_nullifier_key_pair(account: AztecAddress) -> KeyPair { +pub fn get_nullifier_key_pair(account: AztecAddress) -> NullifierKeyPair { get_nullifier_key_pair_internal(account) } -pub fn get_nullifier_secret_key(account: AztecAddress) -> GrumpkinScalar { +pub fn get_nullifier_secret_key(account: AztecAddress) -> GrumpkinPrivateKey { get_nullifier_key_pair_internal(account).secret_key } diff --git a/yarn-project/aztec-sandbox/src/bin/index.ts b/yarn-project/aztec-sandbox/src/bin/index.ts deleted file mode 100644 index 97aa2d790ea..00000000000 --- a/yarn-project/aztec-sandbox/src/bin/index.ts +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env -S node --no-warnings -import { deployInitialTestAccounts } from '@aztec/accounts/testing'; -import { createAztecNodeRpcServer, getConfigEnvVars as getNodeConfigEnvVars } from '@aztec/aztec-node'; -import { AccountManager, createAztecNodeClient } from '@aztec/aztec.js'; -import { NULL_KEY } from '@aztec/ethereum'; -import { init } from '@aztec/foundation/crypto'; -import { createStatusRouter, startHttpRpcServer } from '@aztec/foundation/json-rpc/server'; -import { createDebugLogger } from '@aztec/foundation/log'; -import { fileURLToPath } from '@aztec/foundation/url'; -import { BootstrapNode, getP2PConfigEnvVars } from '@aztec/p2p'; -import { GrumpkinScalar, PXEService, createPXERpcServer } from '@aztec/pxe'; - -import { lookup } from 'dns/promises'; -import { readFileSync } from 'fs'; -import http from 'http'; -import { dirname, resolve } from 'path'; -import { mnemonicToAccount } from 'viem/accounts'; - -import { setupFileDebugLog } from '../logging.js'; -import { MNEMONIC, createAztecNode, createAztecPXE, createSandbox, deployContractsToL1 } from '../sandbox.js'; -import { github, splash } from '../splash.js'; - -/** - * The mode in which the sandbox should be run. - */ -enum SandboxMode { - Sandbox = 'sandbox', - Node = 'node', - PXE = 'pxe', - P2PBootstrap = 'p2p-bootstrap', -} - -/** - * If we can successfully resolve 'host.docker.internal', then we are running in a container, and we should treat - * localhost as being host.docker.internal. - */ -const getLocalhost = () => - lookup('host.docker.internal') - .then(() => 'host.docker.internal') - .catch(() => 'localhost'); - -const LOCALHOST = await getLocalhost(); -const { - AZTEC_NODE_URL = `http://${LOCALHOST}:8079`, - AZTEC_NODE_PORT = 8079, - PXE_PORT = 8080, - MODE = 'sandbox', - TEST_ACCOUNTS = 'true', - DEPLOY_AZTEC_CONTRACTS = 'true', - API_PREFIX = '', -} = process.env; - -const logger = createDebugLogger(`aztec:${MODE}`); - -/** - * Creates the sandbox from provided config and deploys any initial L1 and L2 contracts - */ -async function createAndInitialiseSandbox(deployTestAccounts: boolean) { - const { aztecNodeConfig, node, pxe, stop } = await createSandbox(); - if (aztecNodeConfig.p2pEnabled) { - logger.info(`Not setting up test accounts as we are connecting to a network`); - return { - aztecNodeConfig, - pxe, - node, - stop, - accounts: [], - }; - } - let accounts; - if (deployTestAccounts) { - logger.info('Setting up test accounts...'); - accounts = await deployInitialTestAccounts(pxe); - } - return { - aztecNodeConfig, - pxe, - node, - stop, - accounts, - }; -} - -/** - * Create and start a new Aztec RPC HTTP Server - */ -async function main() { - const deployTestAccounts = TEST_ACCOUNTS === 'true'; - const deployAztecContracts = DEPLOY_AZTEC_CONTRACTS === 'true'; - - const mode = MODE as SandboxMode; - - const installSignalHandlers = (cb?: () => Promise) => { - const shutdown = async () => { - logger.info('Shutting down...'); - if (cb) { - await cb(); - } - process.exit(0); - }; - process.removeAllListeners('SIGINT'); - process.removeAllListeners('SIGTERM'); - process.once('SIGINT', shutdown); - process.once('SIGTERM', shutdown); - }; - - installSignalHandlers(); - - // Init crypto (bb.js). - await init(); - - const logStrings = []; - - const logPath = setupFileDebugLog(); - logger.info(`Debug logs will be written to ${logPath}`); - - // Get Sandbox version - const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); - const version = JSON.parse(readFileSync(packageJsonPath).toString()).version; - - // Code path for starting Sandbox - if (mode === SandboxMode.Sandbox) { - logger.info(`Setting up Aztec Sandbox v${version} please stand by...`); - - const { pxe, node, stop, accounts } = await createAndInitialiseSandbox(deployTestAccounts); - - // Create shutdown cleanup function - installSignalHandlers(stop); - - // Start Node and PXE JSON-RPC servers - startHttpRpcServer(node, createAztecNodeRpcServer, AZTEC_NODE_PORT); - logger.info(`Aztec Node JSON-RPC Server listening on port ${AZTEC_NODE_PORT}`); - startHttpRpcServer(pxe, createPXERpcServer, PXE_PORT); - logger.info(`PXE JSON-RPC Server listening on port ${PXE_PORT}`); - - // Log initial accounts details - if (accounts?.length) { - const accountLogStrings = await createAccountLogs(accounts, pxe); - logStrings.push(...accountLogStrings); - } - logStrings.push(`Aztec Sandbox v${version} is now ready for use!`); - } else if (mode === SandboxMode.Node) { - // Code path for starting Node only - const nodeConfig = getNodeConfigEnvVars(); - const hdAccount = mnemonicToAccount(MNEMONIC); - - // Deploy L1 Aztec Contracts if needed - if (deployAztecContracts) { - await deployContractsToL1(nodeConfig, hdAccount); - if (nodeConfig.publisherPrivateKey === NULL_KEY) { - const privKey = hdAccount.getHdKey().privateKey; - nodeConfig.publisherPrivateKey = `0x${Buffer.from(privKey!).toString('hex')}`; - } - } - - const node = await createAztecNode(nodeConfig); - installSignalHandlers(node.stop); - - const port = process.env.AZTEC_NODE_PORT || 8080; // Use standard 8080 when no PXE is running - const nodeRpcServer = createAztecNodeRpcServer(node); - const app = nodeRpcServer.getApp(API_PREFIX); - - // Add a /status endpoint - const statusRouter = createStatusRouter(API_PREFIX); - app.use(statusRouter.routes()); - app.use(statusRouter.allowedMethods()); - - // Start Node JSON-RPC server - const httpServer = http.createServer(app.callback()); - httpServer.listen(port); - - logStrings.push(`Aztec Node v${version} is now ready for use in port ${port}!`); - } else if (mode === SandboxMode.PXE) { - // Code path for starting PXE only - - // Create a Node client to connect to the PXE - const node = createAztecNodeClient(AZTEC_NODE_URL); - - const pxe = await createAztecPXE(node); - installSignalHandlers(pxe.stop); - - // Start PXE JSON-RPC server - startHttpRpcServer(pxe, createPXERpcServer, PXE_PORT); - - if (deployTestAccounts) { - logger.info('Setting up test accounts...'); - const accounts = await deployInitialTestAccounts(pxe); - const accountLogStrings = await createAccountLogs(accounts, pxe); - logStrings.push(...accountLogStrings); - } - - logStrings.push(`PXE v${version} is now ready for use in port ${PXE_PORT}!`); - } else if (mode === SandboxMode.P2PBootstrap) { - // Code path for starting a P2P bootstrap node - const config = getP2PConfigEnvVars(); - const bootstrapNode = new BootstrapNode(logger); - await bootstrapNode.start(config); - installSignalHandlers(bootstrapNode.stop); - logStrings.push( - `Bootstrap P2P node is now ready for use. Listening on: ${config.tcpListenIp}:${config.tcpListenPort}.`, - ); - } - - // Log startup details - logger.info(`${splash}\n${github}\n\n`.concat(...logStrings)); -} - -/** - * Creates logs for the initial accounts - * @param accounts - The initial accounts - * @param pxe - A PXE instance to get the registered accounts - * @returns A string array containing the initial accounts details - */ -async function createAccountLogs( - accounts: { - /** - * The account object - */ - account: AccountManager; - /** - * The private key of the account - */ - privateKey: GrumpkinScalar; - }[], - pxe: PXEService, -) { - const registeredAccounts = await pxe.getRegisteredAccounts(); - const accountLogStrings = [`Initial Accounts:\n\n`]; - for (const account of accounts) { - const completeAddress = account.account.getCompleteAddress(); - if (registeredAccounts.find(a => a.equals(completeAddress))) { - accountLogStrings.push(` Address: ${completeAddress.address.toString()}\n`); - accountLogStrings.push(` Partial Address: ${completeAddress.partialAddress.toString()}\n`); - accountLogStrings.push(` Private Key: ${account.privateKey.toString()}\n`); - accountLogStrings.push(` Public Key: ${completeAddress.publicKey.toString()}\n\n`); - } - } - return accountLogStrings; -} - -main().catch(err => { - logger.error(err); - process.exit(1); -}); diff --git a/yarn-project/aztec.js/src/contract/index.ts b/yarn-project/aztec.js/src/contract/index.ts index eb3c16064d3..b7d5c4b6742 100644 --- a/yarn-project/aztec.js/src/contract/index.ts +++ b/yarn-project/aztec.js/src/contract/index.ts @@ -1,7 +1,7 @@ /** * The `contract` module provides utilities for deploying and interacting with contracts, based on a * `Wallet` instance and a compiled artifact. Refer to the {@link account} module for how to obtain a valid - * `Wallet` instance, and to the {@link https://docs.aztec.network/dev_docs/contracts/compiling | Compiling contracts} + * `Wallet` instance, and to the {@link https://docs.aztec.network/developers/contracts/compiling | Compiling contracts} * section of the documentation for how to generate an artifact out of your Noir source code. * * The {@link Contract} class is the main class in this module, and provides static methods for deploying @@ -30,7 +30,7 @@ * has synchronized its changes. * * @remarks If you are using typescript, consider using the - * {@link https://docs.aztec.network/dev_docs/contracts/compiling#typescript-interfaces | autogenerated type-safe interfaces} + * {@link https://docs.aztec.network/developers/contracts/compiling#typescript-interfaces | autogenerated type-safe interfaces} * for interacting with your contracts. * * @packageDocumentation diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index bc5558c8d9f..9446b4cc5d7 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -48,7 +48,7 @@ export { waitForAccountSynch, } from './utils/index.js'; -export { createPXEClient } from './pxe_client.js'; +export { createPXEClient } from './rpc_clients/index.js'; export { AuthWitnessProvider } from './account/index.js'; @@ -108,7 +108,6 @@ export { mockTx, Comparator, } from '@aztec/circuit-types'; - export { NodeInfo } from '@aztec/types/interfaces'; // TODO: These kinds of things have no place on our public api. diff --git a/yarn-project/aztec.js/src/rpc_clients/index.ts b/yarn-project/aztec.js/src/rpc_clients/index.ts new file mode 100644 index 00000000000..8dfa33a26d6 --- /dev/null +++ b/yarn-project/aztec.js/src/rpc_clients/index.ts @@ -0,0 +1 @@ +export * from './pxe_client.js'; diff --git a/yarn-project/aztec.js/src/pxe_client.ts b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts similarity index 94% rename from yarn-project/aztec.js/src/pxe_client.ts rename to yarn-project/aztec.js/src/rpc_clients/pxe_client.ts index 86ab174e769..296daead28b 100644 --- a/yarn-project/aztec.js/src/pxe_client.ts +++ b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts @@ -26,8 +26,6 @@ import { } from '@aztec/circuits.js'; import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client'; -export { makeFetch } from '@aztec/foundation/json-rpc/client'; - /** * Creates a JSON-RPC client to remotely talk to PXE. * @param url - The URL of the PXE. @@ -59,5 +57,6 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], true)) }, { Tx, TxReceipt, L2BlockL2Logs }, false, + 'pxe', fetch, ); diff --git a/yarn-project/aztec.js/src/utils/l1_contracts.ts b/yarn-project/aztec.js/src/utils/l1_contracts.ts index 9fd0e5d2b63..d0230c8f329 100644 --- a/yarn-project/aztec.js/src/utils/l1_contracts.ts +++ b/yarn-project/aztec.js/src/utils/l1_contracts.ts @@ -1,7 +1,7 @@ import { L1ContractAddresses } from '@aztec/ethereum'; import { retryUntil } from '@aztec/foundation/retry'; -import { createPXEClient } from '../pxe_client.js'; +import { createPXEClient } from '../rpc_clients/index.js'; export const getL1ContractAddresses = async (url: string): Promise => { const pxeClient = createPXEClient(url); diff --git a/yarn-project/aztec-sandbox/.eslintrc.cjs b/yarn-project/aztec/.eslintrc.cjs similarity index 100% rename from yarn-project/aztec-sandbox/.eslintrc.cjs rename to yarn-project/aztec/.eslintrc.cjs diff --git a/yarn-project/aztec-sandbox/.gitignore b/yarn-project/aztec/.gitignore similarity index 100% rename from yarn-project/aztec-sandbox/.gitignore rename to yarn-project/aztec/.gitignore diff --git a/yarn-project/aztec-sandbox/Dockerfile b/yarn-project/aztec/Dockerfile similarity index 85% rename from yarn-project/aztec-sandbox/Dockerfile rename to yarn-project/aztec/Dockerfile index afdfb2094e1..e8a8e8d45d1 100644 --- a/yarn-project/aztec-sandbox/Dockerfile +++ b/yarn-project/aztec/Dockerfile @@ -1,6 +1,6 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-prod AS yarn-project-prod -ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/aztec-sandbox/dest/bin/index.js"] -EXPOSE 8079 8080 +ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/aztec/dest/bin/index.js"] +EXPOSE 8080 # The version has been updated in yarn-project-prod. # Adding COMMIT_TAG here to rebuild versioned image. diff --git a/yarn-project/aztec-sandbox/README.md b/yarn-project/aztec/README.md similarity index 72% rename from yarn-project/aztec-sandbox/README.md rename to yarn-project/aztec/README.md index b901d0b8b9d..2c01123c7b4 100644 --- a/yarn-project/aztec-sandbox/README.md +++ b/yarn-project/aztec/README.md @@ -1,6 +1,6 @@ -# aztec-sandbox +# aztec -Aztec Sandbox is a package that allows for a simple development environment on Aztec stack. It creates a Private eXecution Environment (PXE) that listens for HTTP requests on `localhost:8080` by default. When started, it deploys all necessary L1 Aztec contracts and then starts listening for RPC requests. +Aztec is a package that allows for a simple development environment on Aztec stack. It creates a Private eXecution Environment (PXE) that listens for HTTP requests on `localhost:8080` by default. When started, it deploys all necessary L1 Aztec contracts and then starts listening for RPC requests. ## How to run: @@ -38,7 +38,7 @@ Before running locally you'll need to: - `yarn build` And you should be good to go! -From the `aztec-sandbox` directory, you can run the two existing examples: +From the `aztec` directory, you can run the two existing examples: - Deployment, mint and transfer on an Aztec Private Token - `yarn run:example:token` @@ -54,4 +54,4 @@ export FORK_URL= ## Publishing This package is set-up to be published on dockerhub by CI whenever there's a tagged release on `master` branch. -It's published under the tags `aztecprotocol/aztec-sandbox:latest` & `aztecprotocol/aztec-sandbox:`. +It's published under the tags `aztecprotocol/aztec:latest` & `aztecprotocol/aztec:`. diff --git a/yarn-project/aztec-sandbox/docker-compose.yml b/yarn-project/aztec/docker-compose.yml similarity index 85% rename from yarn-project/aztec-sandbox/docker-compose.yml rename to yarn-project/aztec/docker-compose.yml index 2741f74c069..84397ba70b7 100644 --- a/yarn-project/aztec-sandbox/docker-compose.yml +++ b/yarn-project/aztec/docker-compose.yml @@ -7,7 +7,7 @@ services: if [ -n "$FORK_BLOCK_NUMBER" ] && [ -n "$FORK_URL" ]; then exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --silent --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" elif [ -n "$FORK_URL" ]; then - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --silent --fork-url "$FORK_URL" + exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --silent --fork-url "$FORK_URL" else exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --silent fi' @@ -15,9 +15,8 @@ services: - '${SANDBOX_ANVIL_PORT:-8545}:8545' aztec: - image: 'aztecprotocol/aztec-sandbox:${SANDBOX_VERSION:-latest}' + image: 'aztecprotocol/aztec:${SANDBOX_VERSION:-latest}' ports: - - '${SANDBOX_AZTEC_NODE_PORT:-8079}:8079' - '${SANDBOX_PXE_PORT:-8080}:8080' environment: DEBUG: # Loaded from the user shell if explicitly set @@ -31,4 +30,4 @@ services: PXE_BLOCK_POLLING_INTERVAL_MS: 50 ARCHIVER_VIEM_POLLING_INTERVAL_MS: 500 volumes: - - ./log:/usr/src/yarn-project/aztec-sandbox/log:rw + - ./log:/usr/src/yarn-project/aztec/log:rw diff --git a/yarn-project/aztec-sandbox/package.json b/yarn-project/aztec/package.json similarity index 92% rename from yarn-project/aztec-sandbox/package.json rename to yarn-project/aztec/package.json index 30d0f41da34..fbc0b5dcb20 100644 --- a/yarn-project/aztec-sandbox/package.json +++ b/yarn-project/aztec/package.json @@ -1,5 +1,5 @@ { - "name": "@aztec/aztec-sandbox", + "name": "@aztec/aztec", "version": "0.1.0", "type": "module", "exports": { @@ -10,7 +10,7 @@ "entryPoints": [ "./src/index.ts" ], - "name": "Sandbox", + "name": "Aztec Packages", "tsconfig": "./tsconfig.json" }, "scripts": { @@ -28,18 +28,21 @@ ], "dependencies": { "@aztec/accounts": "workspace:^", + "@aztec/archiver": "workspace:^", "@aztec/aztec-node": "workspace:^", "@aztec/aztec.js": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/ethereum": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/kv-store": "workspace:^", "@aztec/l1-artifacts": "workspace:^", "@aztec/noir-compiler": "workspace:^", "@aztec/noir-contracts": "workspace:^", "@aztec/p2p": "workspace:^", "@aztec/pxe": "workspace:^", "abitype": "^0.8.11", + "commander": "^11.1.0", "koa": "^2.14.2", "koa-router": "^12.0.0", "viem": "^1.2.5", diff --git a/yarn-project/aztec/src/aztec_client.ts b/yarn-project/aztec/src/aztec_client.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/yarn-project/aztec/src/bin/index.ts b/yarn-project/aztec/src/bin/index.ts new file mode 100644 index 00000000000..b463e48c895 --- /dev/null +++ b/yarn-project/aztec/src/bin/index.ts @@ -0,0 +1,66 @@ +import { deployInitialTestAccounts } from '@aztec/accounts/testing'; +import { createAztecNodeRpcServer } from '@aztec/aztec-node'; +import { fileURLToPath } from '@aztec/aztec.js'; +import { createNamespacedJsonRpcServer } from '@aztec/foundation/json-rpc/server'; +import { createConsoleLogger, createDebugLogger } from '@aztec/foundation/log'; +import { createPXERpcServer } from '@aztec/pxe'; + +import { readFileSync } from 'fs'; +import http from 'http'; +import { dirname, resolve } from 'path'; + +import { getProgram } from '../cli/index.js'; +import { createAccountLogs, installSignalHandlers } from '../cli/util.js'; +import { createSandbox } from '../sandbox.js'; +import { github, splash } from '../splash.js'; + +const userLog = createConsoleLogger(); +const debugLogger = createDebugLogger('aztec:cli'); + +const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); +const cliVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version; + +const { TEST_ACCOUNTS = 'true', PORT = '8080' } = process.env; + +/** CLI & full node main entrypoint */ +async function main() { + if (process.argv.length > 2) { + // If CLI arguments were provided, run the CLI program. + const cliProgram = getProgram(userLog, debugLogger); + await cliProgram.parseAsync(process.argv); + } else { + // If no CLI arguments were provided, run aztec full node for sandbox usage. + userLog(`${splash}\n${github}\n\n`); + userLog(`Setting up Aztec Sandbox v${cliVersion}, please stand by...`); + const { aztecNodeConfig, node, pxe, stop } = await createSandbox(); + installSignalHandlers(userLog, [stop]); + + // Deploy test accounts by default + if (TEST_ACCOUNTS === 'true') { + if (aztecNodeConfig.p2pEnabled) { + userLog(`Not setting up test accounts as we are connecting to a network`); + } else { + userLog('Setting up test accounts...'); + const accounts = await deployInitialTestAccounts(pxe); + const accLogs = await createAccountLogs(accounts, pxe); + userLog(accLogs.join('')); + } + } + + // Start Node and PXE JSON-RPC server + const nodeServer = createAztecNodeRpcServer(node); + const pxeServer = createPXERpcServer(pxe); + const rpcServer = createNamespacedJsonRpcServer([{ node: nodeServer }, { pxe: pxeServer }], debugLogger); + + const app = rpcServer.getApp(); + const httpServer = http.createServer(app.callback()); + httpServer.listen(PORT); + userLog(`Aztec Server listening on port ${PORT}`); + } +} + +main().catch(err => { + debugLogger(`Error in command execution`); + debugLogger(err); + process.exit(1); +}); diff --git a/yarn-project/aztec/src/cli/cli.ts b/yarn-project/aztec/src/cli/cli.ts new file mode 100644 index 00000000000..da6b97a454b --- /dev/null +++ b/yarn-project/aztec/src/cli/cli.ts @@ -0,0 +1,70 @@ +import { fileURLToPath } from '@aztec/aztec.js'; +import { ServerList, createNamespacedJsonRpcServer } from '@aztec/foundation/json-rpc/server'; +import { DebugLogger, LogFn } from '@aztec/foundation/log'; + +import { Command } from 'commander'; +import { readFileSync } from 'fs'; +import http from 'http'; +import { dirname, resolve } from 'path'; + +import { cliTexts } from './texts.js'; +import { installSignalHandlers } from './util.js'; + +const { AZTEC_PORT = '8080' } = process.env; + +/** + * Returns commander program that defines the 'aztec' command line interface. + * @param userLog - log function for logging user output. + * @param debugLogger - logger for logging debug messages. + */ +export function getProgram(userLog: LogFn, debugLogger: DebugLogger): Command { + const program = new Command(); + + const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); + const cliVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version; + + program.name('aztec').description('Aztec command line interface').version(cliVersion); + + // Start Aztec modules with options + program + .command('start') + .description( + 'Starts Aztec modules. Options for each module can be set as key-value pairs (e.g. "option1=value1,option2=value2") or as environment variables.', + ) + .option('-p, --port ', 'Port to run Aztec on.', AZTEC_PORT) + .option('-n, --node [options]', cliTexts.node) + .option('-px, --pxe [options]', cliTexts.pxe) + .option('-a, --archiver [options]', cliTexts.archiver) + .option('-s, --sequencer [options]', cliTexts.sequencer) + .option('-p2p, --p2p-bootstrap [options]', cliTexts.p2pBootstrap) + .action(async options => { + // list of 'stop' functions to call when process ends + const signalHandlers: Array<() => Promise> = []; + let services: ServerList = []; + + // Start Aztec Node + if (options.node) { + const { startNode } = await import('./cmds/start_node.js'); + services = await startNode(options, signalHandlers, userLog); + } else if (options.pxe) { + const { startPXE } = await import('./cmds/start_pxe.js'); + services = await startPXE(options, signalHandlers, userLog); + } else if (options.archiver) { + const { startArchiver } = await import('./cmds/start_archiver.js'); + await startArchiver(options, signalHandlers); + } else if (options.p2pBootstrap) { + const { startP2PBootstrap } = await import('./cmds/start_p2p_bootstrap.js'); + await startP2PBootstrap(options, signalHandlers, debugLogger); + } + if (services.length) { + const rpcServer = createNamespacedJsonRpcServer(services, debugLogger); + + const app = rpcServer.getApp(); + const httpServer = http.createServer(app.callback()); + httpServer.listen(options.port); + userLog(`Aztec Server listening on port ${options.port}`); + } + installSignalHandlers(debugLogger, signalHandlers); + }); + return program; +} diff --git a/yarn-project/aztec/src/cli/cmds/start_archiver.ts b/yarn-project/aztec/src/cli/cmds/start_archiver.ts new file mode 100644 index 00000000000..0a07c96ae6c --- /dev/null +++ b/yarn-project/aztec/src/cli/cmds/start_archiver.ts @@ -0,0 +1,31 @@ +import { + Archiver, + ArchiverConfig, + KVArchiverDataStore, + createArchiverRpcServer, + getConfigEnvVars as getArchiverConfigEnvVars, +} from '@aztec/archiver'; +import { ServerList } from '@aztec/foundation/json-rpc/server'; +import { AztecLmdbStore } from '@aztec/kv-store'; + +import { mergeEnvVarsAndCliOptions, parseModuleOptions } from '../util.js'; + +export const startArchiver = async (options: any, signalHandlers: (() => Promise)[]) => { + const services: ServerList = []; + // Start a standalone archiver. + // get env vars first + const archiverConfigEnvVars = getArchiverConfigEnvVars(); + // get config from options + const archiverCliOptions = parseModuleOptions(options.archiver); + // merge env vars and cli options + const archiverConfig = mergeEnvVarsAndCliOptions(archiverConfigEnvVars, archiverCliOptions, true); + + const store = await AztecLmdbStore.open(archiverConfig.l1Contracts.rollupAddress, archiverConfig.dataDirectory); + const archiverStore = new KVArchiverDataStore(store, archiverConfig.maxLogs); + + const archiver = await Archiver.createAndSync(archiverConfig, archiverStore, true); + const archiverServer = createArchiverRpcServer(archiver); + services.push({ archiver: archiverServer }); + signalHandlers.push(archiver.stop); + return services; +}; diff --git a/yarn-project/aztec/src/cli/cmds/start_node.ts b/yarn-project/aztec/src/cli/cmds/start_node.ts new file mode 100644 index 00000000000..7a4a0d3623b --- /dev/null +++ b/yarn-project/aztec/src/cli/cmds/start_node.ts @@ -0,0 +1,87 @@ +import { AztecNodeConfig, createAztecNodeRpcServer, getConfigEnvVars as getNodeConfigEnvVars } from '@aztec/aztec-node'; +import { NULL_KEY } from '@aztec/ethereum'; +import { ServerList } from '@aztec/foundation/json-rpc/server'; +import { LogFn } from '@aztec/foundation/log'; +import { PXEServiceConfig, createPXERpcServer, getPXEServiceConfig } from '@aztec/pxe'; + +import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; + +import { MNEMONIC, createAztecNode, createAztecPXE, deployContractsToL1 } from '../../sandbox.js'; +import { mergeEnvVarsAndCliOptions, parseModuleOptions } from '../util.js'; + +const { DEPLOY_AZTEC_CONTRACTS } = process.env; + +export const startNode = async ( + options: any, + signalHandlers: (() => Promise)[], + userLog: LogFn, +): Promise => { + // Services that will be started in a single multi-rpc server + const services: ServerList = []; + // get env vars first + const aztecNodeConfigEnvVars = getNodeConfigEnvVars(); + // get config from options + const nodeCliOptions = parseModuleOptions(options.node); + // merge env vars and cli options + let nodeConfig = mergeEnvVarsAndCliOptions(aztecNodeConfigEnvVars, nodeCliOptions); + + // if no publisher private key, then use MNEMONIC + if (!options.archiver) { + // expect archiver url in node config + const archiverUrl = nodeCliOptions.archiverUrl; + if (!archiverUrl) { + userLog('Archiver Service URL is required to start Aztec Node without --archiver option'); + throw new Error('Archiver Service URL is required to start Aztec Node without --archiver option'); + } + nodeConfig.archiverUrl = archiverUrl; + } else { + const archiverCliOptions = parseModuleOptions(options.archiver); + nodeConfig = mergeEnvVarsAndCliOptions(aztecNodeConfigEnvVars, archiverCliOptions); + } + + // Deploy contracts if needed + if (nodeCliOptions.deployAztecContracts || DEPLOY_AZTEC_CONTRACTS === 'true') { + let account; + if (nodeConfig.publisherPrivateKey === NULL_KEY) { + account = mnemonicToAccount(MNEMONIC); + } else { + account = privateKeyToAccount(nodeConfig.publisherPrivateKey); + } + await deployContractsToL1(nodeConfig, account); + } + + if (!options.sequencer) { + nodeConfig.disableSequencer = true; + } else if (nodeConfig.publisherPrivateKey === NULL_KEY) { + // If we have a sequencer, ensure there's a publisher private key set. + const hdAccount = mnemonicToAccount(MNEMONIC); + const privKey = hdAccount.getHdKey().privateKey; + nodeConfig.publisherPrivateKey = `0x${Buffer.from(privKey!).toString('hex')}`; + } + + // Create and start Aztec Node. + const node = await createAztecNode(nodeConfig); + const nodeServer = createAztecNodeRpcServer(node); + + // Add node to services list + services.push({ node: nodeServer }); + + // Add node stop function to signal handlers + signalHandlers.push(node.stop); + + // Create a PXE client that connects to the node. + if (options.pxe) { + const pxeCliOptions = parseModuleOptions(options.pxe); + const pxeConfig = mergeEnvVarsAndCliOptions(getPXEServiceConfig(), pxeCliOptions); + const pxe = await createAztecPXE(node, pxeConfig); + const pxeServer = createPXERpcServer(pxe); + + // Add PXE to services list + services.push({ pxe: pxeServer }); + + // Add PXE stop function to signal handlers + signalHandlers.push(pxe.stop); + } + + return services; +}; diff --git a/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts b/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts new file mode 100644 index 00000000000..3ed48cf12cf --- /dev/null +++ b/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts @@ -0,0 +1,18 @@ +import { DebugLogger } from '@aztec/aztec.js'; +import { BootstrapNode, P2PConfig, getP2PConfigEnvVars } from '@aztec/p2p'; + +import { mergeEnvVarsAndCliOptions, parseModuleOptions } from '../util.js'; + +export const startP2PBootstrap = async ( + options: any, + signalHandlers: (() => Promise)[], + debugLogger: DebugLogger, +) => { + // Start a P2P bootstrap node. + const envVars = getP2PConfigEnvVars(); + const cliOptions = parseModuleOptions(options.p2pBootstrap); + const bootstrapNode = new BootstrapNode(debugLogger); + const config = mergeEnvVarsAndCliOptions(envVars, cliOptions); + await bootstrapNode.start(config); + signalHandlers.push(bootstrapNode.stop); +}; diff --git a/yarn-project/aztec/src/cli/cmds/start_pxe.ts b/yarn-project/aztec/src/cli/cmds/start_pxe.ts new file mode 100644 index 00000000000..b97cc431cc8 --- /dev/null +++ b/yarn-project/aztec/src/cli/cmds/start_pxe.ts @@ -0,0 +1,38 @@ +import { createAztecNodeClient } from '@aztec/circuit-types'; +import { ServerList } from '@aztec/foundation/json-rpc/server'; +import { LogFn } from '@aztec/foundation/log'; +import { PXEServiceConfig, createPXERpcServer, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; + +import { mergeEnvVarsAndCliOptions, parseModuleOptions } from '../util.js'; + +const { AZTEC_NODE_URL } = process.env; + +export const startPXE = async (options: any, signalHandlers: (() => Promise)[], userLog: LogFn) => { + // Services that will be started in a single multi-rpc server + const services: ServerList = []; + // Starting a PXE with a remote node. + // get env vars first + const pxeConfigEnvVars = getPXEServiceConfig(); + // get config from options + const pxeCliOptions = parseModuleOptions(options.pxe); + + // Determine node url from options or env vars + const nodeUrl = pxeCliOptions.nodeUrl || AZTEC_NODE_URL; + // throw if no Aztec Node URL is provided + if (!nodeUrl) { + userLog('Aztec Node URL (nodeUrl | AZTEC_NODE_URL) option is required to start PXE without --node option'); + throw new Error('Aztec Node URL (nodeUrl | AZTEC_NODE_URL) option is required to start PXE without --node option'); + } + + // merge env vars and cli options + const pxeConfig = mergeEnvVarsAndCliOptions(pxeConfigEnvVars, pxeCliOptions); + + // create a node client + const node = createAztecNodeClient(nodeUrl); + + const pxe = await createPXEService(node, pxeConfig); + const pxeServer = createPXERpcServer(pxe); + services.push({ pxe: pxeServer }); + signalHandlers.push(pxe.stop); + return services; +}; diff --git a/yarn-project/aztec/src/cli/index.ts b/yarn-project/aztec/src/cli/index.ts new file mode 100644 index 00000000000..c01c2dcf0ba --- /dev/null +++ b/yarn-project/aztec/src/cli/index.ts @@ -0,0 +1 @@ +export * from './cli.js'; diff --git a/yarn-project/aztec/src/cli/texts.ts b/yarn-project/aztec/src/cli/texts.ts new file mode 100644 index 00000000000..2536e37637d --- /dev/null +++ b/yarn-project/aztec/src/cli/texts.ts @@ -0,0 +1,71 @@ +const contractAddresses = + 'Aztec Contract Addresses:\n' + + 'rollupAddress:ROLLUP_CONTRACT_ADDRESS - string - The deployed L1 rollup contract address.\n' + + 'registryAddress:REGISTRY_CONTRACT_ADDRESS - string - The deployed L1 registry contract address.\n' + + 'inboxAddress:INBOX_CONTRACT_ADDRESS - string - The deployed L1 inbox contract address.\n' + + 'outboxAddress:OUTBOX_CONTRACT_ADDRESS - string - The deployed L1 outbox contract address.\n' + + 'contractDeploymentEmitterAddress:CONTRACT_DEPLOYMENT_EMITTER_ADDRESS - string - The deployed L1 contract deployment emitter contract address.\n'; +const p2pOptions = + 'p2pBlockCheckIntervalMS:P2P_BLOCK_CHECK_INTERVAL_MS - number - The frequency in which to check for blocks. Default: 100\n' + + 'p2pL2QueueSize:P2P_L2_QUEUE_SIZE - number - Size of queue of L2 blocks to store. Default: 1000\n' + + 'tcpListenPort:TCP_LISTEN_PORT - number - The tcp port on which the P2P service should listen for connections. Default: 40400\n' + + 'tcpListenIp:TCP_LISTEN_IP - string - The tcp IP on which the P2P service should listen for connections. Default: 0.0.0.0\n' + + 'peerIdPrivateKey:PEER_ID_PRIVATE_KEY - string - An optional peer id private key. If blank, will generate a random key.\n' + + 'bootstrapNodes:BOOTSTRAP_NODES - string - A list of bootstrap peers to connect to.\n' + + 'announceHostname:P2P_ANNOUNCE_HOSTNAME - string - P2P Hostname to announce.\n' + + 'announcePort:P2P_ANNOUNCE_PORT - number - P2P Port to announce.\n' + + 'clientKADRouting:P2P_KAD_CLIENT - boolean - Optional specification to run as a client in the Kademlia routing protocol. Default: false\n' + + 'enableNat:P2P_NAT_ENABLED - boolean - Whether to enable NAT from libp2p (ignored for bootstrap node). Default: false\n' + + 'minPeerCount:P2P_MIN_PEERS - number - The minimum number of peers to connect to. Default: 10\n' + + 'maxPeerCount:P2P_MAX_PEERS - number - The maximum number of peers to connect to. Default: 100\n'; + +export const cliTexts = { + node: + 'Starts Aztec Node with options.\n' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + 'rcpUrl:ETHEREUM_HOST - string - The host of the Ethereum node to connect to. Default: http://localhost:8545\n' + + 'archiverUrl:ARCHIVER_URL - string - A URL for an archiver service that the node will use.\n' + + 'p2pEnabled:P2P_ENABLED - boolean - A flag dictating whether the P2P subsystem should be enabled.\n\n' + + 'dataDirectory:DATA_DIRECTORY - string - Where to store node data. If not set, will store temporarily.\n' + + 'deployAztecContracts:DEPLOY_AZTEC_CONTRACTS - boolean - A flag dictating whether to deploy the Aztec contracts. Default: false\n' + + 'l2QueueSize:L2_QUEUE_SIZE - number - Size of queue of L2 blocks to store. Default: 1000\n' + + 'worldStateBlockCheckIntervalMS:WS_BLOCK_CHECK_INTERVAL_MS - number - The frequency in which to check for blocks in ms. Default: 100\n' + + // Contract Addresses + contractAddresses + + // P2P Options + 'When P2P is enabled, the following options are available:\n' + + p2pOptions, + pxe: + 'Starts a PXE with options. If started additionally to --node, the PXE will attach to that node.' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + 'nodeUrl:AZTEC_NODE_URL - string - The URL of the Aztec Node to connect to.\n' + + 'port:PXE_PORT - number - The port on which the PXE should listen for connections. Default: 79\n' + + 'l2BlockPollingIntervalMS:PXE_BLOCK_POLLING_INTERVAL_MS - number - The frequency in which to check for blocks in ms. Default: 1000\n' + + 'l2StartingBlock:PXE_L2_STARTING_BLOCK - number - The block number from which to start polling. Default: 1\n' + + 'dataDirectory:PXE_DATA_DIRECTORY - string - Where to store PXE data. If not set, will store temporarily.\n', + archiver: + 'Starts an Archiver with options. If started additionally to --node, the Archiver will attach to that node.' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + 'rcpUrl:ETHEREUM_HOST - string - The host of the Ethereum node to connect to. Default: http://localhost:8545\n' + + 'apiKey:API_KEY - string - The key for the ethereum node if necessary.\n' + + 'archiverPollingIntervalMS:ARCHIVER_POLLING_INTERVAL_MS - number - The polling interval in ms for retrieving new L2 blocks and encrypted logs. Default: 1000\n' + + 'viemPollingIntervalMS:ARCHIVER_VIEM_POLLING_INTERVAL_MS - number - The polling interval viem uses in ms. Default: 1000\n' + + 'dataDirectory:DATA_DIRECTORY - string - Optional dir to store data. If omitted will store temporarily.\n\n' + + contractAddresses, + sequencer: + 'Starts a Sequencer with options. If started additionally to --node, the Sequencer will attach to that node.\n' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + 'rcpUrl:ETHEREUM_HOST - string - The host of the Ethereum node to connect to. Default: http://localhost:8545\n' + + 'apiKey:API_KEY - string - The key for the ethereum node if necessary.\n' + + 'chainId:CHAIN_ID - number - The chain id of the ethereum host. Default: 31337\n' + + 'version:VERSION - number - The version of the Aztec rollup. Default: 1\n' + + 'publisherPrivateKey:SEQ_PUBLISHER_PRIVATE_KEY - string - The private key of the publisher. If not provided, will try to infer from default foundry test accounts.\n' + + 'requiredConfirmations:SEQ_REQUIRED_CONFIRMATIONS - number - The number of confirmations required before publishing a block. Default: 1\n' + + 'l1BlockPublishRetryIntervalMS:SEQ_PUBLISH_RETRY_INTERVAL_MS - number - The interval in ms to wait before retrying to publish a block. Default: 1000\n' + + 'transactionPollingIntervalMS:SEQ_TX_POLLING_INTERVAL_MS - number - The interval in ms to wait before polling for new transactions. Default: 1000\n' + + contractAddresses, + p2pBootstrap: + 'Starts a P2P bootstrap node with options.\n' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + p2pOptions, +}; diff --git a/yarn-project/aztec/src/cli/util.ts b/yarn-project/aztec/src/cli/util.ts new file mode 100644 index 00000000000..75f8c84d237 --- /dev/null +++ b/yarn-project/aztec/src/cli/util.ts @@ -0,0 +1,139 @@ +import { ArchiverConfig } from '@aztec/archiver'; +import { AztecNodeConfig } from '@aztec/aztec-node'; +import { AccountManager } from '@aztec/aztec.js'; +import { L1ContractAddresses } from '@aztec/ethereum'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { LogFn } from '@aztec/foundation/log'; +import { P2PConfig } from '@aztec/p2p'; +import { GrumpkinScalar, PXEService, PXEServiceConfig } from '@aztec/pxe'; + +/** + * Checks if the object has l1Contracts property + * @param obj - The object to check + * @returns True if the object has l1Contracts property + */ +function hasL1Contracts(obj: any): obj is { + /** the deployed L1 contract addresses */ + l1Contracts: unknown; +} { + return 'l1Contracts' in obj; +} + +/** + * Checks if all contract addresses set in config. + * @param contracts - L1 Contract Addresses object + * @returns true if all contract addresses are not zero + */ +const checkContractAddresses = (contracts: L1ContractAddresses) => { + return ['rollupAddress', 'inboxAddress', 'outboxAddress', 'contractDeploymentEmitterAddress'].every(cn => { + const key = cn as keyof L1ContractAddresses; + return contracts[key] && contracts[key] !== EthAddress.ZERO; + }); +}; + +export const installSignalHandlers = (logFn: LogFn, cb?: Array<() => Promise>) => { + const shutdown = async () => { + logFn('Shutting down...'); + if (cb) { + await Promise.all(cb); + } + process.exit(0); + }; + process.removeAllListeners('SIGINT'); + process.removeAllListeners('SIGTERM'); + process.once('SIGINT', shutdown); + process.once('SIGTERM', shutdown); +}; + +/** + * Parses a string of options into a key-value map. + * @param options - String of options in the format "option1=value1,option2=value2". + * @returns Key-value map of options. + */ +export const parseModuleOptions = (options: string): Record => { + if (!options?.length) { + return {}; + } + const optionsArray = options.split(','); + return optionsArray.reduce((acc, option) => { + const [key, value] = option.split('='); + return { ...acc, [key]: value }; + }, {}); +}; + +export const mergeEnvVarsAndCliOptions = ( + envVars: AztecNodeConfig | PXEServiceConfig | P2PConfig | ArchiverConfig, + cliOptions: Record, + contractsRequired = false, +) => { + if (contractsRequired && !cliOptions.rollupAddress) { + throw new Error('Rollup contract address is required to start the service'); + } + const cliOptionsContracts: L1ContractAddresses = { + rollupAddress: cliOptions.rollupAddress ? EthAddress.fromString(cliOptions.rollupAddress) : EthAddress.ZERO, + registryAddress: cliOptions.registryAddress ? EthAddress.fromString(cliOptions.registryAddress) : EthAddress.ZERO, + inboxAddress: cliOptions.inboxAddress ? EthAddress.fromString(cliOptions.inboxAddress) : EthAddress.ZERO, + outboxAddress: cliOptions.outboxAddress ? EthAddress.fromString(cliOptions.outboxAddress) : EthAddress.ZERO, + contractDeploymentEmitterAddress: cliOptions.contractDeploymentEmitterAddress + ? EthAddress.fromString(cliOptions.contractDeploymentEmitterAddress) + : EthAddress.ZERO, + availabilityOracleAddress: cliOptions.availabilityOracleAddress + ? EthAddress.fromString(cliOptions.availabilityOracleAddress) + : EthAddress.ZERO, + }; + + if ( + hasL1Contracts(envVars) && + contractsRequired && + (!checkContractAddresses(cliOptionsContracts) || !checkContractAddresses(envVars.l1Contracts)) + ) { + throw new Error('Deployed L1 contract addresses are required to start the service'); + } + + let merged = { ...envVars, ...cliOptions } as T; + + if (hasL1Contracts(envVars)) { + merged = { + ...merged, + l1Contracts: { + ...(envVars.l1Contracts && { ...envVars.l1Contracts }), + ...cliOptionsContracts, + }, + } as T; + } + + return merged; +}; + +/** + * Creates logs for the initial accounts + * @param accounts - The initial accounts + * @param pxe - A PXE instance to get the registered accounts + * @returns A string array containing the initial accounts details + */ +export async function createAccountLogs( + accounts: { + /** + * The account object + */ + account: AccountManager; + /** + * The private key of the account + */ + privateKey: GrumpkinScalar; + }[], + pxe: PXEService, +) { + const registeredAccounts = await pxe.getRegisteredAccounts(); + const accountLogStrings = [`Initial Accounts:\n\n`]; + for (const account of accounts) { + const completeAddress = account.account.getCompleteAddress(); + if (registeredAccounts.find(a => a.equals(completeAddress))) { + accountLogStrings.push(` Address: ${completeAddress.address.toString()}\n`); + accountLogStrings.push(` Partial Address: ${completeAddress.partialAddress.toString()}\n`); + accountLogStrings.push(` Private Key: ${account.privateKey.toString()}\n`); + accountLogStrings.push(` Public Key: ${completeAddress.publicKey.toString()}\n\n`); + } + } + return accountLogStrings; +} diff --git a/yarn-project/aztec-sandbox/src/examples/token.ts b/yarn-project/aztec/src/examples/token.ts similarity index 100% rename from yarn-project/aztec-sandbox/src/examples/token.ts rename to yarn-project/aztec/src/examples/token.ts diff --git a/yarn-project/aztec-sandbox/src/examples/util.ts b/yarn-project/aztec/src/examples/util.ts similarity index 100% rename from yarn-project/aztec-sandbox/src/examples/util.ts rename to yarn-project/aztec/src/examples/util.ts diff --git a/yarn-project/aztec-sandbox/src/index.ts b/yarn-project/aztec/src/index.ts similarity index 100% rename from yarn-project/aztec-sandbox/src/index.ts rename to yarn-project/aztec/src/index.ts diff --git a/yarn-project/aztec-sandbox/src/logging.ts b/yarn-project/aztec/src/logging.ts similarity index 92% rename from yarn-project/aztec-sandbox/src/logging.ts rename to yarn-project/aztec/src/logging.ts index a9de4c40415..fe184716efc 100644 --- a/yarn-project/aztec-sandbox/src/logging.ts +++ b/yarn-project/aztec/src/logging.ts @@ -6,14 +6,14 @@ import * as winston from 'winston'; import DailyRotateFile from 'winston-daily-rotate-file'; const { format } = winston; -const CURRENT_LOG_FILE_NAME = 'aztec-sandbox.debug.log'; +const CURRENT_LOG_FILE_NAME = 'aztec.debug.log'; const LOG_DIR = 'log'; /** Creates a winston logger that logs everything to a local rotating file */ function createWinstonLogger() { // See https://www.npmjs.com/package/winston-daily-rotate-file#user-content-options const transport: DailyRotateFile = new DailyRotateFile({ - filename: 'aztec-sandbox-%DATE%.debug.log', + filename: 'aztec-%DATE%.debug.log', dirname: LOG_DIR, datePattern: 'YYYY-MM-DD', zippedArchive: true, diff --git a/yarn-project/aztec-sandbox/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts similarity index 94% rename from yarn-project/aztec-sandbox/src/sandbox.ts rename to yarn-project/aztec/src/sandbox.ts index acb868e4bca..4c4b378ba67 100644 --- a/yarn-project/aztec-sandbox/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -26,7 +26,7 @@ import { } from '@aztec/l1-artifacts'; import { PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; -import { HDAccount, createPublicClient, http as httpViemTransport } from 'viem'; +import { HDAccount, PrivateKeyAccount, createPublicClient, http as httpViemTransport } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; import { foundry } from 'viem/chains'; @@ -74,7 +74,11 @@ async function waitThenDeploy(config: AztecNodeConfig, deployFunction: () => Pro * @param aztecNodeConfig - The Aztec Node Config * @param hdAccount - Account for publishing L1 contracts */ -export async function deployContractsToL1(aztecNodeConfig: AztecNodeConfig, hdAccount: HDAccount) { +export async function deployContractsToL1( + aztecNodeConfig: AztecNodeConfig, + hdAccount: HDAccount | PrivateKeyAccount, + contractDeployLogger = logger, +) { const l1Artifacts: L1ContractArtifactsForDeployment = { contractDeploymentEmitter: { contractAbi: ContractDeploymentEmitterAbi, @@ -104,7 +108,7 @@ export async function deployContractsToL1(aztecNodeConfig: AztecNodeConfig, hdAc aztecNodeConfig.l1Contracts = ( await waitThenDeploy(aztecNodeConfig, () => - deployL1Contracts(aztecNodeConfig.rpcUrl, hdAccount, localAnvil, logger, l1Artifacts), + deployL1Contracts(aztecNodeConfig.rpcUrl, hdAccount, localAnvil, contractDeployLogger, l1Artifacts), ) ).l1ContractAddresses; diff --git a/yarn-project/aztec-sandbox/src/splash.ts b/yarn-project/aztec/src/splash.ts similarity index 100% rename from yarn-project/aztec-sandbox/src/splash.ts rename to yarn-project/aztec/src/splash.ts diff --git a/yarn-project/aztec-sandbox/tsconfig.json b/yarn-project/aztec/tsconfig.json similarity index 89% rename from yarn-project/aztec-sandbox/tsconfig.json rename to yarn-project/aztec/tsconfig.json index 7b9c2ea9188..a27fb82841d 100644 --- a/yarn-project/aztec-sandbox/tsconfig.json +++ b/yarn-project/aztec/tsconfig.json @@ -9,6 +9,9 @@ { "path": "../accounts" }, + { + "path": "../archiver" + }, { "path": "../aztec-node" }, @@ -27,6 +30,9 @@ { "path": "../foundation" }, + { + "path": "../kv-store" + }, { "path": "../l1-artifacts" }, diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index 3a2f9ebb635..32a4dd48d97 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -42,6 +42,7 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN }, { Tx, L2BlockL2Logs }, false, + 'node', fetch, ); } diff --git a/yarn-project/circuit-types/src/contract_data.ts b/yarn-project/circuit-types/src/contract_data.ts index a84e0434d23..1fbf3a7b88a 100644 --- a/yarn-project/circuit-types/src/contract_data.ts +++ b/yarn-project/circuit-types/src/contract_data.ts @@ -105,6 +105,23 @@ export class EncodedContractFunction { return new EncodedContractFunction(fnSelector, isInternal, reader.readBuffer()); } + /** + * Serializes this instance into a string. + * @returns Encoded string. + */ + toString(): string { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes a contract function object from an encoded string. + * @param data - The encoded string. + * @returns The deserialized contract function. + */ + static fromString(data: string): EncodedContractFunction { + return EncodedContractFunction.fromBuffer(Buffer.from(data, 'hex')); + } + /** * Creates a random contract function. * @returns A random contract function. diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts index d9da2be7d50..f70648a0c4c 100644 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ b/yarn-project/circuit-types/src/keys/key_store.ts @@ -45,6 +45,15 @@ export interface KeyStore { */ getNullifierSecretKey(pubKey: PublicKey): Promise; + /** + * Retrieves the nullifier secret key of the specified nullifier public key. + * Throws an error if the provided public key is not associated with any of the registered accounts. + * + * @param nullifierPubKey - The nullifier public key. + * @returns A Promise that resolves to the nullifier secret key. + */ + getNullifierSecretKeyFromPublicKey(nullifierPubKey: PublicKey): Promise; + /** * Retrieves the nullifier public key of the account associated with the specified AztecAddress. * Throws an error if the provided public key is not found in the list of registered accounts. diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.ts b/yarn-project/circuit-types/src/l1_to_l2_message.ts index 2165d4bd49e..29452647a3c 100644 --- a/yarn-project/circuit-types/src/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/l1_to_l2_message.ts @@ -132,6 +132,15 @@ export class L1ToL2Message { return new L1ToL2Message(sender, recipient, content, secretHash, deadline, fee); } + toString(): string { + return this.toBuffer().toString('hex'); + } + + static fromString(data: string): L1ToL2Message { + const buffer = Buffer.from(data, 'hex'); + return L1ToL2Message.fromBuffer(buffer); + } + static empty(): L1ToL2Message { return new L1ToL2Message(L1Actor.empty(), L2Actor.empty(), Fr.ZERO, Fr.ZERO, 0, 0); } diff --git a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts index a0c095c3aa6..3b298f06a41 100644 --- a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts @@ -56,6 +56,24 @@ export class L2BlockL2Logs { return new L2BlockL2Logs(txLogs); } + /** + * Seralizes logs into a string. + * @returns A string representation of the serialized logs. + */ + public toString(): string { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes logs from a string. + * @param data - The string containing the serialized logs. + * @returns A new `L2BlockL2Logs` object. + */ + public static fromString(data: string): L2BlockL2Logs { + const buffer = Buffer.from(data, 'hex'); + return L2BlockL2Logs.fromBuffer(buffer); + } + /** * Creates a new `L2BlockL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each function * call. diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index a33a058a9d3..94043432bef 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -190,9 +190,6 @@ export function computeCompleteAddress( ); } -/** - * - */ function computePartialAddress(contractAddrSalt: Fr, fnTreeRoot: Fr, constructorHash: Fr) { return Fr.fromBuffer( pedersenHash( @@ -450,9 +447,6 @@ export function computeTxHash(txRequest: TxRequest): Fr { ); } -/** - * - */ function computeFunctionDataHash(functionData: FunctionData): Fr { return Fr.fromBuffer( pedersenHash( @@ -467,9 +461,6 @@ function computeFunctionDataHash(functionData: FunctionData): Fr { ); } -/** - * - */ function computeTxContextHash(txContext: TxContext): Fr { return Fr.fromBuffer( pedersenHash( @@ -486,9 +477,6 @@ function computeTxContextHash(txContext: TxContext): Fr { ); } -/** - * - */ function computeContractDeploymentDataHash(data: ContractDeploymentData): Fr { return Fr.fromBuffer( pedersenHash( @@ -505,9 +493,6 @@ function computeContractDeploymentDataHash(data: ContractDeploymentData): Fr { ); } -/** - * - */ function computeCallContextHash(input: CallContext) { return pedersenHash( [ @@ -524,24 +509,21 @@ function computeCallContextHash(input: CallContext) { ); } -/** - * - */ function computePrivateInputsHash(input: PrivateCircuitPublicInputs) { const toHash = [ computeCallContextHash(input.callContext), input.argsHash.toBuffer(), ...input.returnValues.map(fr => fr.toBuffer()), ...input.readRequests - .map(se => se.toFieldArray()) + .map(rr => rr.toFields()) .flat() .map(fr => fr.toBuffer()), ...input.newCommitments - .map(se => se.toFieldArray()) + .map(n => n.toFields()) .flat() .map(fr => fr.toBuffer()), ...input.newNullifiers - .map(selinked => selinked.toFieldArray()) + .map(n => n.toFields()) .flat() .map(fr => fr.toBuffer()), ...input.privateCallStackHashes.map(fr => fr.toBuffer()), @@ -589,9 +571,6 @@ export function computePrivateCallStackItemHash(callStackItem: PrivateCallStackI ); } -/** - * - */ function computeContractStorageUpdateRequestHash(input: ContractStorageUpdateRequest) { return pedersenHash( [input.storageSlot.toBuffer(), input.oldValue.toBuffer(), input.newValue.toBuffer()], @@ -599,22 +578,14 @@ function computeContractStorageUpdateRequestHash(input: ContractStorageUpdateReq ); } -/** - * - */ function computeContractStorageReadsHash(input: ContractStorageRead) { return pedersenHash([input.storageSlot.toBuffer(), input.currentValue.toBuffer()], GeneratorIndex.PUBLIC_DATA_READ); } -/** - * - */ + export function computeCommitmentsHash(input: SideEffect) { return pedersenHash([input.value.toBuffer(), input.counter.toBuffer()], GeneratorIndex.SIDE_EFFECT); } -/** - * - */ export function computeNullifierHash(input: SideEffectLinkedToNoteHash) { return pedersenHash( [input.value.toBuffer(), input.noteHash.toBuffer(), input.counter.toBuffer()], @@ -622,9 +593,6 @@ export function computeNullifierHash(input: SideEffectLinkedToNoteHash) { ); } -/** - * - */ export function computePublicInputsHash(input: PublicCircuitPublicInputs) { const toHash = [ computeCallContextHash(input.callContext), diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 39a05fee9ca..5560166590c 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -10,6 +10,7 @@ export const MAX_NEW_L2_TO_L1_MSGS_PER_CALL = 2; export const MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; export const MAX_PUBLIC_DATA_READS_PER_CALL = 16; export const MAX_READ_REQUESTS_PER_CALL = 32; +export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1; export const MAX_NEW_COMMITMENTS_PER_TX = 64; export const MAX_NEW_NULLIFIERS_PER_TX = 64; export const MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX = 8; @@ -20,6 +21,7 @@ export const MAX_PUBLIC_DATA_READS_PER_TX = 16; export const MAX_NEW_CONTRACTS_PER_TX = 1; export const MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX = 4; export const MAX_READ_REQUESTS_PER_TX = 128; +export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; export const NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; export const NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; export const NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; @@ -62,7 +64,7 @@ export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; export const CONTRACT_STORAGE_READ_LENGTH = 2; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 190; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; -export const CALL_PRIVATE_FUNCTION_RETURN_SIZE = 195; +export const CALL_PRIVATE_FUNCTION_RETURN_SIZE = 199; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 87; export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 177; export const COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/yarn-project/circuits.js/src/keys/index.ts b/yarn-project/circuits.js/src/keys/index.ts index 09ec99767c4..07e8b0b2a65 100644 --- a/yarn-project/circuits.js/src/keys/index.ts +++ b/yarn-project/circuits.js/src/keys/index.ts @@ -16,8 +16,9 @@ export function derivePublicKey(secretKey: GrumpkinPrivateKey) { /** * Derives a new secret key from a secret key and an index. */ -function _deriveSecretKey(secretKey: GrumpkinPrivateKey, index: Fr): GrumpkinPrivateKey { +function deriveSecretKey(secretKey: GrumpkinPrivateKey, index: Fr): GrumpkinPrivateKey { // TODO: Temporary hack. Should replace it with a secure way to derive the secret key. + // Match the way keys are derived in noir-protocol-circuits/src/crates/private_kernel_lib/src/common.nr const hash = pedersenHash([secretKey.high, secretKey.low, index].map(v => v.toBuffer())); return new GrumpkinScalar(hash); } @@ -26,9 +27,7 @@ function _deriveSecretKey(secretKey: GrumpkinPrivateKey, index: Fr): GrumpkinPri * Computes the nullifier secret key from seed secret key. */ export function computeNullifierSecretKey(seedSecretKey: GrumpkinPrivateKey): GrumpkinPrivateKey { - // TODO - // return deriveSecretKey(seedSecretKey, new Fr(1)); - return seedSecretKey; + return deriveSecretKey(seedSecretKey, new Fr(1)); } /** @@ -36,9 +35,7 @@ export function computeNullifierSecretKey(seedSecretKey: GrumpkinPrivateKey): Gr */ export function computeSiloedNullifierSecretKey( nullifierSecretKey: GrumpkinPrivateKey, - _contractAddress: AztecAddress, + contractAddress: AztecAddress, ): GrumpkinPrivateKey { - // TODO - // return deriveSecretKey(nullifierSecretKey, contractAddress); - return nullifierSecretKey; + return deriveSecretKey(nullifierSecretKey, contractAddress); } diff --git a/yarn-project/circuits.js/src/structs/call_context.ts b/yarn-project/circuits.js/src/structs/call_context.ts index 266f715e3b8..5f35bced17d 100644 --- a/yarn-project/circuits.js/src/structs/call_context.ts +++ b/yarn-project/circuits.js/src/structs/call_context.ts @@ -1,6 +1,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; import { Fr, FunctionSelector } from './index.js'; @@ -126,6 +126,20 @@ export class CallContext { ); } + static fromFields(fields: Fr[] | FieldReader): CallContext { + const reader = FieldReader.asReader(fields); + return new CallContext( + reader.readObject(AztecAddress), + reader.readObject(AztecAddress), + reader.readField(), + reader.readObject(FunctionSelector), + reader.readBoolean(), + reader.readBoolean(), + reader.readBoolean(), + reader.readU32(), + ); + } + equals(callContext: CallContext) { return ( callContext.msgSender.equals(this.msgSender) && diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index 2a569fb984c..ea7b1147a8b 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -53,7 +53,7 @@ export class GlobalVariables { } static getFields(fields: FieldsOf) { - // Note: The order here must match the order in the HeaderDecoder solidity library. + // Note: The order here must match the order in the HeaderLib solidity library. return [fields.chainId, fields.version, fields.blockNumber, fields.timestamp] as const; } diff --git a/yarn-project/circuits.js/src/structs/header.ts b/yarn-project/circuits.js/src/structs/header.ts index 6c70655e81d..44b17a3009e 100644 --- a/yarn-project/circuits.js/src/structs/header.ts +++ b/yarn-project/circuits.js/src/structs/header.ts @@ -24,17 +24,18 @@ export class Header { } toBuffer() { - // Note: The order here must match the order in the HeaderDecoder solidity library. - return serializeToBuffer(this.globalVariables, this.state, this.lastArchive, this.bodyHash); + // Note: The order here must match the order in the HeaderLib solidity library. + return serializeToBuffer(this.lastArchive, this.bodyHash, this.state, this.globalVariables); } static fromBuffer(buffer: Buffer | BufferReader): Header { const reader = BufferReader.asReader(buffer); - // TODO(#4045): unify ordering here with ordering in constructor. - const globalVariables = reader.readObject(GlobalVariables); - const state = reader.readObject(StateReference); - const lastArchive = reader.readObject(AppendOnlyTreeSnapshot); - const bodyHash = reader.readBytes(NUM_BYTES_PER_SHA256); - return new Header(lastArchive, bodyHash, state, globalVariables); + + return new Header( + reader.readObject(AppendOnlyTreeSnapshot), + reader.readBytes(NUM_BYTES_PER_SHA256), + reader.readObject(StateReference), + reader.readObject(GlobalVariables), + ); } } diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index fc9305a85a6..d5428d65734 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -17,6 +17,7 @@ export * from './kernel/public_inputs.js'; export * from './kernel/public_inputs_final.js'; export * from './kernel/public_kernel.js'; export * from './membership_witness.js'; +export * from './nullifier_key_validation_request.js'; export * from './private_circuit_public_inputs.js'; export * from './proof.js'; export * from './public_call_request.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 0faefe3a5ba..7e2f73a90a3 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -7,6 +7,7 @@ import { MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, @@ -22,6 +23,7 @@ import { EthAddress, Fr, FunctionData, + NullifierKeyValidationRequestContext, SideEffect, SideEffectLinkedToNoteHash, } from '../index.js'; @@ -299,6 +301,13 @@ export class CombinedAccumulatedData { * All the read requests made in this transaction. */ public readRequests: Tuple, + /** + * All the nullifier key validation requests made in this transaction. + */ + public nullifierKeyValidationRequests: Tuple< + NullifierKeyValidationRequestContext, + typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + >, /** * The new commitments made in this transaction. */ @@ -359,6 +368,7 @@ export class CombinedAccumulatedData { return serializeToBuffer( this.aggregationObject, this.readRequests, + this.nullifierKeyValidationRequests, this.newCommitments, this.newNullifiers, this.privateCallStack, @@ -389,6 +399,7 @@ export class CombinedAccumulatedData { return new CombinedAccumulatedData( reader.readObject(AggregationObject), reader.readArray(MAX_READ_REQUESTS_PER_TX, SideEffect), + reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_NEW_COMMITMENTS_PER_TX, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -409,6 +420,7 @@ export class CombinedAccumulatedData { return new CombinedAccumulatedData( finalData.aggregationObject, makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), finalData.newCommitments, finalData.newNullifiers, finalData.privateCallStack, @@ -438,6 +450,7 @@ export class CombinedAccumulatedData { return new CombinedAccumulatedData( AggregationObject.makeFake(), makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_NEW_COMMITMENTS_PER_TX, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts index 973928d7da8..13a6cb87185 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts @@ -1,4 +1,4 @@ -import { Fr } from '@aztec/foundation/fields'; +import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; @@ -7,11 +7,13 @@ import { FUNCTION_TREE_HEIGHT, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, MAX_READ_REQUESTS_PER_TX, } from '../../constants.gen.js'; +import { GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; import { CallRequest } from '../call_request.js'; import { PrivateCallStackItem } from '../call_stack_item.js'; import { MembershipWitness } from '../membership_witness.js'; @@ -146,6 +148,16 @@ export class PrivateKernelInputsInit { toBuffer() { return serializeToBuffer(this.txRequest, this.privateCall); } + + /** + * Deserializes from a buffer or reader. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized instance. + */ + static fromBuffer(buffer: Buffer | BufferReader): PrivateKernelInputsInit { + const reader = BufferReader.asReader(buffer); + return new PrivateKernelInputsInit(reader.readObject(TxRequest), reader.readObject(PrivateCallData)); + } } /** @@ -215,6 +227,10 @@ export class PrivateKernelInputsOrdering { * Contains hints for the transient nullifiers to localize corresponding commitments. */ public nullifierCommitmentHints: Tuple, + /** + * The master nullifier secret keys for the nullifier key validation requests. + */ + public masterNullifierSecretKeys: Tuple, ) {} /** @@ -230,6 +246,26 @@ export class PrivateKernelInputsOrdering { this.sortedNewNullifiers, this.sortedNewNullifiersIndexes, this.nullifierCommitmentHints, + this.masterNullifierSecretKeys, + ); + } + + /** + * Deserializes from a buffer or reader. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized instance. + */ + static fromBuffer(buffer: Buffer | BufferReader): PrivateKernelInputsOrdering { + const reader = BufferReader.asReader(buffer); + return new PrivateKernelInputsOrdering( + reader.readObject(PreviousKernelData), + reader.readArray(MAX_NEW_COMMITMENTS_PER_TX, SideEffect), + reader.readNumbers(MAX_NEW_COMMITMENTS_PER_TX), + reader.readArray(MAX_READ_REQUESTS_PER_TX, Fr), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), + reader.readNumbers(MAX_NEW_NULLIFIERS_PER_TX), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Fr), + reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar), ); } } diff --git a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts new file mode 100644 index 00000000000..5e93ead5855 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts @@ -0,0 +1,101 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { GrumpkinPrivateKey } from '../types/grumpkin_private_key.js'; + +/** + * Request for validating a nullifier key pair used in the app. + */ +export class NullifierKeyValidationRequest { + constructor( + /** + * Public key of the nullifier key. + */ + public readonly publicKey: Point, + /** + * Secret key of the nullifier key. + */ + public readonly secretKey: GrumpkinPrivateKey, + ) {} + + toBuffer() { + return serializeToBuffer(this.publicKey, this.secretKey); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new NullifierKeyValidationRequest(Point.fromBuffer(reader), GrumpkinScalar.fromBuffer(reader)); + } + + toFields(): Fr[] { + return [this.publicKey.toFields(), this.secretKey.high, this.secretKey.low].flat(); + } + + static fromFields(fields: Fr[] | FieldReader): NullifierKeyValidationRequest { + const reader = FieldReader.asReader(fields); + return new NullifierKeyValidationRequest(Point.fromFields(reader), reader.readFq()); + } + + isEmpty() { + return this.publicKey.isZero() && this.secretKey.isZero(); + } + + static empty() { + return new NullifierKeyValidationRequest(Point.ZERO, GrumpkinScalar.ZERO); + } +} + +/** + * Request for validating a nullifier key pair used in the app. + */ +export class NullifierKeyValidationRequestContext { + constructor( + /** + * Public key of the nullifier key. + */ + public readonly publicKey: Point, + /** + * Secret key of the nullifier key. + */ + public readonly secretKey: GrumpkinPrivateKey, + /** + * The storage contract address the nullifier key is for. + */ + public readonly contractAddress: AztecAddress, + ) {} + + toBuffer() { + return serializeToBuffer(this.publicKey, this.secretKey, this.contractAddress); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new NullifierKeyValidationRequestContext( + Point.fromBuffer(reader), + GrumpkinScalar.fromBuffer(reader), + AztecAddress.fromBuffer(reader), + ); + } + + toFields(): Fr[] { + return [this.publicKey.toFields(), this.secretKey.high, this.secretKey.low, this.contractAddress].flat(); + } + + static fromFields(fields: Fr[] | FieldReader): NullifierKeyValidationRequestContext { + const reader = FieldReader.asReader(fields); + return new NullifierKeyValidationRequestContext( + Point.fromFields(reader), + reader.readFq(), + AztecAddress.fromFields(reader), + ); + } + + isEmpty() { + return this.publicKey.isZero() && this.secretKey.isZero() && this.contractAddress.isZero(); + } + + static empty() { + return new NullifierKeyValidationRequestContext(Point.ZERO, GrumpkinScalar.ZERO, AztecAddress.ZERO); + } +} diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index db10fdfb428..03db0d35fbc 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -8,6 +8,7 @@ import { MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, @@ -16,6 +17,7 @@ import { } from '../constants.gen.js'; import { CallContext } from './call_context.js'; import { BlockHeader, SideEffect, SideEffectLinkedToNoteHash } from './index.js'; +import { NullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; import { ContractDeploymentData } from './tx_context.js'; /** @@ -40,6 +42,13 @@ export class PrivateCircuitPublicInputs { * Read requests created by the corresponding function call. */ public readRequests: Tuple, + /** + * Nullifier key validation requests created by the corresponding function call. + */ + public nullifierKeyValidationRequests: Tuple< + NullifierKeyValidationRequest, + typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL + >, /** * New commitments created by the corresponding function call. */ @@ -123,6 +132,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(Fr), reader.readArray(RETURN_VALUES_LENGTH, Fr), reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), + reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, Fr), @@ -150,6 +160,7 @@ export class PrivateCircuitPublicInputs { Fr.ZERO, makeTuple(RETURN_VALUES_LENGTH, Fr.zero), makeTuple(MAX_READ_REQUESTS_PER_CALL, SideEffect.empty), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), makeTuple(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, Fr.zero), @@ -168,22 +179,23 @@ export class PrivateCircuitPublicInputs { } isEmpty() { - const isFrArrayEmpty = (arr: Fr[]) => isArrayEmpty(arr, item => item.isZero()); - const isSideEffectArrayEmpty = (arr: SideEffect[]) => isArrayEmpty(arr, item => item.isEmpty()); - const isSideEffectLinkedArrayEmpty = (arr: SideEffectLinkedToNoteHash[]) => - isArrayEmpty(arr, item => item.isEmpty()); + // eslint-disable-next-line jsdoc/require-jsdoc + const isEmptyArray = (arr: { isEmpty: (...args: any[]) => boolean }[]) => isArrayEmpty(arr, item => item.isEmpty()); + // eslint-disable-next-line jsdoc/require-jsdoc + const isZeroArray = (arr: { isZero: (...args: any[]) => boolean }[]) => isArrayEmpty(arr, item => item.isZero()); return ( this.callContext.isEmpty() && this.argsHash.isZero() && - isFrArrayEmpty(this.returnValues) && - isSideEffectArrayEmpty(this.readRequests) && - isSideEffectArrayEmpty(this.newCommitments) && - isSideEffectLinkedArrayEmpty(this.newNullifiers) && - isFrArrayEmpty(this.privateCallStackHashes) && - isFrArrayEmpty(this.publicCallStackHashes) && - isFrArrayEmpty(this.newL2ToL1Msgs) && - isFrArrayEmpty(this.encryptedLogsHash) && - isFrArrayEmpty(this.unencryptedLogsHash) && + isZeroArray(this.returnValues) && + isEmptyArray(this.readRequests) && + isEmptyArray(this.nullifierKeyValidationRequests) && + isEmptyArray(this.newCommitments) && + isEmptyArray(this.newNullifiers) && + isZeroArray(this.privateCallStackHashes) && + isZeroArray(this.publicCallStackHashes) && + isZeroArray(this.newL2ToL1Msgs) && + isZeroArray(this.encryptedLogsHash) && + isZeroArray(this.unencryptedLogsHash) && this.encryptedLogPreimagesLength.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.blockHeader.isEmpty() && @@ -204,6 +216,7 @@ export class PrivateCircuitPublicInputs { fields.argsHash, fields.returnValues, fields.readRequests, + fields.nullifierKeyValidationRequests, fields.newCommitments, fields.newNullifiers, fields.privateCallStackHashes, diff --git a/yarn-project/circuits.js/src/structs/side_effects.ts b/yarn-project/circuits.js/src/structs/side_effects.ts index c6b85800082..25b3df86a88 100644 --- a/yarn-project/circuits.js/src/structs/side_effects.ts +++ b/yarn-project/circuits.js/src/structs/side_effects.ts @@ -1,4 +1,4 @@ -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { Fr } from './index.js'; @@ -13,7 +13,7 @@ export interface SideEffectType { /** Convert to a buffer */ toBuffer(): Buffer; /** Convert to a field array */ - toFieldArray(): Fr[]; + toFields(): Fr[]; /** Are all of the fields of the SideEffect zero? */ isEmpty(): boolean; } @@ -46,10 +46,15 @@ export class SideEffect implements SideEffectType { * Convert to an array of fields. * @returns The array of fields. */ - toFieldArray(): Fr[] { + toFields(): Fr[] { return [this.value, this.counter]; } + static fromFields(fields: Fr[] | FieldReader): SideEffect { + const reader = FieldReader.asReader(fields); + return new SideEffect(reader.readField(), reader.readField()); + } + /** * Returns whether this instance of side-effect is empty. * @returns True if the value and counter both are zero. @@ -109,10 +114,15 @@ export class SideEffectLinkedToNoteHash implements SideEffectType { * Convert to an array of fields. * @returns The array of fields. */ - toFieldArray(): Fr[] { + toFields(): Fr[] { return [this.value, this.noteHash, this.counter]; } + static fromFields(fields: Fr[] | FieldReader): SideEffectLinkedToNoteHash { + const reader = FieldReader.asReader(fields); + return new SideEffectLinkedToNoteHash(reader.readField(), reader.readField(), reader.readField()); + } + /** * Returns whether this instance of side-effect is empty. * @returns True if the value, note hash and counter are all zero. diff --git a/yarn-project/circuits.js/src/structs/state_reference.ts b/yarn-project/circuits.js/src/structs/state_reference.ts index 21c9359434f..444f44f4b03 100644 --- a/yarn-project/circuits.js/src/structs/state_reference.ts +++ b/yarn-project/circuits.js/src/structs/state_reference.ts @@ -15,7 +15,7 @@ export class StateReference { ) {} toBuffer() { - // Note: The order here must match the order in the HeaderDecoder solidity library. + // Note: The order here must match the order in the HeaderLib solidity library. return serializeToBuffer(this.l1ToL2MessageTree, this.partial); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 6586d23ceb1..58e1c8bdb41 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -33,6 +33,8 @@ import { FunctionData, FunctionSelector, G1AffineElement, + GrumpkinPrivateKey, + GrumpkinScalar, KernelCircuitPublicInputs, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_COMMITMENTS_PER_CALL, @@ -42,6 +44,8 @@ import { MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, @@ -62,6 +66,8 @@ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_FIELDS_PER_SHA256, NewContractData, + NullifierKeyValidationRequest, + NullifierKeyValidationRequestContext, NullifierLeafPreimage, OptionallyRevealedData, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, @@ -171,6 +177,28 @@ export function makeSelector(seed: number): FunctionSelector { return new FunctionSelector(seed); } +/** + * Creates arbitrary NullifierKeyValidationRequest from the given seed. + * @param seed - The seed to use for generating the NullifierKeyValidationRequest. + * @returns A NullifierKeyValidationRequest. + */ +function makeNullifierKeyValidationRequest(seed: number): NullifierKeyValidationRequest { + return new NullifierKeyValidationRequest(makePoint(seed), makeGrumpkinPrivateKey(seed + 2)); +} + +/** + * Creates arbitrary NullifierKeyValidationRequestContext from the given seed. + * @param seed - The seed to use for generating the NullifierKeyValidationRequestContext. + * @returns A NullifierKeyValidationRequestContext. + */ +function makeNullifierKeyValidationRequestContext(seed: number): NullifierKeyValidationRequestContext { + return new NullifierKeyValidationRequestContext( + makePoint(seed), + makeGrumpkinPrivateKey(seed + 2), + makeAztecAddress(seed + 4), + ); +} + /** * Creates arbitrary public data update request. * @param seed - The seed to use for generating the public data update request. @@ -234,7 +262,12 @@ export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulated return new CombinedAccumulatedData( makeAggregationObject(seed), tupleGenerator(MAX_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), - tupleGenerator(MAX_NEW_COMMITMENTS_PER_TX, sideEffectFromNumber, seed + 0x100), + tupleGenerator( + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + makeNullifierKeyValidationRequestContext, + seed + 0x100, + ), + tupleGenerator(MAX_NEW_COMMITMENTS_PER_TX, sideEffectFromNumber, seed + 0x120), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x200), tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), @@ -469,6 +502,15 @@ export function makePoint(seed = 1): Point { return new Point(fr(seed), fr(seed + 1)); } +/** + * Creates an arbitrary grumpkin private key. + * @param seed - Seed to generate the values. + * @returns A GrumpkinPrivateKey. + */ +export function makeGrumpkinPrivateKey(seed = 1): GrumpkinPrivateKey { + return GrumpkinScalar.fromHighLow(fr(seed), fr(seed + 1)); +} + /** * Makes arbitrary previous kernel data. * @param seed - The seed to use for generating the previous kernel data. @@ -690,6 +732,11 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn argsHash: fr(seed + 0x100), returnValues: makeTuple(RETURN_VALUES_LENGTH, fr, seed + 0x200), readRequests: makeTuple(MAX_READ_REQUESTS_PER_CALL, sideEffectFromNumber, seed + 0x300), + nullifierKeyValidationRequests: makeTuple( + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + makeNullifierKeyValidationRequest, + seed + 0x300, + ), newCommitments: makeTuple(MAX_NEW_COMMITMENTS_PER_CALL, sideEffectFromNumber, seed + 0x400), newNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, sideEffectLinkedFromNumber, seed + 0x500), privateCallStackHashes: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, fr, seed + 0x600), diff --git a/yarn-project/cli/src/bin/index.ts b/yarn-project/cli/src/bin/index.ts index 4e1c4b1ad28..0d79e796d50 100644 --- a/yarn-project/cli/src/bin/index.ts +++ b/yarn-project/cli/src/bin/index.ts @@ -5,7 +5,7 @@ import 'source-map-support/register.js'; import { getProgram } from '../index.js'; -const debugLogger = createDebugLogger('aztec:cli'); +const debugLogger = createDebugLogger('aztec:cli-client'); const log = createConsoleLogger(); /** CLI main entrypoint */ diff --git a/yarn-project/cli/src/client.test.ts b/yarn-project/cli/src/client.test.ts index 526c218ac35..bcace613eeb 100644 --- a/yarn-project/cli/src/client.test.ts +++ b/yarn-project/cli/src/client.test.ts @@ -1,5 +1,5 @@ +import { NodeInfo } from '@aztec/aztec.js'; import { PXE } from '@aztec/circuit-types'; -import { NodeInfo } from '@aztec/types/interfaces'; import { MockProxy, mock } from 'jest-mock-extended'; diff --git a/yarn-project/cli/src/cmds/add_contract.ts b/yarn-project/cli/src/cmds/add_contract.ts index 6ac361f1fbc..0124a6c83fb 100644 --- a/yarn-project/cli/src/cmds/add_contract.ts +++ b/yarn-project/cli/src/cmds/add_contract.ts @@ -4,9 +4,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; import { getContractArtifact } from '../utils.js'; -/** - * - */ export async function addContract( rpcUrl: string, contractArtifactPath: string, diff --git a/yarn-project/cli/src/cmds/add_note.ts b/yarn-project/cli/src/cmds/add_note.ts index e547f76d3c9..c70176159d7 100644 --- a/yarn-project/cli/src/cmds/add_note.ts +++ b/yarn-project/cli/src/cmds/add_note.ts @@ -5,9 +5,6 @@ import { DebugLogger } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; import { parseFields } from '../parse_args.js'; -/** - * - */ export async function addNote( address: AztecAddress, contractAddress: AztecAddress, diff --git a/yarn-project/cli/src/cmds/block_number.ts b/yarn-project/cli/src/cmds/block_number.ts index 37795a12966..c5aed126443 100644 --- a/yarn-project/cli/src/cmds/block_number.ts +++ b/yarn-project/cli/src/cmds/block_number.ts @@ -2,9 +2,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function blockNumber(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const num = await client.getBlockNumber(); diff --git a/yarn-project/cli/src/cmds/call.ts b/yarn-project/cli/src/cmds/call.ts index 7e395276177..cab98e2dd42 100644 --- a/yarn-project/cli/src/cmds/call.ts +++ b/yarn-project/cli/src/cmds/call.ts @@ -6,9 +6,6 @@ import { format } from 'util'; import { createCompatibleClient } from '../client.js'; import { getFunctionArtifact, getTxSender, prepTx } from '../utils.js'; -/** - * - */ export async function call( functionName: string, functionArgsIn: any[], diff --git a/yarn-project/cli/src/cmds/check_deploy.ts b/yarn-project/cli/src/cmds/check_deploy.ts index 25641418c71..90408309ff4 100644 --- a/yarn-project/cli/src/cmds/check_deploy.ts +++ b/yarn-project/cli/src/cmds/check_deploy.ts @@ -3,9 +3,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function checkDeploy(rpcUrl: string, contractAddress: AztecAddress, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const isDeployed = await isContractDeployed(client, contractAddress); diff --git a/yarn-project/cli/src/cmds/compute_selector.ts b/yarn-project/cli/src/cmds/compute_selector.ts index d0ef8e14abe..074be33597a 100644 --- a/yarn-project/cli/src/cmds/compute_selector.ts +++ b/yarn-project/cli/src/cmds/compute_selector.ts @@ -1,9 +1,6 @@ import { FunctionSelector } from '@aztec/foundation/abi'; import { LogFn } from '@aztec/foundation/log'; -/** - * - */ export function computeSelector(functionSignature: string, log: LogFn) { const selector = FunctionSelector.fromSignature(functionSignature); log(`${selector}`); diff --git a/yarn-project/cli/src/cmds/create_account.ts b/yarn-project/cli/src/cmds/create_account.ts index a8f895a84ce..2ad6a5d92d6 100644 --- a/yarn-project/cli/src/cmds/create_account.ts +++ b/yarn-project/cli/src/cmds/create_account.ts @@ -5,9 +5,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function createAccount( rpcUrl: string, privateKey: Fq, diff --git a/yarn-project/cli/src/cmds/deploy.ts b/yarn-project/cli/src/cmds/deploy.ts index a8c7e7ffd96..986417edac8 100644 --- a/yarn-project/cli/src/cmds/deploy.ts +++ b/yarn-project/cli/src/cmds/deploy.ts @@ -6,9 +6,6 @@ import { encodeArgs } from '../encoding.js'; import { GITHUB_TAG_PREFIX } from '../github.js'; import { getContractArtifact, getFunctionArtifact } from '../utils.js'; -/** - * - */ export async function deploy( artifactPath: string, json: boolean, diff --git a/yarn-project/cli/src/cmds/deploy_l1_contracts.ts b/yarn-project/cli/src/cmds/deploy_l1_contracts.ts index 3b45537d88a..7ecd5abe455 100644 --- a/yarn-project/cli/src/cmds/deploy_l1_contracts.ts +++ b/yarn-project/cli/src/cmds/deploy_l1_contracts.ts @@ -2,9 +2,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { deployAztecContracts } from '../utils.js'; -/** - * - */ export async function deployL1Contracts( rpcUrl: string, apiKey: string, diff --git a/yarn-project/cli/src/cmds/example_contracts.ts b/yarn-project/cli/src/cmds/example_contracts.ts index a5b71e2ec0d..5b40c5c60c3 100644 --- a/yarn-project/cli/src/cmds/example_contracts.ts +++ b/yarn-project/cli/src/cmds/example_contracts.ts @@ -2,9 +2,6 @@ import { LogFn } from '@aztec/foundation/log'; import { getExampleContractArtifacts } from '../utils.js'; -/** - * - */ export async function exampleContracts(log: LogFn) { const abisList = await getExampleContractArtifacts(); const names = Object.keys(abisList); diff --git a/yarn-project/cli/src/cmds/generate_p2p_private_key.ts b/yarn-project/cli/src/cmds/generate_p2p_private_key.ts index 4bf3ad7a5c4..928e61974ba 100644 --- a/yarn-project/cli/src/cmds/generate_p2p_private_key.ts +++ b/yarn-project/cli/src/cmds/generate_p2p_private_key.ts @@ -2,9 +2,6 @@ import { LogFn } from '@aztec/foundation/log'; import { createSecp256k1PeerId } from '@libp2p/peer-id-factory'; -/** - * - */ export async function generateP2PPrivateKey(log: LogFn) { const peerId = await createSecp256k1PeerId(); const exportedPeerId = Buffer.from(peerId.privateKey!).toString('hex'); diff --git a/yarn-project/cli/src/cmds/generate_private_key.ts b/yarn-project/cli/src/cmds/generate_private_key.ts index 8586f03f37a..b447cdcc738 100644 --- a/yarn-project/cli/src/cmds/generate_private_key.ts +++ b/yarn-project/cli/src/cmds/generate_private_key.ts @@ -3,9 +3,6 @@ import { LogFn } from '@aztec/foundation/log'; import { mnemonicToAccount } from 'viem/accounts'; -/** - * - */ export function generatePrivateKey(mnemonic: string | undefined, log: LogFn) { let privKey; let publicKey; diff --git a/yarn-project/cli/src/cmds/get_account.ts b/yarn-project/cli/src/cmds/get_account.ts index 47b3b1056a7..8b3e9359d5f 100644 --- a/yarn-project/cli/src/cmds/get_account.ts +++ b/yarn-project/cli/src/cmds/get_account.ts @@ -3,9 +3,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getAccount(aztecAddress: AztecAddress, rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const account = await client.getRegisteredAccount(aztecAddress); diff --git a/yarn-project/cli/src/cmds/get_accounts.ts b/yarn-project/cli/src/cmds/get_accounts.ts index 79f9dbee325..1e36475f3a8 100644 --- a/yarn-project/cli/src/cmds/get_accounts.ts +++ b/yarn-project/cli/src/cmds/get_accounts.ts @@ -2,9 +2,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getAccounts( rpcUrl: string, json: boolean, diff --git a/yarn-project/cli/src/cmds/get_contract_data.ts b/yarn-project/cli/src/cmds/get_contract_data.ts index 432d4fa249e..80f1e7afb2a 100644 --- a/yarn-project/cli/src/cmds/get_contract_data.ts +++ b/yarn-project/cli/src/cmds/get_contract_data.ts @@ -4,9 +4,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getContractData( rpcUrl: string, contractAddress: AztecAddress, diff --git a/yarn-project/cli/src/cmds/get_logs.ts b/yarn-project/cli/src/cmds/get_logs.ts index 1a48dd920cc..76c27c76726 100644 --- a/yarn-project/cli/src/cmds/get_logs.ts +++ b/yarn-project/cli/src/cmds/get_logs.ts @@ -5,9 +5,6 @@ import { sleep } from '@aztec/foundation/sleep'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getLogs( txHash: TxHash, fromBlock: number, diff --git a/yarn-project/cli/src/cmds/get_node_info.ts b/yarn-project/cli/src/cmds/get_node_info.ts index 2f14d5f5a24..b775c08aa0d 100644 --- a/yarn-project/cli/src/cmds/get_node_info.ts +++ b/yarn-project/cli/src/cmds/get_node_info.ts @@ -2,9 +2,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getNodeInfo(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const info = await client.getNodeInfo(); diff --git a/yarn-project/cli/src/cmds/get_recipient.ts b/yarn-project/cli/src/cmds/get_recipient.ts index 9edf6edecfc..270bbad9ac2 100644 --- a/yarn-project/cli/src/cmds/get_recipient.ts +++ b/yarn-project/cli/src/cmds/get_recipient.ts @@ -3,9 +3,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getRecipient(aztecAddress: AztecAddress, rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const recipient = await client.getRecipient(aztecAddress); diff --git a/yarn-project/cli/src/cmds/get_recipients.ts b/yarn-project/cli/src/cmds/get_recipients.ts index 92bc9fad973..875b84b6038 100644 --- a/yarn-project/cli/src/cmds/get_recipients.ts +++ b/yarn-project/cli/src/cmds/get_recipients.ts @@ -2,9 +2,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getRecipients(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const recipients = await client.getRecipients(); diff --git a/yarn-project/cli/src/cmds/get_tx_receipt.ts b/yarn-project/cli/src/cmds/get_tx_receipt.ts index fe133608820..beaa53e2f9b 100644 --- a/yarn-project/cli/src/cmds/get_tx_receipt.ts +++ b/yarn-project/cli/src/cmds/get_tx_receipt.ts @@ -4,9 +4,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function getTxReceipt(rpcUrl: string, txHash: TxHash, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const receipt = await client.getTxReceipt(txHash); diff --git a/yarn-project/cli/src/cmds/inspect_contract.ts b/yarn-project/cli/src/cmds/inspect_contract.ts index e55954adc1e..ad8aafa871d 100644 --- a/yarn-project/cli/src/cmds/inspect_contract.ts +++ b/yarn-project/cli/src/cmds/inspect_contract.ts @@ -7,9 +7,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { getContractArtifact } from '../utils.js'; -/** - * - */ export async function inspectContract(contractArtifactFile: string, debugLogger: DebugLogger, log: LogFn) { const contractArtifact = await getContractArtifact(contractArtifactFile, debugLogger); const contractFns = contractArtifact.functions.filter( diff --git a/yarn-project/cli/src/cmds/parse_parameter_struct.ts b/yarn-project/cli/src/cmds/parse_parameter_struct.ts index 1ef572fd5ce..d8b29211d3a 100644 --- a/yarn-project/cli/src/cmds/parse_parameter_struct.ts +++ b/yarn-project/cli/src/cmds/parse_parameter_struct.ts @@ -5,9 +5,6 @@ import { LogFn } from '@aztec/foundation/log'; import { parseStructString } from '../encoding.js'; import { getContractArtifact } from '../utils.js'; -/** - * - */ export async function parseParameterStruct( encodedString: string, contractArtifactPath: string, diff --git a/yarn-project/cli/src/cmds/register_account.ts b/yarn-project/cli/src/cmds/register_account.ts index fae880f81a1..b6949cee4fa 100644 --- a/yarn-project/cli/src/cmds/register_account.ts +++ b/yarn-project/cli/src/cmds/register_account.ts @@ -3,9 +3,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function registerAccount( rpcUrl: string, privateKey: Fq, diff --git a/yarn-project/cli/src/cmds/register_recipient.ts b/yarn-project/cli/src/cmds/register_recipient.ts index df8b7a0c11a..6458143c542 100644 --- a/yarn-project/cli/src/cmds/register_recipient.ts +++ b/yarn-project/cli/src/cmds/register_recipient.ts @@ -4,9 +4,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; -/** - * - */ export async function registerRecipient( aztecAddress: AztecAddress, publicKey: Point, diff --git a/yarn-project/cli/src/cmds/send.ts b/yarn-project/cli/src/cmds/send.ts index 50dab7479e9..8513fe1392e 100644 --- a/yarn-project/cli/src/cmds/send.ts +++ b/yarn-project/cli/src/cmds/send.ts @@ -5,9 +5,6 @@ import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; import { prepTx } from '../utils.js'; -/** - * - */ export async function send( functionName: string, functionArgsIn: any[], diff --git a/yarn-project/cli/src/cmds/unbox.ts b/yarn-project/cli/src/cmds/unbox.ts index 38150ba16e4..b1b6542b5e0 100644 --- a/yarn-project/cli/src/cmds/unbox.ts +++ b/yarn-project/cli/src/cmds/unbox.ts @@ -80,9 +80,6 @@ function copyDependenciesToBox(dirName: string, destPath: string) { ); } -/** - * - */ function packageJsonInjectLocalResolutions(path: string) { const data = readFileSync(path, 'utf-8'); const packageJson = JSON.parse(data); diff --git a/yarn-project/cli/src/update/update.ts b/yarn-project/cli/src/update/update.ts index 9f78d0caab2..5c946f9953d 100644 --- a/yarn-project/cli/src/update/update.ts +++ b/yarn-project/cli/src/update/update.ts @@ -10,7 +10,7 @@ import { updateAztecNr } from './noir.js'; import { getNewestVersion, updateAztecDeps, updateLockfile } from './npm.js'; const AZTECJS_PACKAGE = '@aztec/aztec.js'; -const UPDATE_DOCS_URL = 'https://docs.aztec.network/dev_docs/updating'; +const UPDATE_DOCS_URL = 'https://docs.aztec.network/developers/updating'; export async function update( projectPath: string, diff --git a/yarn-project/cli/src/utils.ts b/yarn-project/cli/src/utils.ts index a3926ae6750..ef2c07a811b 100644 --- a/yarn-project/cli/src/utils.ts +++ b/yarn-project/cli/src/utils.ts @@ -62,7 +62,9 @@ export async function deployAztecContracts( const { createEthereumChain, deployL1Contracts } = await import('@aztec/ethereum'); const { mnemonicToAccount, privateKeyToAccount } = await import('viem/accounts'); - const account = !privateKey ? mnemonicToAccount(mnemonic!) : privateKeyToAccount(`0x${privateKey}`); + const account = !privateKey + ? mnemonicToAccount(mnemonic!) + : privateKeyToAccount(`${privateKey.startsWith('0x') ? '' : '0x'}${privateKey}` as `0x${string}`); const chain = createEthereumChain(rpcUrl, apiKey); const l1Artifacts: L1ContractArtifactsForDeployment = { contractDeploymentEmitter: { diff --git a/yarn-project/end-to-end/package.json b/yarn-project/end-to-end/package.json index 88ccca29173..f019bf353b4 100644 --- a/yarn-project/end-to-end/package.json +++ b/yarn-project/end-to-end/package.json @@ -5,6 +5,7 @@ "exports": "./dest/index.js", "scripts": { "build": "yarn clean && tsc -b && webpack", + "build:e2e": "yarn clean && tsc -b", "build:dev": "tsc -b --watch", "build:web": "webpack", "clean": "rm -rf ./dest .tsbuildinfo", diff --git a/yarn-project/end-to-end/scripts/docker-compose-browser.yml b/yarn-project/end-to-end/scripts/docker-compose-browser.yml index d3abd8fb74d..f859de7de39 100644 --- a/yarn-project/end-to-end/scripts/docker-compose-browser.yml +++ b/yarn-project/end-to-end/scripts/docker-compose-browser.yml @@ -13,7 +13,7 @@ services: - '8545:8545' sandbox: - image: aztecprotocol/aztec-sandbox:latest + image: aztecprotocol/aztec:latest environment: DEBUG: 'aztec:*' DEBUG_COLORS: 1 diff --git a/yarn-project/end-to-end/scripts/docker-compose-p2p.yml b/yarn-project/end-to-end/scripts/docker-compose-p2p.yml index 3bca942dd23..50cca540d6c 100644 --- a/yarn-project/end-to-end/scripts/docker-compose-p2p.yml +++ b/yarn-project/end-to-end/scripts/docker-compose-p2p.yml @@ -7,12 +7,11 @@ services: - '8545:8545' p2p-bootstrap: - image: aztecprotocol/aztec-sandbox:latest + image: aztecprotocol/aztec:latest + command: 'start --p2p-bootstrap' ports: - '40400:40400' - command: 'start' environment: - MODE: 'p2p-bootstrap' DEBUG: 'aztec:*' DEBUG_COLORS: 1 P2P_TCP_LISTEN_PORT: 40400 diff --git a/yarn-project/end-to-end/scripts/docker-compose.yml b/yarn-project/end-to-end/scripts/docker-compose.yml index 9b675470f35..6a05e652777 100644 --- a/yarn-project/end-to-end/scripts/docker-compose.yml +++ b/yarn-project/end-to-end/scripts/docker-compose.yml @@ -13,7 +13,7 @@ services: - '8545:8545' sandbox: - image: aztecprotocol/aztec-sandbox:latest + image: aztecprotocol/aztec:latest environment: DEBUG: 'aztec:*' DEBUG_COLORS: 1 diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts index f5904fdce5b..a434f91f090 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts @@ -14,18 +14,15 @@ import { computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; +import { AztecLmdbStore } from '@aztec/kv-store'; import { Pedersen, SparseTree, newTree } from '@aztec/merkle-tree'; import { SlowTreeContract, TokenBlacklistContract, TokenContract } from '@aztec/noir-contracts'; import { jest } from '@jest/globals'; -import levelup from 'levelup'; -import { type MemDown, default as memdown } from 'memdown'; import { setup } from './fixtures/utils.js'; import { TokenSimulator } from './simulators/token_simulator.js'; -export const createMemDown = () => (memdown as any)() as MemDown; - const TIMEOUT = 90_000; describe('e2e_blacklist_token_contract', () => { @@ -48,7 +45,7 @@ describe('e2e_blacklist_token_contract', () => { const getMembershipProof = async (index: bigint, includeUncommitted: boolean) => { return { index, - value: Fr.fromBuffer((await slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted))!), + value: Fr.fromBuffer(slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!), // eslint-disable-next-line camelcase sibling_path: (await slowUpdateTreeSimulator.getSiblingPath(index, includeUncommitted)).toFieldArray(), }; @@ -107,7 +104,7 @@ describe('e2e_blacklist_token_contract', () => { slowTree = await SlowTreeContract.deploy(wallets[0]).send().deployed(); const depth = 254; - slowUpdateTreeSimulator = await newTree(SparseTree, levelup(createMemDown()), new Pedersen(), 'test', depth); + slowUpdateTreeSimulator = await newTree(SparseTree, await AztecLmdbStore.openTmp(), new Pedersen(), 'test', depth); const deployTx = TokenBlacklistContract.deploy(wallets[0], accounts[0], slowTree.address).send({}); const receipt = await deployTx.wait(); diff --git a/yarn-project/end-to-end/src/e2e_card_game.test.ts b/yarn-project/end-to-end/src/e2e_card_game.test.ts index e78a3a9ae84..69d7bbae065 100644 --- a/yarn-project/end-to-end/src/e2e_card_game.test.ts +++ b/yarn-project/end-to-end/src/e2e_card_game.test.ts @@ -9,6 +9,9 @@ import { Wallet, generatePublicKey, } from '@aztec/aztec.js'; +import { computeNullifierSecretKey, computeSiloedNullifierSecretKey } from '@aztec/circuits.js'; +import { toBufferLE } from '@aztec/foundation/bigint-buffer'; +import { sha256 } from '@aztec/foundation/crypto'; import { CardGameContract } from '@aztec/noir-contracts/CardGame'; import { setup } from './fixtures/utils.js'; @@ -25,9 +28,7 @@ const cardToField = (card: Card): bigint => { }; interface PlayerGameEntry { - address: { - inner: bigint; - }; + address: AztecAddress; deck_strength: bigint; points: bigint; } @@ -51,6 +52,8 @@ function unwrapOptions(options: NoirOption[]): T[] { return options.filter((option: any) => option._is_some).map((option: any) => option._value); } +// Game settings. +const PACK_CARDS = 3; const GAME_ID = 42; const PLAYER_ENCRYPTION_KEYS = INITIAL_TEST_ENCRYPTION_KEYS; @@ -61,6 +64,8 @@ describe('e2e_card_game', () => { let teardown: () => Promise; let wallets: AccountWallet[]; + let nullifierSecretKeys: GrumpkinScalar[]; + let firstPlayerWallet: Wallet; let secondPlayerWallet: Wallet; let thirdPlayerWallet: Wallet; @@ -73,6 +78,21 @@ describe('e2e_card_game', () => { let contractAsSecondPlayer: CardGameContract; let contractAsThirdPlayer: CardGameContract; + const getPackedCards = (accountIndex: number, seed: bigint): Card[] => { + const nullifierKey = nullifierSecretKeys[accountIndex]; + const secret = computeSiloedNullifierSecretKey(nullifierKey, contract.address); + const mix = secret.high.add(secret.low).toBigInt() + seed; + const randomBytes = sha256(toBufferLE(mix, 32)); + const cards: Card[] = []; + for (let i = 0; i < PACK_CARDS; ++i) { + cards.push({ + strength: BigInt(randomBytes.readUint8(i) + randomBytes.readUint8(i + 1) * 256), + points: BigInt(randomBytes.readUint8(i + 2) + randomBytes.readUint8(i + 3) * 256), + }); + } + return cards; + }; + beforeAll(async () => { ({ pxe, logger, teardown, wallets } = await setup(0)); @@ -98,6 +118,8 @@ describe('e2e_card_game', () => { [firstPlayerWallet, secondPlayerWallet, thirdPlayerWallet] = wallets; [firstPlayer, secondPlayer, thirdPlayer] = wallets.map(a => a.getAddress()); + + nullifierSecretKeys = PLAYER_ENCRYPTION_KEYS.map(pk => computeNullifierSecretKey(pk)); }, 100_000); beforeEach(async () => { @@ -118,33 +140,21 @@ describe('e2e_card_game', () => { const contractFor = (address: AztecAddress) => contract.withWallet(getWallet(address))!; it('should be able to buy packs', async () => { - await contract.methods.buy_pack(27n).send().wait(); + const seed = 27n; + await contract.methods.buy_pack(seed).send().wait(); const collection = await contract.methods.view_collection_cards(firstPlayer, 0).view({ from: firstPlayer }); - expect(unwrapOptions(collection)).toMatchInlineSnapshot(` - [ - { - "points": 18471n, - "strength": 55863n, - }, - { - "points": 30024n, - "strength": 10202n, - }, - { - "points": 47477n, - "strength": 18471n, - }, - ] - `); + const expected = getPackedCards(0, seed); + expect(unwrapOptions(collection)).toMatchObject(expected); }, 30_000); describe('game join', () => { + const seed = 27n; let firstPlayerCollection: Card[]; beforeEach(async () => { await Promise.all([ - contract.methods.buy_pack(27n).send().wait(), - contractAsSecondPlayer.methods.buy_pack(27n).send().wait(), + contract.methods.buy_pack(seed).send().wait(), + contractAsSecondPlayer.methods.buy_pack(seed).send().wait(), ]); firstPlayerCollection = unwrapOptions( await contract.methods.view_collection_cards(firstPlayer, 0).view({ from: firstPlayer }), @@ -166,28 +176,17 @@ describe('e2e_card_game', () => { const collection = await contract.methods.view_collection_cards(firstPlayer, 0).view({ from: firstPlayer }); expect(unwrapOptions(collection)).toHaveLength(1); - expect(unwrapOptions(collection)).toMatchInlineSnapshot(` - [ - { - "points": 30024n, - "strength": 10202n, - }, - ] - `); + expect(unwrapOptions(collection)).toMatchObject([firstPlayerCollection[1]]); expect((await contract.methods.view_game(GAME_ID).view({ from: firstPlayer })) as Game).toMatchObject({ players: [ { - address: { - inner: firstPlayer.toBigInt(), - }, + address: firstPlayer, deck_strength: expect.anything(), points: 0n, }, { - address: { - inner: 0n, - }, + address: AztecAddress.ZERO, deck_strength: 0n, points: 0n, }, @@ -222,16 +221,12 @@ describe('e2e_card_game', () => { expect((await contract.methods.view_game(GAME_ID).view({ from: firstPlayer })) as Game).toMatchObject({ players: expect.arrayContaining([ { - address: { - inner: firstPlayer.toBigInt(), - }, + address: firstPlayer, deck_strength: expect.anything(), points: 0n, }, { - address: { - inner: secondPlayer.toBigInt(), - }, + address: secondPlayer, deck_strength: expect.anything(), points: 0n, }, @@ -250,10 +245,11 @@ describe('e2e_card_game', () => { let thirdPlayerCOllection: Card[]; beforeEach(async () => { + const seed = 27n; await Promise.all([ - contract.methods.buy_pack(27n).send().wait(), - contractAsSecondPlayer.methods.buy_pack(27n).send().wait(), - contractAsThirdPlayer.methods.buy_pack(27n).send().wait(), + contract.methods.buy_pack(seed).send().wait(), + contractAsSecondPlayer.methods.buy_pack(seed).send().wait(), + contractAsThirdPlayer.methods.buy_pack(seed).send().wait(), ]); firstPlayerCollection = unwrapOptions( @@ -275,16 +271,16 @@ describe('e2e_card_game', () => { async function playGame(playerDecks: { address: AztecAddress; deck: Card[] }[], id = GAME_ID) { const initialGameState = (await contract.methods.view_game(id).view({ from: firstPlayer })) as Game; - const players = initialGameState.players.map(player => player.address.inner); + const players = initialGameState.players.map(player => player.address); const cards = players.map( - player => playerDecks.find(playerDeckEntry => playerDeckEntry.address.toBigInt() === player)!.deck, + player => playerDecks.find(playerDeckEntry => playerDeckEntry.address.equals(player))!.deck, ); for (let roundIndex = 0; roundIndex < cards.length; roundIndex++) { for (let playerIndex = 0; playerIndex < players.length; playerIndex++) { const player = players[playerIndex]; const card = cards[playerIndex][roundIndex]; - await contractFor(AztecAddress.fromBigInt(player)).methods.play_card(id, card).send().wait(); + await contractFor(player).methods.play_card(id, card).send().wait(); } } @@ -309,8 +305,8 @@ describe('e2e_card_game', () => { ]); const sortedByPoints = game.players.sort((a, b) => Number(b.points - a.points)); - const winner = AztecAddress.fromBigInt(sortedByPoints[0].address.inner); - const loser = AztecAddress.fromBigInt(sortedByPoints[1].address.inner); + const winner = sortedByPoints[0].address; + const loser = sortedByPoints[1].address; await expect( contractFor(loser).methods.claim_cards(GAME_ID, game.rounds_cards.map(cardToField)).send().wait(), diff --git a/yarn-project/end-to-end/src/e2e_cli.test.ts b/yarn-project/end-to-end/src/e2e_cli.test.ts index 221902983f9..7fd0884a091 100644 --- a/yarn-project/end-to-end/src/e2e_cli.test.ts +++ b/yarn-project/end-to-end/src/e2e_cli.test.ts @@ -20,7 +20,7 @@ const testSetup = async () => { debug(`Environment set up`); ({ pxe, teardown } = context); if (!RPC_URL) { - http = startHttpRpcServer(pxe, createPXERpcServer, HTTP_PORT); + http = startHttpRpcServer('pxe', pxe, createPXERpcServer, HTTP_PORT); debug(`HTTP RPC server started on port ${HTTP_PORT}`); RPC_URL = `http://localhost:${HTTP_PORT}`; } diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index f1f4d29b3ae..d3dec0751ea 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -36,12 +36,32 @@ describe('e2e_nested_contract', () => { .wait(); if (isGenerateTestDataEnabled()) { - const privateKernelInputs = getTestData('private-kernel-inputs-inner'); - const nestedCallPrivateKernelInput = privateKernelInputs[privateKernelInputs.length - 1]; - writeFileSync( - '../noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex', - nestedCallPrivateKernelInput.toBuffer().toString('hex'), - ); + { + const privateKernelInputsInit = getTestData('private-kernel-inputs-init'); + const nestedCallPrivateKernelInput = privateKernelInputsInit[0]; + writeFileSync( + '../noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex', + nestedCallPrivateKernelInput.toBuffer().toString('hex'), + ); + } + + { + const privateKernelInputsInner = getTestData('private-kernel-inputs-inner'); + const nestedCallPrivateKernelInput = privateKernelInputsInner[privateKernelInputsInner.length - 1]; + writeFileSync( + '../noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex', + nestedCallPrivateKernelInput.toBuffer().toString('hex'), + ); + } + + { + const privateKernelInputsOrdering = getTestData('private-kernel-inputs-ordering'); + const nestedCallPrivateKernelInput = privateKernelInputsOrdering[0]; + writeFileSync( + '../noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex', + nestedCallPrivateKernelInput.toBuffer().toString('hex'), + ); + } } }, 100_000); diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 3d5b309a36e..68f41d00444 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -8,6 +8,9 @@ interface NoirOption { _value: T; } +const sortFunc = (a: any, b: any) => + a.points > b.points ? 1 : a.points < b.points ? -1 : a.randomness > b.randomness ? 1 : -1; + function unwrapOptions(options: NoirOption[]): T[] { return options.filter((option: any) => option._is_some).map((option: any) => option._value); } @@ -28,9 +31,17 @@ describe('e2e_note_getter', () => { afterAll(() => teardown()); it('inserts notes from 0-9, then makes multiple queries specifying the total suite of comparators', async () => { - const numbers = [...Array(10).keys()]; - await Promise.all(numbers.map(number => contract.methods.insert_note(number).send().wait())); - await contract.methods.insert_note(5).send().wait(); + // ISSUE #4243 + // Calling this function does not work like this + // const numbers = [...Array(10).keys()]; + // await Promise.all(numbers.map(number => contract.methods.insert_note(number).send().wait())); + // It causes a race condition complaining about root mismatch + + await contract.methods + .insert_notes([...Array(10).keys()]) + .send() + .wait(); + await contract.methods.insert_note(5, Fr.ZERO).send().wait(); const [returnEq, returnNeq, returnLt, returnGt, returnLte, returnGte] = await Promise.all([ contract.methods.read_note(5, Comparator.EQ).view(), @@ -41,15 +52,21 @@ describe('e2e_note_getter', () => { contract.methods.read_note(5, Comparator.GTE).view(), ]); - expect(unwrapOptions(returnEq).map(({ points, randomness }: any) => ({ points, randomness }))).toStrictEqual([ - { points: 5n, randomness: 1n }, - { points: 5n, randomness: 1n }, - ]); + expect( + unwrapOptions(returnEq) + .map(({ points, randomness }: any) => ({ points, randomness })) + .sort(sortFunc), + ).toStrictEqual( + [ + { points: 5n, randomness: 1n }, + { points: 5n, randomness: 0n }, + ].sort(sortFunc), + ); expect( unwrapOptions(returnNeq) .map(({ points, randomness }: any) => ({ points, randomness })) - .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + .sort(sortFunc), ).toStrictEqual( [ { points: 0n, randomness: 1n }, @@ -61,13 +78,13 @@ describe('e2e_note_getter', () => { { points: 8n, randomness: 1n }, { points: 4n, randomness: 1n }, { points: 3n, randomness: 1n }, - ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ].sort(sortFunc), ); expect( unwrapOptions(returnLt) .map(({ points, randomness }: any) => ({ points, randomness })) - .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + .sort(sortFunc), ).toStrictEqual( [ { points: 0n, randomness: 1n }, @@ -75,51 +92,51 @@ describe('e2e_note_getter', () => { { points: 2n, randomness: 1n }, { points: 4n, randomness: 1n }, { points: 3n, randomness: 1n }, - ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ].sort(sortFunc), ); expect( unwrapOptions(returnGt) .map(({ points, randomness }: any) => ({ points, randomness })) - .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + .sort(sortFunc), ).toStrictEqual( [ { points: 7n, randomness: 1n }, { points: 9n, randomness: 1n }, { points: 6n, randomness: 1n }, { points: 8n, randomness: 1n }, - ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ].sort(sortFunc), ); expect( unwrapOptions(returnLte) .map(({ points, randomness }: any) => ({ points, randomness })) - .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + .sort(sortFunc), ).toStrictEqual( [ { points: 5n, randomness: 1n }, - { points: 5n, randomness: 1n }, + { points: 5n, randomness: 0n }, { points: 0n, randomness: 1n }, { points: 1n, randomness: 1n }, { points: 2n, randomness: 1n }, { points: 4n, randomness: 1n }, { points: 3n, randomness: 1n }, - ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ].sort(sortFunc), ); expect( unwrapOptions(returnGte) .map(({ points, randomness }: any) => ({ points, randomness })) - .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + .sort(sortFunc), ).toStrictEqual( [ - { points: 5n, randomness: 1n }, + { points: 5n, randomness: 0n }, { points: 5n, randomness: 1n }, { points: 7n, randomness: 1n }, { points: 9n, randomness: 1n }, { points: 6n, randomness: 1n }, { points: 8n, randomness: 1n }, - ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ].sort(sortFunc), ); }, 300_000); }); diff --git a/yarn-project/end-to-end/src/e2e_p2p_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p_network.test.ts index 5522ad9c880..0278c1ce7c8 100644 --- a/yarn-project/end-to-end/src/e2e_p2p_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p_network.test.ts @@ -101,7 +101,7 @@ describe('e2e_p2p_network', () => { // TODO: the following config options are not applicable to bootstrap nodes p2pBlockCheckIntervalMS: 1000, - l2QueueSize: 1, + p2pL2QueueSize: 1, transactionProtocol: '', bootstrapNodes: [''], }; diff --git a/yarn-project/end-to-end/src/e2e_persistence.test.ts b/yarn-project/end-to-end/src/e2e_persistence.test.ts index 98726df23a7..7750291f270 100644 --- a/yarn-project/end-to-end/src/e2e_persistence.test.ts +++ b/yarn-project/end-to-end/src/e2e_persistence.test.ts @@ -153,7 +153,7 @@ describe('Aztec persistence', () => { expect(ownerBalance).toEqual(initialOwnerBalance - 500n); expect(targetBalance).toEqual(500n); - }); + }, 30_000); }); describe.each([ diff --git a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts index 6fc89230b02..00be8111f10 100644 --- a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts +++ b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts @@ -1,15 +1,11 @@ /* eslint-disable camelcase */ import { CheatCodes, DebugLogger, Fr, Wallet } from '@aztec/aztec.js'; +import { AztecLmdbStore } from '@aztec/kv-store'; import { Pedersen, SparseTree, newTree } from '@aztec/merkle-tree'; import { SlowTreeContract } from '@aztec/noir-contracts/SlowTree'; -import { default as levelup } from 'levelup'; -import { type MemDown, default as memdown } from 'memdown'; - import { setup } from './fixtures/utils.js'; -export const createMemDown = () => (memdown as any)() as MemDown; - describe('e2e_slow_tree', () => { let logger: DebugLogger; let wallet: Wallet; @@ -27,11 +23,17 @@ describe('e2e_slow_tree', () => { it('Messing around with noir slow tree', async () => { const depth = 254; - const slowUpdateTreeSimulator = await newTree(SparseTree, levelup(createMemDown()), new Pedersen(), 'test', depth); + const slowUpdateTreeSimulator = await newTree( + SparseTree, + await AztecLmdbStore.openTmp(), + new Pedersen(), + 'test', + depth, + ); const getMembershipProof = async (index: bigint, includeUncommitted: boolean) => { return { index, - value: Fr.fromBuffer((await slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted))!), + value: Fr.fromBuffer(slowUpdateTreeSimulator.getLeafValue(index, includeUncommitted)!), // eslint-disable-next-line camelcase sibling_path: (await slowUpdateTreeSimulator.getSiblingPath(index, includeUncommitted)).toFieldArray(), }; diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index f1bb81bea1e..3e4ffc7c8ae 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -1,6 +1,3 @@ -import { foundry } from 'viem/chains'; - export const MNEMONIC = 'test test test test test test test test test test test junk'; -export const localAnvil = foundry; export const privateKey = Buffer.from('ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', 'hex'); export const privateKey2 = Buffer.from('59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d', 'hex'); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 8942bded297..c3235d235cb 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -48,23 +48,17 @@ import { http, } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; +import { foundry } from 'viem/chains'; -import { MNEMONIC, localAnvil } from './fixtures.js'; +import { MNEMONIC } from './fixtures.js'; import { isMetricsLoggingRequested, setupMetricsLogger } from './logging.js'; export { deployAndInitializeTokenAndBridgeContracts } from '../shared/cross_chain_test_harness.js'; -const { PXE_URL = '', AZTEC_NODE_URL = '' } = process.env; +const { PXE_URL = '' } = process.env; -const getAztecNodeUrl = () => { - if (AZTEC_NODE_URL) { - return AZTEC_NODE_URL; - } - - // If AZTEC_NODE_URL is not set, we assume that the PXE is running on the same host as the Aztec Node and use the default port - const url = new URL(PXE_URL); - url.port = '8079'; - return url.toString(); +const getAztecUrl = () => { + return PXE_URL; }; export const setupL1Contracts = async ( @@ -98,7 +92,7 @@ export const setupL1Contracts = async ( contractBytecode: RollupBytecode, }, }; - return await deployL1Contracts(l1RpcUrl, account, localAnvil, logger, l1Artifacts); + return await deployL1Contracts(l1RpcUrl, account, foundry, logger, l1Artifacts); }; /** @@ -164,7 +158,7 @@ async function setupWithRemoteEnvironment( numberOfAccounts: number, ) { // we are setting up against a remote environment, l1 contracts are already deployed - const aztecNodeUrl = getAztecNodeUrl(); + const aztecNodeUrl = getAztecUrl(); logger(`Creating Aztec Node client to remote host ${aztecNodeUrl}`); const aztecNode = createAztecNodeClient(aztecNodeUrl); logger(`Creating PXE client to remote host ${PXE_URL}`); @@ -184,11 +178,11 @@ async function setupWithRemoteEnvironment( const walletClient = createWalletClient({ account, - chain: localAnvil, + chain: foundry, transport: http(config.rpcUrl), }); const publicClient = createPublicClient({ - chain: localAnvil, + chain: foundry, transport: http(config.rpcUrl), }); const deployL1ContractsValues: DeployL1Contracts = { diff --git a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts index eb57e00eb21..25e501b8fdb 100644 --- a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts +++ b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts @@ -43,7 +43,7 @@ describe('archiver integration with l1 to l2 messages', () => { config.archiverPollingIntervalMS = 100; archiver = await Archiver.createAndSync( { ...config, l1Contracts: deployL1ContractsValues.l1ContractAddresses }, - new KVArchiverDataStore(await AztecLmdbStore.create(deployL1ContractsValues.l1ContractAddresses.rollupAddress)), + new KVArchiverDataStore(await AztecLmdbStore.open(deployL1ContractsValues.l1ContractAddresses.rollupAddress)), ); const walletClient = deployL1ContractsValues.walletClient; diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index be9d3ddad02..fc642ff2a80 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -28,6 +28,7 @@ import { } from '@aztec/circuits.js/factories'; import { createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; +import { AztecLmdbStore } from '@aztec/kv-store'; import { InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { EmptyRollupProver, @@ -44,8 +45,6 @@ import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; import { beforeEach, describe, expect, it } from '@jest/globals'; import * as fs from 'fs'; -import { default as levelup } from 'levelup'; -import memdown from 'memdown'; import { Address, Chain, @@ -133,7 +132,7 @@ describe('L1Publisher integration', () => { publicClient, }); - builderDb = await MerkleTrees.new(levelup((memdown as any)())).then(t => t.asLatest()); + builderDb = await MerkleTrees.new(await AztecLmdbStore.openTmp()).then(t => t.asLatest()); const vks = getVerificationKeys(); const simulator = new RealRollupCircuitSimulator(); const prover = new EmptyRollupProver(); diff --git a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts index db556b0ffe2..d72c2f1e8f2 100644 --- a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts +++ b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts @@ -104,8 +104,7 @@ export async function deployAndInitializeTokenAndBridgeContracts( throw new Error(`Token admin is not ${owner}`); } - // TODO(#3641) - Fix deserialization and compare AztecAddress directly - if ((await bridge.methods.token().view()).inner !== token.address.toBigInt()) { + if (!(await bridge.methods.token().view()).equals(token.address)) { throw new Error(`Bridge token is not ${token.address}`); } diff --git a/yarn-project/foundation/src/abi/decoder.ts b/yarn-project/foundation/src/abi/decoder.ts index ac509d59ba1..e1f4558afa2 100644 --- a/yarn-project/foundation/src/abi/decoder.ts +++ b/yarn-project/foundation/src/abi/decoder.ts @@ -1,10 +1,12 @@ +import { AztecAddress } from '../aztec-address/index.js'; import { Fr } from '../fields/index.js'; import { ABIParameter, type ABIType, ABIVariable, FunctionArtifact } from './abi.js'; +import { isAztecAddressStruct } from './utils.js'; /** * The type of our decoded ABI. */ -export type DecodedReturn = bigint | boolean | DecodedReturn[] | { [key: string]: DecodedReturn }; +export type DecodedReturn = bigint | boolean | AztecAddress | DecodedReturn[] | { [key: string]: DecodedReturn }; /** * Decodes return values from a function call. @@ -38,6 +40,10 @@ class ReturnValuesDecoder { } case 'struct': { const struct: { [key: string]: DecodedReturn } = {}; + if (isAztecAddressStruct(abiType)) { + return new AztecAddress(this.getNextField().toBuffer()); + } + for (const field of abiType.fields) { struct[field.name] = this.decodeReturn(field.type); } diff --git a/yarn-project/foundation/src/abi/selector.ts b/yarn-project/foundation/src/abi/selector.ts index 0a6a0eb661c..760d3bd0931 100644 --- a/yarn-project/foundation/src/abi/selector.ts +++ b/yarn-project/foundation/src/abi/selector.ts @@ -1,5 +1,5 @@ import { fromHex, toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; -import { BufferReader } from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader } from '@aztec/foundation/serialize'; import { randomBytes } from 'crypto'; @@ -106,6 +106,11 @@ export class FunctionSelector extends Selector { return new FunctionSelector(Number(fr.toBigInt())); } + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return FunctionSelector.fromField(reader.readField()); + } + /** * Creates a selector from a signature. * @param signature - Signature to generate the selector for (e.g. "transfer(field,field)"). diff --git a/yarn-project/foundation/src/aztec-address/index.ts b/yarn-project/foundation/src/aztec-address/index.ts index a03257f36de..bf1affc7884 100644 --- a/yarn-project/foundation/src/aztec-address/index.ts +++ b/yarn-project/foundation/src/aztec-address/index.ts @@ -1,4 +1,5 @@ import { Fr } from '../fields/index.js'; +import { FieldReader } from '../serialize/index.js'; /** * AztecAddress represents a 32-byte address in the Aztec Protocol. @@ -19,6 +20,11 @@ export class AztecAddress extends Fr { return new AztecAddress(fr.toBuffer()); } + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return AztecAddress.fromField(reader.readField()); + } + static fromBigInt(value: bigint) { return AztecAddress.fromField(new Fr(value)); } diff --git a/yarn-project/foundation/src/fields/point.ts b/yarn-project/foundation/src/fields/point.ts index cd90e852872..b1135d6e6b5 100644 --- a/yarn-project/foundation/src/fields/point.ts +++ b/yarn-project/foundation/src/fields/point.ts @@ -1,4 +1,4 @@ -import { BufferReader } from '../serialize/buffer_reader.js'; +import { BufferReader, FieldReader } from '../serialize/index.js'; import { Fr } from './fields.js'; /** @@ -66,6 +66,11 @@ export class Point { return [this.x, this.y]; } + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new this(reader.readField(), reader.readField()); + } + /** * Returns the contents of the point as BigInts. * @returns The point as BigInts diff --git a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.test.ts b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.test.ts index 7b720a6e123..c95984230a2 100644 --- a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.test.ts +++ b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.test.ts @@ -1,16 +1,34 @@ import request from 'supertest'; import { TestNote, TestState } from '../fixtures/test_state.js'; -import { JsonRpcServer } from '../server/index.js'; +import { JsonRpcServer, createNamespacedJsonRpcServer } from '../server/index.js'; import { createJsonRpcClient } from './json_rpc_client.js'; it('test an RPC function over client', async () => { const mockFetch = async (host: string, method: string, body: any) => { - const server = new JsonRpcServer(new TestState([new TestNote('a'), new TestNote('b')]), { TestNote }, {}, true); - const result = await request(server.getApp().callback()).post(`/${method}`).send(body); + const server = new JsonRpcServer(new TestState([new TestNote('a'), new TestNote('b')]), { TestNote }, {}); + const result = await request(server.getApp().callback()).post(`/`).send(body); return JSON.parse(result.text); }; - const client = createJsonRpcClient('', { TestNote }, {}, true, mockFetch); + const client = createJsonRpcClient('', { TestNote }, {}, true, false, mockFetch); + const result = await client.addNotes([new TestNote('c')]); + expect(result[0]).toBeInstanceOf(TestNote); + expect(result[1]).toBeInstanceOf(TestNote); + expect(result[2]).toBeInstanceOf(TestNote); + expect(result[0].toString()).toBe('a'); + expect(result[1].toString()).toBe('b'); + expect(result[2].toString()).toBe('c'); +}); + +it('test a namespaced RPC function over client', async () => { + const namespace = 'testService'; + const mockFetch = async (host: string, method: string, body: any) => { + const service = new JsonRpcServer(new TestState([new TestNote('a'), new TestNote('b')]), { TestNote }, {}); + const server = createNamespacedJsonRpcServer([{ [namespace]: service }]); + const result = await request(server.getApp().callback()).post('/').send(body); + return JSON.parse(result.text); + }; + const client = createJsonRpcClient('', { TestNote }, {}, true, namespace, mockFetch); const result = await client.addNotes([new TestNote('c')]); expect(result[0]).toBeInstanceOf(TestNote); expect(result[1]).toBeInstanceOf(TestNote); diff --git a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts index 37713f3da94..c62b20d66f7 100644 --- a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts +++ b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts @@ -88,12 +88,19 @@ export function makeFetch(retries: number[], noRetry: boolean, log?: DebugLogger /** * Creates a Proxy object that delegates over RPC and satisfies RemoteObject. * The server should have ran new JsonRpcServer(). + * @param host - The host URL. + * @param stringClassMap - A map of class names to string representations. + * @param objectClassMap - A map of class names to class constructors. + * @param useApiEndpoints - Whether to use the API endpoints or the default RPC endpoint. + * @param namespaceMethods - String value (or false/empty) to namespace all methods sent to the server. e.g. 'getInfo' -\> 'pxe_getInfo' + * @param fetch - The fetch implementation to use. */ export function createJsonRpcClient( host: string, stringClassMap: StringClassConverterInput, objectClassMap: JsonClassConverterInput, useApiEndpoints: boolean, + namespaceMethods?: string | false, fetch = defaultFetch, ) { const classConverter = new ClassConverter(stringClassMap, objectClassMap); @@ -122,9 +129,13 @@ export function createJsonRpcClient( return new Proxy( {}, { - get: (target, rpcMethod: string) => { - if (['then', 'catch'].includes(rpcMethod)) { - return Reflect.get(target, rpcMethod); + get: (target, method: string) => { + let rpcMethod = method; + if (namespaceMethods) { + rpcMethod = `${namespaceMethods}_${method}`; + } + if (['then', 'catch'].includes(method)) { + return Reflect.get(target, method); } return (...params: any[]) => { debug(format(`JsonRpcClient.constructor`, 'proxy', rpcMethod, '<-', params)); diff --git a/yarn-project/foundation/src/json-rpc/server/index.ts b/yarn-project/foundation/src/json-rpc/server/index.ts index a20b679993b..a0f5caf72ca 100644 --- a/yarn-project/foundation/src/json-rpc/server/index.ts +++ b/yarn-project/foundation/src/json-rpc/server/index.ts @@ -1,2 +1,2 @@ -export { JsonRpcServer, createStatusRouter, startHttpRpcServer } from './json_rpc_server.js'; +export * from './json_rpc_server.js'; export { JsonProxy } from './json_proxy.js'; diff --git a/yarn-project/foundation/src/json-rpc/server/json_proxy.ts b/yarn-project/foundation/src/json-rpc/server/json_proxy.ts index e7630d7f5e8..b46a1983ada 100644 --- a/yarn-project/foundation/src/json-rpc/server/json_proxy.ts +++ b/yarn-project/foundation/src/json-rpc/server/json_proxy.ts @@ -7,6 +7,16 @@ import { assert, hasOwnProperty } from '../js_utils.js'; const debug = createDebugLogger('json-rpc:json_proxy'); +/** + * A map of class names to class constructors. + */ +export type ClassMaps = { + /** The String class map */ + stringClassMap: StringClassConverterInput; + /** The object class map */ + objectClassMap: JsonClassConverterInput; +}; + /** * Handles conversion of objects over the write. * Delegates to a ClassConverter object. @@ -15,8 +25,8 @@ export class JsonProxy { classConverter: ClassConverter; constructor( private handler: object, - stringClassMap: StringClassConverterInput, - objectClassMap: JsonClassConverterInput, + private stringClassMap: StringClassConverterInput, + private objectClassMap: JsonClassConverterInput, ) { this.classConverter = new ClassConverter(stringClassMap, objectClassMap); } @@ -24,19 +34,26 @@ export class JsonProxy { * Call an RPC method. * @param methodName - The RPC method. * @param jsonParams - The RPG parameters. + * @param skipConversion - Whether to skip conversion of the parameters. * @returns The remote result. */ - public async call(methodName: string, jsonParams: any[] = []) { + public async call(methodName: string, jsonParams: any[] = [], skipConversion = false) { debug(format(`JsonProxy:call`, methodName, jsonParams)); // Get access to our class members const proto = Object.getPrototypeOf(this.handler); assert(hasOwnProperty(proto, methodName), `JsonProxy: Method ${methodName} not found!`); - assert(Array.isArray(jsonParams), 'JsonProxy: Params not an array!'); + assert(Array.isArray(jsonParams), `JsonProxy: ${methodName} params not an array: ${jsonParams}`); // convert the params from json representation to classes - const convertedParams = jsonParams.map(param => convertFromJsonObj(this.classConverter, param)); + let convertedParams = jsonParams; + if (!skipConversion) { + convertedParams = jsonParams.map(param => convertFromJsonObj(this.classConverter, param)); + } debug(format('JsonProxy:call', methodName, '<-', convertedParams)); const rawRet = await (this.handler as any)[methodName](...convertedParams); - const ret = convertToJsonObj(this.classConverter, rawRet); + let ret = rawRet; + if (!skipConversion) { + ret = convertToJsonObj(this.classConverter, rawRet); + } debug(format('JsonProxy:call', methodName, '->', ret)); return ret; } diff --git a/yarn-project/foundation/src/json-rpc/server/json_rpc_server.test.ts b/yarn-project/foundation/src/json-rpc/server/json_rpc_server.test.ts index c5272c2b74c..9815055346d 100644 --- a/yarn-project/foundation/src/json-rpc/server/json_rpc_server.test.ts +++ b/yarn-project/foundation/src/json-rpc/server/json_rpc_server.test.ts @@ -4,19 +4,20 @@ import { TestNote, TestState } from '../fixtures/test_state.js'; import { JsonRpcServer } from './json_rpc_server.js'; it('test an RPC function with a primitive parameter', async () => { - const server = new JsonRpcServer(new TestState([new TestNote('a'), new TestNote('b')]), { TestNote }, {}, true); + const server = new JsonRpcServer(new TestState([new TestNote('a'), new TestNote('b')]), { TestNote }, {}); const response = await request(server.getApp().callback()) - .post('/getNote') - .send({ params: [0] }); + .post('/') + .send({ method: 'getNote', params: [0] }); expect(response.status).toBe(200); expect(response.text).toBe(JSON.stringify({ result: { type: 'TestNote', data: 'a' } })); }); it('test an RPC function with an array of classes', async () => { - const server = new JsonRpcServer(new TestState([]), { TestNote }, {}, true); + const server = new JsonRpcServer(new TestState([]), { TestNote }, {}); const response = await request(server.getApp().callback()) - .post('/addNotes') + .post('/') .send({ + method: 'addNotes', params: [[{ data: 'a' }, { data: 'b' }, { data: 'c' }]], }); expect(response.status).toBe(200); @@ -24,7 +25,7 @@ it('test an RPC function with an array of classes', async () => { }); it('test invalid JSON', async () => { - const server = new JsonRpcServer(new TestState([]), { TestNote }, {}, false); + const server = new JsonRpcServer(new TestState([]), { TestNote }, {}); const response = await request(server.getApp().callback()).post('/').send('{'); expect(response.status).toBe(400); expect(response.body).toEqual({ @@ -35,7 +36,7 @@ it('test invalid JSON', async () => { }); it('invalid method', async () => { - const server = new JsonRpcServer(new TestState([]), { TestNote }, {}, false); + const server = new JsonRpcServer(new TestState([]), { TestNote }, {}); const response = await request(server.getApp().callback()).post('/').send({ jsonrpc: '2.0', method: 'invalid', diff --git a/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts b/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts index ea1bd7e2d05..08e0533aff4 100644 --- a/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts +++ b/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts @@ -8,20 +8,23 @@ import Router from 'koa-router'; import { createDebugLogger } from '../../log/index.js'; import { JsonClassConverterInput, StringClassConverterInput } from '../class_converter.js'; import { convertBigintsInObj } from '../convert.js'; -import { JsonProxy } from './json_proxy.js'; +import { ClassMaps, JsonProxy } from './json_proxy.js'; /** * JsonRpcServer. * Minimal, dev-friendly mechanism to create a server from an object. */ export class JsonRpcServer { - proxy: JsonProxy; + /** + * The proxy object. + */ + public proxy: JsonProxy; constructor( private handler: object, - stringClassMap: StringClassConverterInput, - objectClassMap: JsonClassConverterInput, - private createApi: boolean, - private disallowedMethods: string[] = [], + private stringClassMap: StringClassConverterInput, + private objectClassMap: JsonClassConverterInput, + /** List of methods to disallow from calling remotely */ + public readonly disallowedMethods: string[] = [], private log = createDebugLogger('aztec:foundation:json-rpc:server'), ) { this.proxy = new JsonProxy(handler, stringClassMap, objectClassMap); @@ -90,90 +93,45 @@ export class JsonRpcServer { private getRouter(prefix: string) { const router = new Router({ prefix }); const proto = Object.getPrototypeOf(this.handler); - // Find all our endpoints from the handler methods - - if (this.createApi) { - // "API mode" where an endpoint is created for each method - for (const method of Object.getOwnPropertyNames(proto)) { - // Ignore if not a function or function is not allowed - if ( - method === 'constructor' || - typeof proto[method] !== 'function' || - this.disallowedMethods.includes(method) - ) { - continue; - } - router.post(`/${method}`, async (ctx: Koa.Context) => { - const { params = [], jsonrpc, id } = ctx.request.body as any; - try { - const result = await this.proxy.call(method, params); - ctx.body = { - jsonrpc, - id, - result: convertBigintsInObj(result), - }; - ctx.status = 200; - } catch (err: any) { - // Propagate the error message to the client. Plenty of the errors are expected to occur (e.g. adding - // a duplicate recipient) so this is necessary. - ctx.status = 400; - ctx.body = { - jsonrpc, - id, - error: { - // TODO assign error codes - https://github.com/AztecProtocol/aztec-packages/issues/2633 - code: -32000, - message: err.message, - }, - }; - } - }); - } - } else { - // "JSON RPC mode" where a single endpoint is used and the method is given in the request body - router.post('/', async (ctx: Koa.Context) => { - const { params = [], jsonrpc, id, method } = ctx.request.body as any; - // Ignore if not a function - if ( - method === 'constructor' || - typeof proto[method] !== 'function' || - this.disallowedMethods.includes(method) - ) { + // "JSON RPC mode" where a single endpoint is used and the method is given in the request body + router.post('/', async (ctx: Koa.Context) => { + const { params = [], jsonrpc, id, method } = ctx.request.body as any; + // Ignore if not a function + if (method === 'constructor' || typeof proto[method] !== 'function' || this.disallowedMethods.includes(method)) { + ctx.status = 400; + ctx.body = { + jsonrpc, + id, + error: { + code: -32601, + message: `Method not found: ${method}`, + }, + }; + } else { + try { + const result = await this.proxy.call(method, params); + ctx.body = { + jsonrpc, + id, + result: convertBigintsInObj(result), + }; + ctx.status = 200; + } catch (err: any) { + // Propagate the error message to the client. Plenty of the errors are expected to occur (e.g. adding + // a duplicate recipient) so this is necessary. ctx.status = 400; ctx.body = { jsonrpc, id, error: { - code: -32601, - message: `Method not found: ${method}`, + // TODO assign error codes - https://github.com/AztecProtocol/aztec-packages/issues/2633 + code: -32000, + message: err.message, }, }; - } else { - try { - const result = await this.proxy.call(method, params); - ctx.body = { - jsonrpc, - id, - result: convertBigintsInObj(result), - }; - ctx.status = 200; - } catch (err: any) { - // Propagate the error message to the client. Plenty of the errors are expected to occur (e.g. adding - // a duplicate recipient) so this is necessary. - ctx.status = 400; - ctx.body = { - jsonrpc, - id, - error: { - // TODO assign error codes - https://github.com/AztecProtocol/aztec-packages/issues/2633 - code: -32000, - message: err.message, - }, - }; - } } - }); - } + } + }); return router; } @@ -187,6 +145,33 @@ export class JsonRpcServer { const httpServer = http.createServer(this.getApp(prefix).callback()); httpServer.listen(port); } + + /** + * Get a list of methods. + * @returns A list of methods. + */ + public getMethods(): string[] { + return Object.getOwnPropertyNames(Object.getPrototypeOf(this.handler)); + } + + /** + * Gets the class maps that were used to create the proxy. + * @returns The string & object class maps. + */ + public getClassMaps(): ClassMaps { + return { stringClassMap: this.stringClassMap, objectClassMap: this.objectClassMap }; + } + + /** + * Call an RPC method. + * @param methodName - The RPC method. + * @param jsonParams - The RPG parameters. + * @param skipConversion - Whether to skip conversion of the parameters. + * @returns The remote result. + */ + public async call(methodName: string, jsonParams: any[] = [], skipConversion: boolean) { + return await this.proxy.call(methodName, jsonParams, skipConversion); + } } /** @@ -210,16 +195,75 @@ export function createStatusRouter(apiPrefix = '') { * @returns A running http server. */ export function startHttpRpcServer( + name: string, instance: T, jsonRpcFactoryFunc: (instance: T) => JsonRpcServer, port: string | number, ): http.Server { const rpcServer = jsonRpcFactoryFunc(instance); - const app = rpcServer.getApp(); + const namespacedServer = createNamespacedJsonRpcServer([{ [name]: rpcServer }]); + + const app = namespacedServer.getApp(); const httpServer = http.createServer(app.callback()); httpServer.listen(port); return httpServer; } +/** + * List of namespace to server instance. + */ +export type ServerList = { + /** name of the service to be used for namespacing */ + [name: string]: JsonRpcServer; +}[]; + +/** + * Creates a single JsonRpcServer from multiple servers. + * @param servers - List of servers to be combined into a single server, passed as ServerList. + * @returns A single JsonRpcServer with namespaced methods. + */ +export function createNamespacedJsonRpcServer( + servers: ServerList, + log = createDebugLogger('aztec:foundation:json-rpc:multi-server'), +): JsonRpcServer { + const handler = {} as any; + const disallowedMethods: string[] = []; + const classMapsArr: ClassMaps[] = []; + + for (const serverEntry of servers) { + const [namespace, server] = Object.entries(serverEntry)[0]; + const serverMethods = server.getMethods(); + + for (const method of serverMethods) { + const namespacedMethod = `${namespace}_${method}`; + + handler[namespacedMethod] = (...args: any[]) => { + return server.call(method, args, true); + }; + } + + // get the combined disallowed methods from all servers. + disallowedMethods.push(...server.disallowedMethods.map(method => `${namespace}_${method}`)); + // get the combined classmaps from all servers. + const classMap = server.getClassMaps(); + classMapsArr.push({ + stringClassMap: classMap.stringClassMap, + objectClassMap: classMap.objectClassMap, + }); + } + + // Get the combined stringClassMap & objectClassMap from all servers + const classMaps = classMapsArr.reduce( + (acc, curr) => { + return { + stringClassMap: { ...acc.stringClassMap, ...curr.stringClassMap }, + objectClassMap: { ...acc.objectClassMap, ...curr.objectClassMap }, + }; + }, + { stringClassMap: {}, objectClassMap: {} } as ClassMaps, + ); + + return new JsonRpcServer(Object.create(handler), classMaps.stringClassMap, classMaps.objectClassMap, [], log); +} diff --git a/yarn-project/foundation/src/serialize/buffer_reader.ts b/yarn-project/foundation/src/serialize/buffer_reader.ts index 903abcab077..d11efff3cb5 100644 --- a/yarn-project/foundation/src/serialize/buffer_reader.ts +++ b/yarn-project/foundation/src/serialize/buffer_reader.ts @@ -54,6 +54,16 @@ export class BufferReader { return this.buffer.readUint32BE(this.index - 4); } + /** + * Reads `count` 32-bit unsigned integers from the buffer at the current index position. + * @param count - The number of 32-bit unsigned integers to read. + * @returns An array of 32-bit unsigned integers. + */ + public readNumbers(count: N): Tuple { + const result = Array.from({ length: count }, () => this.readNumber()); + return result as Tuple; + } + /** * Reads a 16-bit unsigned integer from the buffer at the current index position. * Updates the index position by 2 bytes after reading the number. diff --git a/yarn-project/foundation/src/serialize/field_reader.test.ts b/yarn-project/foundation/src/serialize/field_reader.test.ts new file mode 100644 index 00000000000..7a242bae1b0 --- /dev/null +++ b/yarn-project/foundation/src/serialize/field_reader.test.ts @@ -0,0 +1,93 @@ +import { Fq, Fr } from '../fields/fields.js'; +import { FieldReader } from './field_reader.js'; + +const FIELDS = [new Fr(0), new Fr(1), new Fr(23), new Fr(45), new Fr(6789)]; + +class Something { + constructor(public id: Fr, public value: number) {} + + static fromFields(reader: FieldReader): Something { + return new Something(reader.readField(), reader.readU32()); + } +} + +describe('field reader', () => { + let reader: FieldReader; + + beforeEach(() => { + reader = new FieldReader(FIELDS); + }); + + describe('readFr', () => { + it('should read Fr', () => { + FIELDS.forEach(fr => { + expect(reader.readField()).toEqual(fr); + }); + + expect(() => reader.readField()).toThrow('Not enough fields to be consumed.'); + }); + }); + + describe('readFq', () => { + it('should get Fq from buffer', () => { + expect(reader.readFq()).toEqual(Fq.fromHighLow(new Fr(0), new Fr(1))); + expect(reader.readFq()).toEqual(Fq.fromHighLow(new Fr(23), new Fr(45))); + + expect(() => reader.readFq()).toThrow('Not enough fields to be consumed.'); + }); + }); + + describe('readBoolean', () => { + it('should read false when 0 and true when 1, throw otherwise', () => { + expect(reader.readBoolean()).toBe(false); + expect(reader.readBoolean()).toBe(true); + + expect(() => reader.readBoolean()).toThrow('Field is not a boolean'); + }); + }); + + describe('readU32', () => { + it('should return number', () => { + expect(reader.readU32()).toBe(0); + expect(reader.readU32()).toBe(1); + expect(reader.readU32()).toBe(23); + expect(reader.readU32()).toBe(45); + expect(reader.readU32()).toBe(6789); + }); + + it('should throw if reading a value larger than u32', () => { + const reader = new FieldReader([new Fr(2n ** 32n)]); + expect(() => reader.readU32()).toThrow('Field is not a u32.'); + }); + }); + + describe('readFieldArray', () => { + it('should read an array of fields', () => { + expect(reader.readFieldArray(3)).toEqual([new Fr(0), new Fr(1), new Fr(23)]); + }); + + it('should throw if reading more fields than in the reader', () => { + expect(() => reader.readFieldArray(FIELDS.length + 1)).toThrow('Not enough fields to be consumed.'); + }); + }); + + describe('readArray', () => { + it('should read array of custom type', () => { + const things = reader.readArray(2, Something); + expect(things).toEqual([new Something(new Fr(0), 1), new Something(new Fr(23), 45)]); + }); + + it('should throw if reading more fields than in the reader', () => { + expect(() => reader.readArray(3, Something)).toThrow('Not enough fields to be consumed.'); + }); + }); + + describe('readObject', () => { + it('should read object from buffer', () => { + expect(reader.readObject(Something)).toEqual(new Something(new Fr(0), 1)); + expect(reader.readObject(Something)).toEqual(new Something(new Fr(23), 45)); + + expect(() => reader.readObject(Something)).toThrow('Not enough fields to be consumed.'); + }); + }); +}); diff --git a/yarn-project/foundation/src/serialize/field_reader.ts b/yarn-project/foundation/src/serialize/field_reader.ts new file mode 100644 index 00000000000..be3a06e72dd --- /dev/null +++ b/yarn-project/foundation/src/serialize/field_reader.ts @@ -0,0 +1,143 @@ +import { Fq, Fr } from '../fields/fields.js'; +import { Tuple } from './types.js'; + +/** + * The FieldReader class provides a utility for reading various data types from a field array. + * + * Usage: + * Create a new instance of FieldReader with an array of fields and an optional offset. + * Use the provided methods to read desired data types from the field array. + * The reading methods automatically advance the internal index. + */ +export class FieldReader { + private index: number; + private length: number; + constructor(private fields: Fr[], offset = 0) { + this.index = offset; + this.length = fields.length; + if (offset >= this.length) { + throw new Error('Offset out of bounds.'); + } + } + + /** + * Creates a FieldReader instance from either a field array or an existing FieldReader. + * + * @param fields - A field array or FieldReader to initialize the FieldReader. + * @returns An instance of FieldReader. + */ + public static asReader(fields: Fr[] | FieldReader): FieldReader { + if (fields instanceof FieldReader) { + return fields; + } + + return new FieldReader(fields); + } + + /** + * Reads a single field from the array. + * + * @returns A field. + */ + public readField(): Fr { + if (this.index === this.length) { + throw new Error('Not enough fields to be consumed.'); + } + return this.fields[this.index++]; + } + + /** + * Reads a Fq from the array. + * + * @returns An Fq. + */ + public readFq(): Fq { + return Fq.fromHighLow(this.readField(), this.readField()); + } + + /** + * Reads and returns the next boolean value from the field array. + * Advances the internal index by 1, treating the field at the current index as a boolean value. + * Returns true if the field is non-zero, false otherwise. + * Throw if the value is not 0 or 1. + * + * @returns A boolean value representing the field at the current index. + */ + public readBoolean(): boolean { + const field = this.readField(); + const value = field.toBigInt(); + if (value > 1n) { + throw new Error('Field is not a boolean.'); + } + return value == 1n; + } + + /** + * Reads a 32-bit unsigned integer from the field array at the current index position. + * Updates the index position by 1 after reading the number. + * Throw if the value is greater than 2 ** 32. + * + * @returns The read 32-bit unsigned integer value. + */ + public readU32(): number { + const field = this.readField(); + const value = field.toBigInt(); + if (value >= 1n << 32n) { + throw new Error('Field is not a u32.'); + } + return Number(value); + } + + /** + * Read an array of a fixed size field array. + * + * @param size - The fixed number of fields in the array. + * @returns An array of fields. + */ + public readFieldArray(size: N): Tuple { + const result: Fr[] = []; + for (let i = 0; i < size; ++i) { + result.push(this.readField()); + } + return result as Tuple; + } + + /** + * Read an array of a fixed size with elements of type T from the field array. + * The 'itemDeserializer' object should have a 'fromFields' method that takes a FieldReader instance as input, + * and returns an instance of the desired deserialized data type T. + * This method will call the 'fromFields' method for each element in the array and return the resulting array. + * + * @param size - The fixed number of elements in the array. + * @param itemDeserializer - An object with a 'fromFields' method to deserialize individual elements of type T. + * @returns An array of instances of type T. + */ + public readArray( + size: N, + itemDeserializer: { + /** + * A function for deserializing data from a FieldReader instance. + */ + fromFields: (reader: FieldReader) => T; + }, + ): Tuple { + const result = Array.from({ length: size }, () => itemDeserializer.fromFields(this)); + return result as Tuple; + } + + /** + * Reads a serialized object from a field array and returns the deserialized object using the given deserializer. + * + * @typeparam T - The type of the deserialized object. + * @param deserializer - An object with a 'fromFields' method that takes a FieldReader instance and returns an instance of the deserialized object. + * @returns The deserialized object of type T. + */ + public readObject(deserializer: { + /** + * A method that takes a FieldReader instance and returns an instance of the deserialized data type. + */ + fromFields: (reader: FieldReader) => T; + }): T { + return deserializer.fromFields(this); + } +} diff --git a/yarn-project/foundation/src/serialize/index.ts b/yarn-project/foundation/src/serialize/index.ts index 669ab25f8e4..875d37f4410 100644 --- a/yarn-project/foundation/src/serialize/index.ts +++ b/yarn-project/foundation/src/serialize/index.ts @@ -1,4 +1,5 @@ export * from './free_funcs.js'; export * from './buffer_reader.js'; +export * from './field_reader.js'; export * from './types.js'; export * from './serialize.js'; diff --git a/yarn-project/key-store/src/test_key_store.ts b/yarn-project/key-store/src/test_key_store.ts index f0af31ee6da..f0bab98c51d 100644 --- a/yarn-project/key-store/src/test_key_store.ts +++ b/yarn-project/key-store/src/test_key_store.ts @@ -21,7 +21,7 @@ export class TestKeyStore implements KeyStore { #keys: AztecMap; constructor(private curve: Grumpkin, database: AztecKVStore) { - this.#keys = database.createMap('key_store'); + this.#keys = database.openMap('key_store'); } public async addAccount(privKey: GrumpkinPrivateKey): Promise { @@ -51,6 +51,20 @@ export class TestKeyStore implements KeyStore { return computeNullifierSecretKey(privateKey); } + public async getNullifierSecretKeyFromPublicKey(nullifierPubKey: PublicKey) { + const accounts = await this.getAccounts(); + for (let i = 0; i < accounts.length; ++i) { + const accountPublicKey = accounts[i]; + const privateKey = await this.getAccountPrivateKey(accountPublicKey); + const secretKey = computeNullifierSecretKey(privateKey); + const publicKey = derivePublicKey(secretKey); + if (publicKey.equals(nullifierPubKey)) { + return secretKey; + } + } + throw new Error('Unknown nullifier public key.'); + } + public async getNullifierPublicKey(pubKey: PublicKey) { const secretKey = await this.getNullifierSecretKey(pubKey); return derivePublicKey(secretKey); @@ -73,7 +87,7 @@ export class TestKeyStore implements KeyStore { const privKey = this.#keys.get(pubKey.toString()); if (!privKey) { throw new Error( - 'Unknown account.\nSee docs for context: https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#could-not-process-note-because-of-error-unknown-account-skipping-note', + 'Unknown account.\nSee docs for context: https://docs.aztec.network/developers/debugging/aztecnr-errors#could-not-process-note-because-of-error-unknown-account-skipping-note', ); } return ConstantKeyPair.fromPrivateKey(this.curve, GrumpkinScalar.fromBuffer(privKey)); diff --git a/yarn-project/kv-store/package.json b/yarn-project/kv-store/package.json index 8aea043378d..4c440901969 100644 --- a/yarn-project/kv-store/package.json +++ b/yarn-project/kv-store/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@aztec/foundation": "workspace:^", - "lmdb": "^2.9.1" + "lmdb": "^2.9.2" }, "devDependencies": { "@jest/globals": "^29.5.0", diff --git a/yarn-project/kv-store/src/interfaces/store.ts b/yarn-project/kv-store/src/interfaces/store.ts index 73a2901387c..2e2777f0e8a 100644 --- a/yarn-project/kv-store/src/interfaces/store.ts +++ b/yarn-project/kv-store/src/interfaces/store.ts @@ -11,34 +11,34 @@ export interface AztecKVStore { * @param name - The name of the map * @returns The map */ - createMap(name: string): AztecMap; + openMap(name: string): AztecMap; /** * Creates a new multi-map. * @param name - The name of the multi-map * @returns The multi-map */ - createMultiMap(name: string): AztecMultiMap; + openMultiMap(name: string): AztecMultiMap; /** * Creates a new array. * @param name - The name of the array * @returns The array */ - createArray(name: string): AztecArray; + openArray(name: string): AztecArray; /** * Creates a new singleton. * @param name - The name of the singleton * @returns The singleton */ - createSingleton(name: string): AztecSingleton; + openSingleton(name: string): AztecSingleton; /** * Creates a new count map. * @param name - name of the counter */ - createCounter(name: string): AztecCounter; + openCounter(name: string): AztecCounter; /** * Starts a transaction. All calls to read/write data while in a transaction are queued and executed atomically. diff --git a/yarn-project/kv-store/src/lmdb/store.ts b/yarn-project/kv-store/src/lmdb/store.ts index 8c3cebd0737..bbd866efe8c 100644 --- a/yarn-project/kv-store/src/lmdb/store.ts +++ b/yarn-project/kv-store/src/lmdb/store.ts @@ -39,7 +39,7 @@ export class AztecLmdbStore implements AztecKVStore { dupSort: true, }); - this.#rollupAddress = this.createSingleton('rollupAddress'); + this.#rollupAddress = this.openSingleton('rollupAddress'); } /** @@ -55,7 +55,7 @@ export class AztecLmdbStore implements AztecKVStore { * @param log - A logger to use. Optional * @returns The store */ - static async create( + static async open( rollupAddress: EthAddress, path?: string, log = createDebugLogger('aztec:kv-store:lmdb'), @@ -72,12 +72,16 @@ export class AztecLmdbStore implements AztecKVStore { return db; } + static openTmp(): Promise { + return AztecLmdbStore.open(EthAddress.random()); + } + /** * Creates a new AztecMap in the store. * @param name - Name of the map * @returns A new AztecMap */ - createMap(name: string): AztecMap { + openMap(name: string): AztecMap { return new LmdbAztecMap(this.#data, name); } @@ -86,11 +90,11 @@ export class AztecLmdbStore implements AztecKVStore { * @param name - Name of the map * @returns A new AztecMultiMap */ - createMultiMap(name: string): AztecMultiMap { + openMultiMap(name: string): AztecMultiMap { return new LmdbAztecMap(this.#multiMapData, name); } - createCounter>(name: string): AztecCounter { + openCounter>(name: string): AztecCounter { return new LmdbAztecCounter(this.#data, name); } @@ -99,7 +103,7 @@ export class AztecLmdbStore implements AztecKVStore { * @param name - Name of the array * @returns A new AztecArray */ - createArray(name: string): AztecArray { + openArray(name: string): AztecArray { return new LmdbAztecArray(this.#data, name); } @@ -108,7 +112,7 @@ export class AztecLmdbStore implements AztecKVStore { * @param name - Name of the singleton * @returns A new AztecSingleton */ - createSingleton(name: string): AztecSingleton { + openSingleton(name: string): AztecSingleton { return new LmdbAztecSingleton(this.#data, name); } diff --git a/yarn-project/merkle-tree/package.json b/yarn-project/merkle-tree/package.json index d9c347ed115..75bb7b0e2bf 100644 --- a/yarn-project/merkle-tree/package.json +++ b/yarn-project/merkle-tree/package.json @@ -34,9 +34,8 @@ "dependencies": { "@aztec/circuit-types": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/kv-store": "workspace:^", "@aztec/types": "workspace:^", - "levelup": "^5.1.1", - "memdown": "^6.1.1", "sha256": "^0.2.0", "tslib": "^2.4.0" }, @@ -44,8 +43,6 @@ "@aztec/circuits.js": "workspace:^", "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", - "@types/levelup": "^5.1.2", - "@types/memdown": "^3.0.1", "@types/node": "^18.15.3", "@types/sha256": "^0.2.0", "jest": "^29.5.0", diff --git a/yarn-project/merkle-tree/src/interfaces/indexed_tree.ts b/yarn-project/merkle-tree/src/interfaces/indexed_tree.ts index 5e5531afacf..651f734f09e 100644 --- a/yarn-project/merkle-tree/src/interfaces/indexed_tree.ts +++ b/yarn-project/merkle-tree/src/interfaces/indexed_tree.ts @@ -1,8 +1,35 @@ -import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; +import { IndexedTreeLeaf, IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { SiblingPath } from '@aztec/types/membership'; import { AppendOnlyTree } from './append_only_tree.js'; +/** + * Factory for creating leaf preimages. + */ +export interface PreimageFactory { + /** + * Creates a new preimage from a leaf. + * @param leaf - Leaf to create a preimage from. + * @param nextKey - Next key of the leaf. + * @param nextIndex - Next index of the leaf. + */ + fromLeaf(leaf: IndexedTreeLeaf, nextKey: bigint, nextIndex: bigint): IndexedTreeLeafPreimage; + /** + * Creates a new preimage from a buffer. + * @param buffer - Buffer to create a preimage from. + */ + fromBuffer(buffer: Buffer): IndexedTreeLeafPreimage; + /** + * Creates an empty preimage. + */ + empty(): IndexedTreeLeafPreimage; + /** + * Creates a copy of a preimage. + * @param preimage - Preimage to be cloned. + */ + clone(preimage: IndexedTreeLeafPreimage): IndexedTreeLeafPreimage; +} + /** * All of the data to be return during batch insertion. */ @@ -56,7 +83,7 @@ export interface IndexedTree extends AppendOnlyTree { findIndexOfPreviousKey( newValue: bigint, includeUncommitted: boolean, - ): Promise< + ): | { /** * The index of the found leaf. @@ -67,8 +94,7 @@ export interface IndexedTree extends AppendOnlyTree { */ alreadyPresent: boolean; } - | undefined - >; + | undefined; /** * Gets the latest LeafPreimage copy. @@ -76,7 +102,7 @@ export interface IndexedTree extends AppendOnlyTree { * @param includeUncommitted - If true, the uncommitted changes are included in the search. * @returns A copy of the leaf preimage at the given index or undefined if the leaf was not found. */ - getLatestLeafPreimageCopy(index: bigint, includeUncommitted: boolean): Promise; + getLatestLeafPreimageCopy(index: bigint, includeUncommitted: boolean): IndexedTreeLeafPreimage | undefined; /** * Batch insert multiple leaves into the tree. diff --git a/yarn-project/merkle-tree/src/interfaces/merkle_tree.ts b/yarn-project/merkle-tree/src/interfaces/merkle_tree.ts index 257e5d79761..209656f885d 100644 --- a/yarn-project/merkle-tree/src/interfaces/merkle_tree.ts +++ b/yarn-project/merkle-tree/src/interfaces/merkle_tree.ts @@ -48,7 +48,7 @@ export interface MerkleTree extends SiblingPathSource { * @param index - The index of the leaf value to be returned. * @param includeUncommitted - Set to true to include uncommitted updates in the data set. */ - getLeafValue(index: bigint, includeUncommitted: boolean): Promise; + getLeafValue(index: bigint, includeUncommitted: boolean): Buffer | undefined; /** * Returns the index of a leaf given its value, or undefined if no leaf with that value is found. @@ -56,5 +56,5 @@ export interface MerkleTree extends SiblingPathSource { * @param includeUncommitted - Indicates whether to include uncommitted data. * @returns The index of the first leaf found with a given value (undefined if not found). */ - findLeafIndex(leaf: Buffer, includeUncommitted: boolean): Promise; + findLeafIndex(leaf: Buffer, includeUncommitted: boolean): bigint | undefined; } diff --git a/yarn-project/merkle-tree/src/load_tree.ts b/yarn-project/merkle-tree/src/load_tree.ts index 4d5bf606bb0..a4bf1e8853a 100644 --- a/yarn-project/merkle-tree/src/load_tree.ts +++ b/yarn-project/merkle-tree/src/load_tree.ts @@ -1,8 +1,7 @@ +import { AztecKVStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; -import { LevelUp } from 'levelup'; - -import { TreeBase, decodeMeta } from './tree_base.js'; +import { TreeBase, getTreeMeta } from './tree_base.js'; /** * Creates a new tree and sets its root, depth and size based on the meta data which are associated with the name. @@ -12,15 +11,13 @@ import { TreeBase, decodeMeta } from './tree_base.js'; * @param name - Name of the tree. * @returns The newly created tree. */ -export async function loadTree( - c: new (db: LevelUp, hasher: Hasher, name: string, depth: number, size: bigint, root: Buffer) => T, - db: LevelUp, +export function loadTree( + c: new (store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint, root: Buffer) => T, + store: AztecKVStore, hasher: Hasher, name: string, ): Promise { - const meta: Buffer = await db.get(name); - const { root, depth, size } = decodeMeta(meta); - - const tree = new c(db, hasher, name, depth, size, root); - return tree; + const { root, depth, size } = getTreeMeta(store, name); + const tree = new c(store, hasher, name, depth, size, root); + return Promise.resolve(tree); } diff --git a/yarn-project/merkle-tree/src/new_tree.ts b/yarn-project/merkle-tree/src/new_tree.ts index 45e01ded402..5c354e21851 100644 --- a/yarn-project/merkle-tree/src/new_tree.ts +++ b/yarn-project/merkle-tree/src/new_tree.ts @@ -1,7 +1,6 @@ +import { AztecKVStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; -import { LevelUp } from 'levelup'; - import { TreeBase } from './tree_base.js'; /** @@ -15,14 +14,14 @@ import { TreeBase } from './tree_base.js'; * @returns The newly created tree. */ export async function newTree( - c: new (db: LevelUp, hasher: Hasher, name: string, depth: number, size: bigint) => T, - db: LevelUp, + c: new (store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint) => T, + store: AztecKVStore, hasher: Hasher, name: string, depth: number, prefilledSize = 1, ): Promise { - const tree = new c(db, hasher, name, depth, 0n); + const tree = new c(store, hasher, name, depth, 0n); await tree.init(prefilledSize); return tree; } diff --git a/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts b/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts index b66eb2af22b..52ebdec437d 100644 --- a/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts +++ b/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts @@ -1,17 +1,16 @@ -import levelup, { LevelUp } from 'levelup'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Pedersen, StandardTree, newTree } from '../index.js'; -import { createMemDown } from '../test/utils/create_mem_down.js'; import { AppendOnlySnapshotBuilder } from './append_only_snapshot.js'; import { describeSnapshotBuilderTestSuite } from './snapshot_builder_test_suite.js'; describe('AppendOnlySnapshot', () => { let tree: StandardTree; let snapshotBuilder: AppendOnlySnapshotBuilder; - let db: LevelUp; + let db: AztecKVStore; beforeEach(async () => { - db = levelup(createMemDown()); + db = await AztecLmdbStore.openTmp(); const hasher = new Pedersen(); tree = await newTree(StandardTree, db, hasher, 'test', 4); snapshotBuilder = new AppendOnlySnapshotBuilder(db, tree, hasher); diff --git a/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.ts b/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.ts index 113a01d2bee..06d6e4b3194 100644 --- a/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.ts +++ b/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.ts @@ -1,23 +1,26 @@ +import { AztecKVStore, AztecMap } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; -import { LevelUp } from 'levelup'; - import { AppendOnlyTree } from '../interfaces/append_only_tree.js'; import { TreeBase } from '../tree_base.js'; import { TreeSnapshot, TreeSnapshotBuilder } from './snapshot_builder.js'; // stores the last block that modified this node -const nodeModifiedAtBlockKey = (treeName: string, level: number, index: bigint) => - `snapshot:node:${treeName}:${level}:${index}:block`; +const nodeModifiedAtBlockKey = (level: number, index: bigint) => `node:${level}:${index}:modifiedAtBlock`; // stores the value of the node at the above block -const historicalNodeKey = (treeName: string, level: number, index: bigint) => - `snapshot:node:${treeName}:${level}:${index}:value`; +const historicalNodeKey = (level: number, index: bigint) => `node:${level}:${index}:value`; -// metadata for a snapshot -const snapshotRootKey = (treeName: string, block: number) => `snapshot:root:${treeName}:${block}`; -const snapshotNumLeavesKey = (treeName: string, block: number) => `snapshot:numLeaves:${treeName}:${block}`; +/** + * Metadata for a snapshot, per block + */ +type SnapshotMetadata = { + /** The tree root at the time */ + root: Buffer; + /** The number of filled leaves */ + numLeaves: bigint; +}; /** * A more space-efficient way of storing snapshots of AppendOnlyTrees that trades space need for slower @@ -35,91 +38,110 @@ const snapshotNumLeavesKey = (treeName: string, block: number) => `snapshot:numL * Worst case: O(H) database reads + O(H) hashes */ export class AppendOnlySnapshotBuilder implements TreeSnapshotBuilder { - constructor(private db: LevelUp, private tree: TreeBase & AppendOnlyTree, private hasher: Hasher) {} - async getSnapshot(block: number): Promise { - const meta = await this.#getSnapshotMeta(block); + #nodeValue: AztecMap, Buffer>; + #nodeLastModifiedByBlock: AztecMap, number>; + #snapshotMetadata: AztecMap; + + constructor(private db: AztecKVStore, private tree: TreeBase & AppendOnlyTree, private hasher: Hasher) { + const treeName = tree.getName(); + this.#nodeValue = db.openMap(`append_only_snapshot:${treeName}:node`); + this.#nodeLastModifiedByBlock = db.openMap(`append_ony_snapshot:${treeName}:block`); + this.#snapshotMetadata = db.openMap(`append_only_snapshot:${treeName}:snapshot_metadata`); + } + + getSnapshot(block: number): Promise { + const meta = this.#getSnapshotMeta(block); if (typeof meta === 'undefined') { - throw new Error(`Snapshot for tree ${this.tree.getName()} at block ${block} does not exist`); + return Promise.reject(new Error(`Snapshot for tree ${this.tree.getName()} at block ${block} does not exist`)); } - return new AppendOnlySnapshot(this.db, block, meta.numLeaves, meta.root, this.tree, this.hasher); + return Promise.resolve( + new AppendOnlySnapshot( + this.#nodeValue, + this.#nodeLastModifiedByBlock, + block, + meta.numLeaves, + meta.root, + this.tree, + this.hasher, + ), + ); } - async snapshot(block: number): Promise { - const meta = await this.#getSnapshotMeta(block); - if (typeof meta !== 'undefined') { - // no-op, we already have a snapshot - return new AppendOnlySnapshot(this.db, block, meta.numLeaves, meta.root, this.tree, this.hasher); - } - - const batch = this.db.batch(); - const root = this.tree.getRoot(false); - const depth = this.tree.getDepth(); - const treeName = this.tree.getName(); - const queue: [Buffer, number, bigint][] = [[root, 0, 0n]]; - - // walk the tree in BF and store latest nodes - while (queue.length > 0) { - const [node, level, index] = queue.shift()!; - - const historicalValue = await this.db.get(historicalNodeKey(treeName, level, index)).catch(() => undefined); - if (!historicalValue || !node.equals(historicalValue)) { - // we've never seen this node before or it's different than before - // update the historical tree and tag it with the block that modified it - batch.put(nodeModifiedAtBlockKey(treeName, level, index), String(block)); - batch.put(historicalNodeKey(treeName, level, index), node); - } else { - // if this node hasn't changed, that means, nothing below it has changed either - continue; - } - - if (level + 1 > depth) { - // short circuit if we've reached the leaf level - // otherwise getNode might throw if we ask for the children of a leaf - continue; + snapshot(block: number): Promise { + return this.db.transaction(() => { + const meta = this.#getSnapshotMeta(block); + if (typeof meta !== 'undefined') { + // no-op, we already have a snapshot + return new AppendOnlySnapshot( + this.#nodeValue, + this.#nodeLastModifiedByBlock, + block, + meta.numLeaves, + meta.root, + this.tree, + this.hasher, + ); } - // these could be undefined because zero hashes aren't stored in the tree - const [lhs, rhs] = await Promise.all([ - this.tree.getNode(level + 1, 2n * index), - this.tree.getNode(level + 1, 2n * index + 1n), - ]); - - if (lhs) { - queue.push([lhs, level + 1, 2n * index]); - } - - if (rhs) { - queue.push([rhs, level + 1, 2n * index + 1n]); + const root = this.tree.getRoot(false); + const depth = this.tree.getDepth(); + const queue: [Buffer, number, bigint][] = [[root, 0, 0n]]; + + // walk the tree in BF and store latest nodes + while (queue.length > 0) { + const [node, level, index] = queue.shift()!; + + const historicalValue = this.#nodeValue.get(historicalNodeKey(level, index)); + if (!historicalValue || !node.equals(historicalValue)) { + // we've never seen this node before or it's different than before + // update the historical tree and tag it with the block that modified it + void this.#nodeLastModifiedByBlock.set(nodeModifiedAtBlockKey(level, index), block); + void this.#nodeValue.set(historicalNodeKey(level, index), node); + } else { + // if this node hasn't changed, that means, nothing below it has changed either + continue; + } + + if (level + 1 > depth) { + // short circuit if we've reached the leaf level + // otherwise getNode might throw if we ask for the children of a leaf + continue; + } + + // these could be undefined because zero hashes aren't stored in the tree + const [lhs, rhs] = [this.tree.getNode(level + 1, 2n * index), this.tree.getNode(level + 1, 2n * index + 1n)]; + + if (lhs) { + queue.push([lhs, level + 1, 2n * index]); + } + + if (rhs) { + queue.push([rhs, level + 1, 2n * index + 1n]); + } } - } - - const numLeaves = this.tree.getNumLeaves(false); - batch.put(snapshotNumLeavesKey(treeName, block), String(numLeaves)); - batch.put(snapshotRootKey(treeName, block), root); - await batch.write(); - return new AppendOnlySnapshot(this.db, block, numLeaves, root, this.tree, this.hasher); + const numLeaves = this.tree.getNumLeaves(false); + void this.#snapshotMetadata.set(block, { + numLeaves, + root, + }); + + return new AppendOnlySnapshot( + this.#nodeValue, + this.#nodeLastModifiedByBlock, + block, + numLeaves, + root, + this.tree, + this.hasher, + ); + }); } - async #getSnapshotMeta(block: number): Promise< - | { - /** The root of the tree snapshot */ - root: Buffer; - /** The number of leaves in the tree snapshot */ - numLeaves: bigint; - } - | undefined - > { - try { - const treeName = this.tree.getName(); - const root = await this.db.get(snapshotRootKey(treeName, block)); - const numLeaves = BigInt(await this.db.get(snapshotNumLeavesKey(treeName, block))); - return { root, numLeaves }; - } catch (err) { - return undefined; - } + #getSnapshotMeta(block: number): SnapshotMetadata | undefined { + return this.#snapshotMetadata.get(block); } } @@ -128,7 +150,8 @@ export class AppendOnlySnapshotBuilder implements TreeSnapshotBuilder { */ class AppendOnlySnapshot implements TreeSnapshot { constructor( - private db: LevelUp, + private nodes: AztecMap, + private nodeHistory: AztecMap, private block: number, private leafCount: bigint, private historicalRoot: Buffer, @@ -136,7 +159,7 @@ class AppendOnlySnapshot implements TreeSnapshot { private hasher: Hasher, ) {} - public async getSiblingPath(index: bigint): Promise> { + public getSiblingPath(index: bigint): SiblingPath { const path: Buffer[] = []; const depth = this.tree.getDepth(); let level = depth; @@ -145,7 +168,7 @@ class AppendOnlySnapshot implements TreeSnapshot { const isRight = index & 0x01n; const siblingIndex = isRight ? index - 1n : index + 1n; - const sibling = await this.#getHistoricalNodeValue(level, siblingIndex); + const sibling = this.#getHistoricalNodeValue(level, siblingIndex); path.push(sibling); level -= 1; @@ -168,9 +191,9 @@ class AppendOnlySnapshot implements TreeSnapshot { return this.historicalRoot; } - async getLeafValue(index: bigint): Promise { + getLeafValue(index: bigint): Buffer | undefined { const leafLevel = this.getDepth(); - const blockNumber = await this.#getBlockNumberThatModifiedNode(leafLevel, index); + const blockNumber = this.#getBlockNumberThatModifiedNode(leafLevel, index); // leaf hasn't been set yet if (typeof blockNumber === 'undefined') { @@ -179,15 +202,15 @@ class AppendOnlySnapshot implements TreeSnapshot { // leaf was set some time in the past if (blockNumber <= this.block) { - return this.db.get(historicalNodeKey(this.tree.getName(), leafLevel, index)); + return this.nodes.get(historicalNodeKey(leafLevel, index)); } // leaf has been set but in a block in the future return undefined; } - async #getHistoricalNodeValue(level: number, index: bigint): Promise { - const blockNumber = await this.#getBlockNumberThatModifiedNode(level, index); + #getHistoricalNodeValue(level: number, index: bigint): Buffer { + const blockNumber = this.#getBlockNumberThatModifiedNode(level, index); // node has never been set if (typeof blockNumber === 'undefined') { @@ -196,7 +219,7 @@ class AppendOnlySnapshot implements TreeSnapshot { // node was set some time in the past if (blockNumber <= this.block) { - return this.db.get(historicalNodeKey(this.tree.getName(), level, index)); + return this.nodes.get(historicalNodeKey(level, index))!; } // the node has been modified since this snapshot was taken @@ -214,27 +237,22 @@ class AppendOnlySnapshot implements TreeSnapshot { return this.tree.getZeroHash(level); } - const [lhs, rhs] = await Promise.all([ + const [lhs, rhs] = [ this.#getHistoricalNodeValue(level + 1, 2n * index), this.#getHistoricalNodeValue(level + 1, 2n * index + 1n), - ]); + ]; return this.hasher.hash(lhs, rhs); } - async #getBlockNumberThatModifiedNode(level: number, index: bigint): Promise { - try { - const value: Buffer | string = await this.db.get(nodeModifiedAtBlockKey(this.tree.getName(), level, index)); - return parseInt(value.toString(), 10); - } catch (err) { - return undefined; - } + #getBlockNumberThatModifiedNode(level: number, index: bigint): number | undefined { + return this.nodeHistory.get(nodeModifiedAtBlockKey(level, index)); } - async findLeafIndex(value: Buffer): Promise { + findLeafIndex(value: Buffer): bigint | undefined { const numLeaves = this.getNumLeaves(); for (let i = 0n; i < numLeaves; i++) { - const currentValue = await this.getLeafValue(i); + const currentValue = this.getLeafValue(i); if (currentValue && currentValue.equals(value)) { return i; } diff --git a/yarn-project/merkle-tree/src/snapshots/base_full_snapshot.ts b/yarn-project/merkle-tree/src/snapshots/base_full_snapshot.ts index 8f49bb91582..5f1e250c569 100644 --- a/yarn-project/merkle-tree/src/snapshots/base_full_snapshot.ts +++ b/yarn-project/merkle-tree/src/snapshots/base_full_snapshot.ts @@ -1,17 +1,18 @@ +import { AztecKVStore, AztecMap } from '@aztec/kv-store'; import { SiblingPath } from '@aztec/types/membership'; -import { LevelUp, LevelUpChain } from 'levelup'; - import { TreeBase } from '../tree_base.js'; import { TreeSnapshot, TreeSnapshotBuilder } from './snapshot_builder.js'; -// key for a node's children -const snapshotChildKey = (node: Buffer, child: 0 | 1) => - Buffer.concat([Buffer.from('snapshot:node:'), node, Buffer.from(':' + child)]); - -// metadata for a snapshot -const snapshotRootKey = (treeName: string, block: number) => `snapshot:root:${treeName}:${block}`; -const snapshotNumLeavesKey = (treeName: string, block: number) => `snapshot:numLeaves:${treeName}:${block}`; +/** + * Metadata for a snapshot, per block + */ +type SnapshotMetadata = { + /** The tree root at the time */ + root: Buffer; + /** The number of filled leaves */ + numLeaves: bigint; +}; /** * Builds a full snapshot of a tree. This implementation works for any Merkle tree and stores @@ -32,104 +33,86 @@ const snapshotNumLeavesKey = (treeName: string, block: number) => `snapshot:numL export abstract class BaseFullTreeSnapshotBuilder implements TreeSnapshotBuilder { - constructor(protected db: LevelUp, protected tree: T) {} - - async snapshot(block: number): Promise { - const snapshotMetadata = await this.#getSnapshotMeta(block); - - if (snapshotMetadata) { - return this.openSnapshot(snapshotMetadata.root, snapshotMetadata.numLeaves); - } - - const batch = this.db.batch(); - const root = this.tree.getRoot(false); - const numLeaves = this.tree.getNumLeaves(false); - const depth = this.tree.getDepth(); - const queue: [Buffer, number, bigint][] = [[root, 0, 0n]]; - - // walk the tree breadth-first and store each of its nodes in the database - // for each node we save two keys - // :0 -> - // :1 -> - while (queue.length > 0) { - const [node, level, i] = queue.shift()!; - // check if the database already has a child for this tree - // if it does, then we know we've seen the whole subtree below it before - // and we don't have to traverse it anymore - // we use the left child here, but it could be anything that shows we've stored the node before - const exists: Buffer | undefined = await this.db.get(snapshotChildKey(node, 0)).catch(() => undefined); - if (exists) { - continue; - } + protected nodes: AztecMap; + protected snapshotMetadata: AztecMap; - if (level + 1 > depth) { - // short circuit if we've reached the leaf level - // otherwise getNode might throw if we ask for the children of a leaf - await this.handleLeaf(i, node, batch); - continue; - } - - const [lhs, rhs] = await Promise.all([ - this.tree.getNode(level + 1, 2n * i), - this.tree.getNode(level + 1, 2n * i + 1n), - ]); - - // we want the zero hash at the children's level, not the node's level - const zeroHash = this.tree.getZeroHash(level + 1); + constructor(protected db: AztecKVStore, protected tree: T) { + this.nodes = db.openMap(`full_snapshot:${tree.getName()}:node`); + this.snapshotMetadata = db.openMap(`full_snapshot:${tree.getName()}:metadata`); + } - batch.put(snapshotChildKey(node, 0), lhs ?? zeroHash); - batch.put(snapshotChildKey(node, 1), rhs ?? zeroHash); + snapshot(block: number): Promise { + return this.db.transaction(() => { + const snapshotMetadata = this.#getSnapshotMeta(block); - // enqueue the children only if they're not zero hashes - if (lhs) { - queue.push([lhs, level + 1, 2n * i]); + if (snapshotMetadata) { + return this.openSnapshot(snapshotMetadata.root, snapshotMetadata.numLeaves); } - if (rhs) { - queue.push([rhs, level + 1, 2n * i + 1n]); + const root = this.tree.getRoot(false); + const numLeaves = this.tree.getNumLeaves(false); + const depth = this.tree.getDepth(); + const queue: [Buffer, number, bigint][] = [[root, 0, 0n]]; + + // walk the tree breadth-first and store each of its nodes in the database + // for each node we save two keys + // :0 -> + // :1 -> + while (queue.length > 0) { + const [node, level, i] = queue.shift()!; + const nodeKey = node.toString('hex'); + // check if the database already has a child for this tree + // if it does, then we know we've seen the whole subtree below it before + // and we don't have to traverse it anymore + // we use the left child here, but it could be anything that shows we've stored the node before + if (this.nodes.has(nodeKey)) { + continue; + } + + if (level + 1 > depth) { + // short circuit if we've reached the leaf level + // otherwise getNode might throw if we ask for the children of a leaf + this.handleLeaf(i, node); + continue; + } + + const [lhs, rhs] = [this.tree.getNode(level + 1, 2n * i), this.tree.getNode(level + 1, 2n * i + 1n)]; + + // we want the zero hash at the children's level, not the node's level + const zeroHash = this.tree.getZeroHash(level + 1); + + void this.nodes.set(nodeKey, [lhs ?? zeroHash, rhs ?? zeroHash]); + // enqueue the children only if they're not zero hashes + if (lhs) { + queue.push([lhs, level + 1, 2n * i]); + } + + if (rhs) { + queue.push([rhs, level + 1, 2n * i + 1n]); + } } - } - batch.put(snapshotRootKey(this.tree.getName(), block), root); - batch.put(snapshotNumLeavesKey(this.tree.getName(), block), String(numLeaves)); - await batch.write(); - - return this.openSnapshot(root, numLeaves); + void this.snapshotMetadata.set(block, { root, numLeaves }); + return this.openSnapshot(root, numLeaves); + }); } - protected handleLeaf(_index: bigint, _node: Buffer, _batch: LevelUpChain) { - return Promise.resolve(); - } + protected handleLeaf(_index: bigint, _node: Buffer): void {} - async getSnapshot(version: number): Promise { - const snapshotMetadata = await this.#getSnapshotMeta(version); + getSnapshot(version: number): Promise { + const snapshotMetadata = this.#getSnapshotMeta(version); if (!snapshotMetadata) { - throw new Error(`Version ${version} does not exist for tree ${this.tree.getName()}`); + return Promise.reject(new Error(`Version ${version} does not exist for tree ${this.tree.getName()}`)); } - return this.openSnapshot(snapshotMetadata.root, snapshotMetadata.numLeaves); + return Promise.resolve(this.openSnapshot(snapshotMetadata.root, snapshotMetadata.numLeaves)); } protected abstract openSnapshot(root: Buffer, numLeaves: bigint): S; - async #getSnapshotMeta(block: number): Promise< - | { - /** The root of the tree snapshot */ - root: Buffer; - /** The number of leaves in the tree snapshot */ - numLeaves: bigint; - } - | undefined - > { - try { - const treeName = this.tree.getName(); - const root = await this.db.get(snapshotRootKey(treeName, block)); - const numLeaves = BigInt(await this.db.get(snapshotNumLeavesKey(treeName, block))); - return { root, numLeaves }; - } catch (err) { - return undefined; - } + #getSnapshotMeta(block: number): SnapshotMetadata | undefined { + return this.snapshotMetadata.get(block); } } @@ -138,16 +121,16 @@ export abstract class BaseFullTreeSnapshotBuilder, protected historicRoot: Buffer, protected numLeaves: bigint, protected tree: TreeBase, ) {} - async getSiblingPath(index: bigint): Promise> { + getSiblingPath(index: bigint): SiblingPath { const siblings: Buffer[] = []; - for await (const [_node, sibling] of this.pathFromRootToLeaf(index)) { + for (const [_node, sibling] of this.pathFromRootToLeaf(index)) { siblings.push(sibling); } @@ -158,9 +141,9 @@ export class BaseFullTreeSnapshot implements TreeSnapshot { return new SiblingPath(this.tree.getDepth() as N, siblings); } - async getLeafValue(index: bigint): Promise { + getLeafValue(index: bigint): Buffer | undefined { let leafNode: Buffer | undefined = undefined; - for await (const [node, _sibling] of this.pathFromRootToLeaf(index)) { + for (const [node, _sibling] of this.pathFromRootToLeaf(index)) { leafNode = node; } @@ -179,17 +162,17 @@ export class BaseFullTreeSnapshot implements TreeSnapshot { return this.numLeaves; } - protected async *pathFromRootToLeaf(leafIndex: bigint) { + protected *pathFromRootToLeaf(leafIndex: bigint) { const root = this.historicRoot; const pathFromRoot = this.#getPathFromRoot(leafIndex); let node: Buffer = root; for (let i = 0; i < pathFromRoot.length; i++) { // get both children. We'll need both anyway (one to keep track of, the other to walk down to) - const children: [Buffer, Buffer] = await Promise.all([ - this.db.get(snapshotChildKey(node, 0)), - this.db.get(snapshotChildKey(node, 1)), - ]).catch(() => [this.tree.getZeroHash(i + 1), this.tree.getZeroHash(i + 1)]); + const children: [Buffer, Buffer] = this.db.get(node.toString('hex')) ?? [ + this.tree.getZeroHash(i + 1), + this.tree.getZeroHash(i + 1), + ]; const next = children[pathFromRoot[i]]; const sibling = children[(pathFromRoot[i] + 1) % 2]; @@ -219,10 +202,10 @@ export class BaseFullTreeSnapshot implements TreeSnapshot { return path; } - async findLeafIndex(value: Buffer): Promise { + findLeafIndex(value: Buffer): bigint | undefined { const numLeaves = this.getNumLeaves(); for (let i = 0n; i < numLeaves; i++) { - const currentValue = await this.getLeafValue(i); + const currentValue = this.getLeafValue(i); if (currentValue && currentValue.equals(value)) { return i; } diff --git a/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts b/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts index 3f2cc2af791..4219dbd1c45 100644 --- a/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts +++ b/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts @@ -1,17 +1,16 @@ -import levelup, { LevelUp } from 'levelup'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Pedersen, StandardTree, newTree } from '../index.js'; -import { createMemDown } from '../test/utils/create_mem_down.js'; import { FullTreeSnapshotBuilder } from './full_snapshot.js'; import { describeSnapshotBuilderTestSuite } from './snapshot_builder_test_suite.js'; describe('FullSnapshotBuilder', () => { let tree: StandardTree; let snapshotBuilder: FullTreeSnapshotBuilder; - let db: LevelUp; + let db: AztecKVStore; beforeEach(async () => { - db = levelup(createMemDown()); + db = await AztecLmdbStore.openTmp(); tree = await newTree(StandardTree, db, new Pedersen(), 'test', 4); snapshotBuilder = new FullTreeSnapshotBuilder(db, tree); }); diff --git a/yarn-project/merkle-tree/src/snapshots/full_snapshot.ts b/yarn-project/merkle-tree/src/snapshots/full_snapshot.ts index c78d0ebb188..73cce3b05e7 100644 --- a/yarn-project/merkle-tree/src/snapshots/full_snapshot.ts +++ b/yarn-project/merkle-tree/src/snapshots/full_snapshot.ts @@ -21,6 +21,6 @@ export class FullTreeSnapshotBuilder implements TreeSnapshotBuilder { protected openSnapshot(root: Buffer, numLeaves: bigint): TreeSnapshot { - return new BaseFullTreeSnapshot(this.db, root, numLeaves, this.tree); + return new BaseFullTreeSnapshot(this.nodes, root, numLeaves, this.tree); } } diff --git a/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts b/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts index 664c83e605d..e1ba0b9e0f7 100644 --- a/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts +++ b/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts @@ -1,27 +1,25 @@ import { Fr, NullifierLeaf, NullifierLeafPreimage } from '@aztec/circuits.js'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; -import levelup, { LevelUp } from 'levelup'; - import { Pedersen, newTree } from '../index.js'; import { StandardIndexedTreeWithAppend } from '../standard_indexed_tree/test/standard_indexed_tree_with_append.js'; -import { createMemDown } from '../test/utils/create_mem_down.js'; import { IndexedTreeSnapshotBuilder } from './indexed_tree_snapshot.js'; import { describeSnapshotBuilderTestSuite } from './snapshot_builder_test_suite.js'; class NullifierTree extends StandardIndexedTreeWithAppend { - constructor(db: levelup.LevelUp, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { + constructor(db: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { super(db, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root); } } describe('IndexedTreeSnapshotBuilder', () => { - let db: LevelUp; + let db: AztecKVStore; let tree: StandardIndexedTreeWithAppend; let snapshotBuilder: IndexedTreeSnapshotBuilder; beforeEach(async () => { - db = levelup(createMemDown()); + db = await AztecLmdbStore.openTmp(); tree = await newTree(NullifierTree, db, new Pedersen(), 'test', 4); snapshotBuilder = new IndexedTreeSnapshotBuilder(db, tree, NullifierLeafPreimage); }); @@ -54,26 +52,26 @@ describe('IndexedTreeSnapshotBuilder', () => { await tree.appendLeaves([Buffer.from('d'), Buffer.from('e'), Buffer.from('f')]); await tree.commit(); - const expectedLeavesAtBlock2 = await Promise.all([ + const expectedLeavesAtBlock2 = [ tree.getLatestLeafPreimageCopy(0n, false), tree.getLatestLeafPreimageCopy(1n, false), tree.getLatestLeafPreimageCopy(2n, false), tree.getLatestLeafPreimageCopy(3n, false), tree.getLatestLeafPreimageCopy(4n, false), tree.getLatestLeafPreimageCopy(5n, false), - ]); + ]; await snapshotBuilder.snapshot(2); const snapshot1 = await snapshotBuilder.getSnapshot(1); - const actualLeavesAtBlock1 = await Promise.all([ + const actualLeavesAtBlock1 = [ snapshot1.getLatestLeafPreimageCopy(0n), snapshot1.getLatestLeafPreimageCopy(1n), snapshot1.getLatestLeafPreimageCopy(2n), snapshot1.getLatestLeafPreimageCopy(3n), snapshot1.getLatestLeafPreimageCopy(4n), snapshot1.getLatestLeafPreimageCopy(5n), - ]); + ]; expect(actualLeavesAtBlock1).toEqual(expectedLeavesAtBlock1); const snapshot2 = await snapshotBuilder.getSnapshot(2); @@ -94,12 +92,12 @@ describe('IndexedTreeSnapshotBuilder', () => { await tree.appendLeaves([Buffer.from('a'), Buffer.from('f'), Buffer.from('d')]); await tree.commit(); const snapshot = await snapshotBuilder.snapshot(1); - const historicalPrevValue = await tree.findIndexOfPreviousKey(2n, false); + const historicalPrevValue = tree.findIndexOfPreviousKey(2n, false); await tree.appendLeaves([Buffer.from('c'), Buffer.from('b'), Buffer.from('e')]); await tree.commit(); - await expect(snapshot.findIndexOfPreviousKey(2n)).resolves.toEqual(historicalPrevValue); + expect(snapshot.findIndexOfPreviousKey(2n)).toEqual(historicalPrevValue); }); }); }); diff --git a/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.ts b/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.ts index 28aeefdc953..8a787fd2067 100644 --- a/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.ts +++ b/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.ts @@ -1,33 +1,32 @@ import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; +import { AztecKVStore, AztecMap } from '@aztec/kv-store'; -import { LevelUp, LevelUpChain } from 'levelup'; - -import { IndexedTree } from '../interfaces/indexed_tree.js'; -import { PreimageFactory } from '../standard_indexed_tree/standard_indexed_tree.js'; +import { IndexedTree, PreimageFactory } from '../interfaces/indexed_tree.js'; import { TreeBase } from '../tree_base.js'; import { BaseFullTreeSnapshot, BaseFullTreeSnapshotBuilder } from './base_full_snapshot.js'; import { IndexedTreeSnapshot, TreeSnapshotBuilder } from './snapshot_builder.js'; -const snapshotLeafValue = (node: Buffer, index: bigint) => - Buffer.concat([Buffer.from('snapshot:leaf:'), node, Buffer.from(':' + index)]); +const snapshotLeafValue = (node: Buffer, index: bigint) => 'snapshot:leaf:' + node.toString('hex') + ':' + index; /** a */ export class IndexedTreeSnapshotBuilder extends BaseFullTreeSnapshotBuilder implements TreeSnapshotBuilder { - constructor(db: LevelUp, tree: IndexedTree & TreeBase, private leafPreimageBuilder: PreimageFactory) { - super(db, tree); + leaves: AztecMap; + constructor(store: AztecKVStore, tree: IndexedTree & TreeBase, private leafPreimageBuilder: PreimageFactory) { + super(store, tree); + this.leaves = store.openMap('indexed_tree_snapshot:' + tree.getName()); } protected openSnapshot(root: Buffer, numLeaves: bigint): IndexedTreeSnapshot { - return new IndexedTreeSnapshotImpl(this.db, root, numLeaves, this.tree, this.leafPreimageBuilder); + return new IndexedTreeSnapshotImpl(this.nodes, this.leaves, root, numLeaves, this.tree, this.leafPreimageBuilder); } - protected async handleLeaf(index: bigint, node: Buffer, batch: LevelUpChain) { - const leafPreimage = await this.tree.getLatestLeafPreimageCopy(index, false); + protected handleLeaf(index: bigint, node: Buffer) { + const leafPreimage = this.tree.getLatestLeafPreimageCopy(index, false); if (leafPreimage) { - batch.put(snapshotLeafValue(node, index), leafPreimage.toBuffer()); + void this.leaves.set(snapshotLeafValue(node, index), leafPreimage.toBuffer()); } } } @@ -35,7 +34,8 @@ export class IndexedTreeSnapshotBuilder /** A snapshot of an indexed tree at a particular point in time */ class IndexedTreeSnapshotImpl extends BaseFullTreeSnapshot implements IndexedTreeSnapshot { constructor( - db: LevelUp, + db: AztecMap, + private leaves: AztecMap, historicRoot: Buffer, numLeaves: bigint, tree: IndexedTree & TreeBase, @@ -44,14 +44,14 @@ class IndexedTreeSnapshotImpl extends BaseFullTreeSnapshot implements IndexedTre super(db, historicRoot, numLeaves, tree); } - async getLeafValue(index: bigint): Promise { - const leafPreimage = await this.getLatestLeafPreimageCopy(index); + getLeafValue(index: bigint): Buffer | undefined { + const leafPreimage = this.getLatestLeafPreimageCopy(index); return leafPreimage?.toBuffer(); } - async getLatestLeafPreimageCopy(index: bigint): Promise { - const leafNode = await super.getLeafValue(index); - const leafValue = await this.db.get(snapshotLeafValue(leafNode!, index)).catch(() => undefined); + getLatestLeafPreimageCopy(index: bigint): IndexedTreeLeafPreimage | undefined { + const leafNode = super.getLeafValue(index); + const leafValue = this.leaves.get(snapshotLeafValue(leafNode!, index)); if (leafValue) { return this.leafPreimageBuilder.fromBuffer(leafValue); } else { @@ -59,7 +59,7 @@ class IndexedTreeSnapshotImpl extends BaseFullTreeSnapshot implements IndexedTre } } - async findIndexOfPreviousKey(newValue: bigint): Promise<{ + findIndexOfPreviousKey(newValue: bigint): { /** * The index of the found leaf. */ @@ -68,13 +68,13 @@ class IndexedTreeSnapshotImpl extends BaseFullTreeSnapshot implements IndexedTre * A flag indicating if the corresponding leaf's value is equal to `newValue`. */ alreadyPresent: boolean; - }> { + } { const numLeaves = this.getNumLeaves(); const diff: bigint[] = []; for (let i = 0; i < numLeaves; i++) { // this is very inefficient - const storedLeaf = await this.getLatestLeafPreimageCopy(BigInt(i))!; + const storedLeaf = this.getLatestLeafPreimageCopy(BigInt(i))!; // The stored leaf can be undefined if it addresses an empty leaf // If the leaf is empty we do the same as if the leaf was larger @@ -99,8 +99,8 @@ class IndexedTreeSnapshotImpl extends BaseFullTreeSnapshot implements IndexedTre return { index: BigInt(minIndex), alreadyPresent: false }; } - async findLeafIndex(value: Buffer): Promise { - const index = await this.tree.findLeafIndex(value, false); + findLeafIndex(value: Buffer): bigint | undefined { + const index = this.tree.findLeafIndex(value, false); if (index !== undefined && index < this.getNumLeaves()) { return index; } diff --git a/yarn-project/merkle-tree/src/snapshots/snapshot_builder.ts b/yarn-project/merkle-tree/src/snapshots/snapshot_builder.ts index 872395e134e..98bbb9051d8 100644 --- a/yarn-project/merkle-tree/src/snapshots/snapshot_builder.ts +++ b/yarn-project/merkle-tree/src/snapshots/snapshot_builder.ts @@ -41,13 +41,13 @@ export interface TreeSnapshot { * Returns the value of a leaf at the specified index. * @param index - The index of the leaf value to be returned. */ - getLeafValue(index: bigint): Promise; + getLeafValue(index: bigint): Buffer | undefined; /** * Returns the sibling path for a requested leaf index. * @param index - The index of the leaf for which a sibling path is required. */ - getSiblingPath(index: bigint): Promise>; + getSiblingPath(index: bigint): SiblingPath; /** * Returns the index of a leaf given its value, or undefined if no leaf with that value is found. @@ -55,7 +55,7 @@ export interface TreeSnapshot { * @param value - The leaf value to look for. * @returns The index of the first leaf found with a given value (undefined if not found). */ - findLeafIndex(value: Buffer): Promise; + findLeafIndex(value: Buffer): bigint | undefined; } /** A snapshot of an indexed tree */ @@ -64,14 +64,14 @@ export interface IndexedTreeSnapshot extends TreeSnapshot { * Gets the historical data for a leaf * @param index - The index of the leaf to get the data for */ - getLatestLeafPreimageCopy(index: bigint): Promise; + getLatestLeafPreimageCopy(index: bigint): IndexedTreeLeafPreimage | undefined; /** * Finds the index of the largest leaf whose value is less than or equal to the provided value. * @param newValue - The new value to be inserted into the tree. * @returns The found leaf index and a flag indicating if the corresponding leaf's value is equal to `newValue`. */ - findIndexOfPreviousKey(newValue: bigint): Promise<{ + findIndexOfPreviousKey(newValue: bigint): { /** * The index of the found leaf. */ @@ -80,5 +80,5 @@ export interface IndexedTreeSnapshot extends TreeSnapshot { * A flag indicating if the corresponding leaf's value is equal to `newValue`. */ alreadyPresent: boolean; - }>; + }; } diff --git a/yarn-project/merkle-tree/src/snapshots/snapshot_builder_test_suite.ts b/yarn-project/merkle-tree/src/snapshots/snapshot_builder_test_suite.ts index f50ff1d69ae..85aa63f7b66 100644 --- a/yarn-project/merkle-tree/src/snapshots/snapshot_builder_test_suite.ts +++ b/yarn-project/merkle-tree/src/snapshots/snapshot_builder_test_suite.ts @@ -185,13 +185,13 @@ export function describeSnapshotBuilderTestSuite => { - return await newTree(SparseTree, levelUp, hasher, name, depth); +const createDb = async (db: AztecKVStore, hasher: Hasher, name: string, depth: number): Promise => { + return await newTree(SparseTree, db, hasher, name, depth); }; -const createFromName = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string): Promise => { - return await loadTree(SparseTree, levelUp, hasher, name); +const createFromName = async (db: AztecKVStore, hasher: Hasher, name: string): Promise => { + return await loadTree(SparseTree, db, hasher, name); }; const TEST_TREE_DEPTH = 3; @@ -42,19 +36,19 @@ describe('SparseTreeSpecific', () => { }); it('throws when index is bigger than (2^DEPTH - 1) ', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const depth = 32; const tree = await createDb(db, pedersen, 'test', depth); const index = 2n ** BigInt(depth); - await expect(tree.updateLeaf(Buffer.alloc(32), index)).rejects.toThrow(); + expect(() => tree.updateLeaf(Buffer.alloc(32), index)).toThrow(); }); it('updating non-empty leaf does not change tree size', async () => { const depth = 32; const maxIndex = 2 ** depth - 1; - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', depth); const randomIndex = BigInt(Math.floor(Math.random() * maxIndex)); @@ -73,7 +67,7 @@ describe('SparseTreeSpecific', () => { const depth = 254; const maxIndex = 2 ** depth - 1; - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', depth); const randomIndex = BigInt(Math.floor(Math.random() * maxIndex)); @@ -89,7 +83,7 @@ describe('SparseTreeSpecific', () => { }); it('should have correct root and sibling path after in a "non-append-only" way', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 3); const level2ZeroHash = pedersen.hash(INITIAL_LEAF, INITIAL_LEAF); @@ -162,7 +156,7 @@ describe('SparseTreeSpecific', () => { const depth = 254; const maxIndex = 2 ** depth - 1; - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', depth); const leaves = Array.from({ length: 1000 }).map(() => randomBytes(32)); diff --git a/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.ts b/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.ts index 138ca8f21e7..86f3c8506e4 100644 --- a/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.ts +++ b/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.ts @@ -7,24 +7,23 @@ import { INITIAL_LEAF, TreeBase } from '../tree_base.js'; * A Merkle tree implementation that uses a LevelDB database to store the tree. */ export class SparseTree extends TreeBase implements UpdateOnlyTree { - #snapshotBuilder = new FullTreeSnapshotBuilder(this.db, this); - + #snapshotBuilder = new FullTreeSnapshotBuilder(this.store, this); /** * Updates a leaf in the tree. * @param leaf - New contents of the leaf. * @param index - Index of the leaf to be updated. */ - public async updateLeaf(leaf: Buffer, index: bigint): Promise { + public updateLeaf(leaf: Buffer, index: bigint): Promise { if (index > this.maxIndex) { throw Error(`Index out of bounds. Index ${index}, max index: ${this.maxIndex}.`); } const insertingZeroElement = leaf.equals(INITIAL_LEAF); - const originallyZeroElement = (await this.getLeafValue(index, true))?.equals(INITIAL_LEAF); + const originallyZeroElement = this.getLeafValue(index, true)?.equals(INITIAL_LEAF); if (insertingZeroElement && originallyZeroElement) { - return; + return Promise.resolve(); } - await this.addLeafToCacheAndHashToRoot(leaf, index); + this.addLeafToCacheAndHashToRoot(leaf, index); if (insertingZeroElement) { // Deleting element (originally non-zero and new value is zero) this.cachedSize = (this.cachedSize ?? this.size) - 1n; @@ -32,6 +31,8 @@ export class SparseTree extends TreeBase implements UpdateOnlyTree { // Inserting new element (originally zero and new value is non-zero) this.cachedSize = (this.cachedSize ?? this.size) + 1n; } + + return Promise.resolve(); } public snapshot(block: number): Promise { @@ -42,7 +43,7 @@ export class SparseTree extends TreeBase implements UpdateOnlyTree { return this.#snapshotBuilder.getSnapshot(block); } - public findLeafIndex(_value: Buffer, _includeUncommitted: boolean): Promise { + public findLeafIndex(_value: Buffer, _includeUncommitted: boolean): bigint | undefined { throw new Error('Finding leaf index is not supported for sparse trees'); } } diff --git a/yarn-project/merkle-tree/src/standard_indexed_tree/standard_indexed_tree.ts b/yarn-project/merkle-tree/src/standard_indexed_tree/standard_indexed_tree.ts index dcd56f31839..316bc2a62df 100644 --- a/yarn-project/merkle-tree/src/standard_indexed_tree/standard_indexed_tree.ts +++ b/yarn-project/merkle-tree/src/standard_indexed_tree/standard_indexed_tree.ts @@ -1,57 +1,22 @@ import { TreeInsertionStats } from '@aztec/circuit-types/stats'; -import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; -import { createDebugLogger } from '@aztec/foundation/log'; +import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { Timer } from '@aztec/foundation/timer'; import { IndexedTreeLeaf, IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; +import { AztecKVStore, AztecMap } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; -import { LevelUp } from 'levelup'; - -import { - BatchInsertionResult, - IndexedTree, - IndexedTreeSnapshot, - IndexedTreeSnapshotBuilder, - LowLeafWitnessData, -} from '../index.js'; +import { BatchInsertionResult, IndexedTree, LowLeafWitnessData, PreimageFactory } from '../interfaces/indexed_tree.js'; +import { IndexedTreeSnapshotBuilder } from '../snapshots/indexed_tree_snapshot.js'; +import { IndexedTreeSnapshot } from '../snapshots/snapshot_builder.js'; import { TreeBase } from '../tree_base.js'; -const log = createDebugLogger('aztec:standard-indexed-tree'); - -/** - * Factory for creating leaf preimages. - */ -export interface PreimageFactory { - /** - * Creates a new preimage from a leaf. - * @param leaf - Leaf to create a preimage from. - * @param nextKey - Next key of the leaf. - * @param nextIndex - Next index of the leaf. - */ - fromLeaf(leaf: IndexedTreeLeaf, nextKey: bigint, nextIndex: bigint): IndexedTreeLeafPreimage; - /** - * Creates a new preimage from a buffer. - * @param buffer - Buffer to create a preimage from. - */ - fromBuffer(buffer: Buffer): IndexedTreeLeafPreimage; - /** - * Creates an empty preimage. - */ - empty(): IndexedTreeLeafPreimage; - /** - * Creates a copy of a preimage. - * @param preimage - Preimage to be cloned. - */ - clone(preimage: IndexedTreeLeafPreimage): IndexedTreeLeafPreimage; -} - export const buildDbKeyForPreimage = (name: string, index: bigint) => { - return `${name}:leaf_by_index:${toBufferBE(index, 32).toString('hex')}`; + return `${name}:leaf_by_index:${toBufferBE(index, 32).toString('hex')}` as const; }; export const buildDbKeyForLeafIndex = (name: string, key: bigint) => { - return `${name}:leaf_index_by_leaf_key:${toBufferBE(key, 32).toString('hex')}`; + return `${name}:leaf_index_by_leaf_key:${toBufferBE(key, 32).toString('hex')}` as const; }; /** @@ -90,11 +55,14 @@ function getEmptyLowLeafWitness( * Standard implementation of an indexed tree. */ export class StandardIndexedTree extends TreeBase implements IndexedTree { - #snapshotBuilder = new IndexedTreeSnapshotBuilder(this.db, this, this.leafPreimageFactory); + #snapshotBuilder = new IndexedTreeSnapshotBuilder(this.store, this, this.leafPreimageFactory); + protected cachedLeafPreimages: { [key: string]: IndexedTreeLeafPreimage } = {}; + protected leaves: AztecMap, Buffer>; + protected leafIndex: AztecMap, bigint>; public constructor( - db: LevelUp, + store: AztecKVStore, hasher: Hasher, name: string, depth: number, @@ -103,7 +71,9 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { protected leafFactory: LeafFactory, root?: Buffer, ) { - super(db, hasher, name, depth, size, root); + super(store, hasher, name, depth, size, root); + this.leaves = store.openMap(`tree_${name}_leaves`); + this.leafIndex = store.openMap(`tree_${name}_leaf_index`); } /** @@ -140,8 +110,8 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { * @param includeUncommitted - Indicates whether to include uncommitted leaves in the computation. * @returns The value of the leaf at the given index or undefined if the leaf is empty. */ - public async getLeafValue(index: bigint, includeUncommitted: boolean): Promise { - const preimage = await this.getLatestLeafPreimageCopy(index, includeUncommitted); + public getLeafValue(index: bigint, includeUncommitted: boolean): Buffer | undefined { + const preimage = this.getLatestLeafPreimageCopy(index, includeUncommitted); return preimage && preimage.toBuffer(); } @@ -151,10 +121,10 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { * @param includeUncommitted - If true, the uncommitted changes are included in the search. * @returns The found leaf index and a flag indicating if the corresponding leaf's value is equal to `newValue`. */ - async findIndexOfPreviousKey( + findIndexOfPreviousKey( newKey: bigint, includeUncommitted: boolean, - ): Promise< + ): | { /** * The index of the found leaf. @@ -165,10 +135,9 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { */ alreadyPresent: boolean; } - | undefined - > { - let lowLeafIndex = await this.getDbLowLeafIndex(newKey); - let lowLeafPreimage = lowLeafIndex !== undefined ? await this.getDbPreimage(lowLeafIndex) : undefined; + | undefined { + let lowLeafIndex = this.getDbLowLeafIndex(newKey); + let lowLeafPreimage = lowLeafIndex !== undefined ? this.getDbPreimage(lowLeafIndex) : undefined; if (includeUncommitted) { const cachedLowLeafIndex = this.getCachedLowLeafIndex(newKey); @@ -213,36 +182,21 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { return undefined; } - private async getDbLowLeafIndex(key: bigint): Promise { - return await new Promise((resolve, reject) => { - let lowLeafIndex: bigint | undefined; - this.db - .createReadStream({ - gte: buildDbKeyForLeafIndex(this.getName(), 0n), - lte: buildDbKeyForLeafIndex(this.getName(), key), - limit: 1, - reverse: true, - }) - .on('data', data => { - lowLeafIndex = toBigIntBE(data.value); - }) - .on('close', function () {}) - .on('end', function () { - resolve(lowLeafIndex); - }) - .on('error', function () { - log.error('stream error'); - reject(); - }); - }); + private getDbLowLeafIndex(key: bigint): bigint | undefined { + const values = Array.from( + this.leafIndex.values({ + end: buildDbKeyForLeafIndex(this.getName(), key), + limit: 1, + reverse: true, + }), + ); + + return values[0]; } - private async getDbPreimage(index: bigint): Promise { - const dbPreimage = await this.db - .get(buildDbKeyForPreimage(this.getName(), index)) - .then(data => this.leafPreimageFactory.fromBuffer(data)) - .catch(() => undefined); - return dbPreimage; + private getDbPreimage(index: bigint): IndexedTreeLeafPreimage | undefined { + const value = this.leaves.get(buildDbKeyForPreimage(this.getName(), index)); + return value ? this.leafPreimageFactory.fromBuffer(value) : undefined; } private getCachedPreimage(index: bigint): IndexedTreeLeafPreimage | undefined { @@ -255,13 +209,10 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { * @param includeUncommitted - If true, the uncommitted changes are included in the search. * @returns A copy of the leaf preimage at the given index or undefined if the leaf was not found. */ - public async getLatestLeafPreimageCopy( - index: bigint, - includeUncommitted: boolean, - ): Promise { + public getLatestLeafPreimageCopy(index: bigint, includeUncommitted: boolean): IndexedTreeLeafPreimage | undefined { const preimage = !includeUncommitted - ? await this.getDbPreimage(index) - : this.getCachedPreimage(index) ?? (await this.getDbPreimage(index)); + ? this.getDbPreimage(index) + : this.getCachedPreimage(index) ?? this.getDbPreimage(index); return preimage && this.leafPreimageFactory.clone(preimage); } @@ -271,17 +222,15 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { * @param includeUncommitted - Indicates whether to include uncommitted data. * @returns The index of the first leaf found with a given value (undefined if not found). */ - public async findLeafIndex(value: Buffer, includeUncommitted: boolean): Promise { + public findLeafIndex(value: Buffer, includeUncommitted: boolean): bigint | undefined { const leaf = this.leafFactory.fromBuffer(value); - let index = await this.db - .get(buildDbKeyForLeafIndex(this.getName(), leaf.getKey())) - .then(data => toBigIntBE(data)) - .catch(() => undefined); + let index = this.leafIndex.get(buildDbKeyForLeafIndex(this.getName(), leaf.getKey())); if (includeUncommitted && index === undefined) { const cachedIndex = this.getCachedLeafIndex(leaf.getKey()); index = cachedIndex; } + return index; } @@ -314,24 +263,24 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { // Make the last leaf point to the first leaf leaves[prefilledSize - 1] = this.leafPreimageFactory.fromLeaf(leaves[prefilledSize - 1].asLeaf(), 0n, 0n); - await this.encodeAndAppendLeaves(leaves, true); + this.encodeAndAppendLeaves(leaves, true); await this.commit(); } /** * Commits all the leaves to the database and removes them from a cache. */ - private async commitLeaves(): Promise { - const batch = this.db.batch(); - const keys = Object.getOwnPropertyNames(this.cachedLeafPreimages); - for (const key of keys) { - const leaf = this.cachedLeafPreimages[key]; - const index = BigInt(key); - batch.put(buildDbKeyForPreimage(this.getName(), index), leaf.toBuffer()); - batch.put(buildDbKeyForLeafIndex(this.getName(), leaf.getKey()), toBufferBE(index, 32)); - } - await batch.write(); - this.clearCachedLeaves(); + private commitLeaves(): Promise { + return this.store.transaction(() => { + const keys = Object.getOwnPropertyNames(this.cachedLeafPreimages); + for (const key of keys) { + const leaf = this.cachedLeafPreimages[key]; + const index = BigInt(key); + void this.leaves.set(buildDbKeyForPreimage(this.getName(), index), leaf.toBuffer()); + void this.leafIndex.set(buildDbKeyForLeafIndex(this.getName(), leaf.getKey()), index); + } + this.clearCachedLeaves(); + }); } /** @@ -346,14 +295,14 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { * @param preimage - New contents of the leaf. * @param index - Index of the leaf to be updated. */ - protected async updateLeaf(preimage: IndexedTreeLeafPreimage, index: bigint) { + protected updateLeaf(preimage: IndexedTreeLeafPreimage, index: bigint) { if (index > this.maxIndex) { throw Error(`Index out of bounds. Index ${index}, max index: ${this.maxIndex}.`); } this.cachedLeafPreimages[index.toString()] = preimage; const encodedLeaf = this.encodeLeaf(preimage, true); - await this.addLeafToCacheAndHashToRoot(encodedLeaf, index); + this.addLeafToCacheAndHashToRoot(encodedLeaf, index); const numLeaves = this.getNumLeaves(true); if (index >= numLeaves) { this.cachedSize = index + 1n; @@ -542,7 +491,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { insertedKeys.set(newLeaf.getKey(), true); } - const indexOfPrevious = await this.findIndexOfPreviousKey(newLeaf.getKey(), true); + const indexOfPrevious = this.findIndexOfPreviousKey(newLeaf.getKey(), true); if (indexOfPrevious === undefined) { return { lowLeavesWitnessData: undefined, @@ -555,7 +504,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { const isUpdate = indexOfPrevious.alreadyPresent; // get the low leaf (existence checked in getting index) - const lowLeafPreimage = (await this.getLatestLeafPreimageCopy(indexOfPrevious.index, true))!; + const lowLeafPreimage = this.getLatestLeafPreimageCopy(indexOfPrevious.index, true)!; const siblingPath = await this.getSiblingPath(BigInt(indexOfPrevious.index), true); const witness: LowLeafWitnessData = { @@ -576,7 +525,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { lowLeafPreimage.getNextIndex(), ); - await this.updateLeaf(newLowLeafPreimage, indexOfPrevious.index); + this.updateLeaf(newLowLeafPreimage, indexOfPrevious.index); pendingInsertionSubtree[originalIndex] = this.leafPreimageFactory.empty(); } else { @@ -586,7 +535,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { startInsertionIndex + BigInt(originalIndex), ); - await this.updateLeaf(newLowLeafPreimage, indexOfPrevious.index); + this.updateLeaf(newLowLeafPreimage, indexOfPrevious.index); const currentPendingPreimageLeaf = this.leafPreimageFactory.fromLeaf( newLeaf, @@ -606,7 +555,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { // Perform batch insertion of new pending values // Note: In this case we set `hash0Leaf` param to false because batch insertion algorithm use forced null leaf // inclusion. See {@link encodeLeaf} for a more through param explanation. - await this.encodeAndAppendLeaves(pendingInsertionSubtree, false); + this.encodeAndAppendLeaves(pendingInsertionSubtree, false); this.log(`Inserted ${leaves.length} leaves into ${this.getName()} tree`, { eventName: 'tree-insertion', @@ -641,8 +590,8 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { return this.#snapshotBuilder.snapshot(blockNumber); } - getSnapshot(block: number): Promise { - return this.#snapshotBuilder.getSnapshot(block); + getSnapshot(blockNumber: number): Promise { + return this.#snapshotBuilder.getSnapshot(blockNumber); } /** @@ -651,7 +600,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { * @param hash0Leaf - Indicates whether 0 value leaf should be hashed. See {@link encodeLeaf}. * @returns Empty promise */ - private async encodeAndAppendLeaves(preimages: IndexedTreeLeafPreimage[], hash0Leaf: boolean): Promise { + private encodeAndAppendLeaves(preimages: IndexedTreeLeafPreimage[], hash0Leaf: boolean): void { const startInsertionIndex = this.getNumLeaves(true); const hashedLeaves = preimages.map((preimage, i) => { @@ -659,7 +608,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree { return this.encodeLeaf(preimage, hash0Leaf); }); - await super.appendLeaves(hashedLeaves); + super.appendLeaves(hashedLeaves); } /** diff --git a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts index 65d50a8eb49..1e793daf656 100644 --- a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts +++ b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts @@ -6,34 +6,32 @@ import { PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; -import { default as levelup } from 'levelup'; - import { INITIAL_LEAF, MerkleTree, Pedersen, loadTree, newTree } from '../../index.js'; import { treeTestSuite } from '../../test/test_suite.js'; -import { createMemDown } from '../../test/utils/create_mem_down.js'; import { StandardIndexedTreeWithAppend } from './standard_indexed_tree_with_append.js'; class NullifierTree extends StandardIndexedTreeWithAppend { - constructor(db: levelup.LevelUp, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { - super(db, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root); + constructor(store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { + super(store, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root); } } class PublicDataTree extends StandardIndexedTreeWithAppend { - constructor(db: levelup.LevelUp, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { - super(db, hasher, name, depth, size, PublicDataTreeLeafPreimage, PublicDataTreeLeaf, root); + constructor(store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { + super(store, hasher, name, depth, size, PublicDataTreeLeafPreimage, PublicDataTreeLeaf, root); } } -const createDb = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string, depth: number, prefilledSize = 1) => { - return await newTree(NullifierTree, levelUp, hasher, name, depth, prefilledSize); +const createDb = async (store: AztecKVStore, hasher: Hasher, name: string, depth: number, prefilledSize = 1) => { + return await newTree(NullifierTree, store, hasher, name, depth, prefilledSize); }; -const createFromName = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string) => { - return await loadTree(NullifierTree, levelUp, hasher, name); +const createFromName = async (store: AztecKVStore, hasher: Hasher, name: string) => { + return await loadTree(NullifierTree, store, hasher, name); }; const createNullifierTreeLeafHashInputs = (value: number, nextIndex: number, nextValue: number) => { @@ -77,7 +75,7 @@ describe('StandardIndexedTreeSpecific', () => { it('produces the correct roots and sibling paths', async () => { // Create a depth-3 indexed merkle tree - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 3); /** @@ -274,8 +272,7 @@ describe('StandardIndexedTreeSpecific', () => { it('Can append empty leaves and handle insertions', async () => { // Create a depth-3 indexed merkle tree - const db = levelup(createMemDown()); - const tree = await createDb(db, pedersen, 'test', 3); + const tree = await createDb(await AztecLmdbStore.openTmp(), pedersen, 'test', 3); /** * Initial state: @@ -492,8 +489,8 @@ describe('StandardIndexedTreeSpecific', () => { const SUBTREE_HEIGHT = 5; // originally from BaseRollupInputs.NULLIFIER_SUBTREE_HEIGHT // Create a depth-3 indexed merkle tree - const appendTree = await createDb(levelup(createMemDown()), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); - const insertTree = await createDb(levelup(createMemDown()), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); + const appendTree = await createDb(await AztecLmdbStore.openTmp(), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); + const insertTree = await createDb(await AztecLmdbStore.openTmp(), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); await appendTree.appendLeaves(leaves); await insertTree.batchInsert(leaves, SUBTREE_HEIGHT); @@ -504,25 +501,25 @@ describe('StandardIndexedTreeSpecific', () => { }); it('should be able to find indexes of leaves', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 3); const values = [Buffer.alloc(32, 1), Buffer.alloc(32, 2)]; await tree.appendLeaves([values[0]]); - expect(await tree.findLeafIndex(values[0], true)).toBeDefined(); - expect(await tree.findLeafIndex(values[0], false)).toBe(undefined); - expect(await tree.findLeafIndex(values[1], true)).toBe(undefined); + expect(tree.findLeafIndex(values[0], true)).toBeDefined(); + expect(tree.findLeafIndex(values[0], false)).toBe(undefined); + expect(tree.findLeafIndex(values[1], true)).toBe(undefined); await tree.commit(); - expect(await tree.findLeafIndex(values[0], false)).toBeDefined(); + expect(tree.findLeafIndex(values[0], false)).toBeDefined(); }); describe('Updatable leaves', () => { it('should be able to upsert leaves', async () => { // Create a depth-3 indexed merkle tree - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await newTree(PublicDataTree, db, pedersen, 'test', 3, 1); /** @@ -632,7 +629,7 @@ describe('StandardIndexedTreeSpecific', () => { const INITIAL_TREE_SIZE = 8; const SUBTREE_HEIGHT = 5; - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const appendTree = await newTree(PublicDataTree, db, pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); const insertTree = await newTree(PublicDataTree, db, pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); diff --git a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts index 3fd3a123084..60ff4a9ecca 100644 --- a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts +++ b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts @@ -12,10 +12,12 @@ export class StandardIndexedTreeWithAppend extends StandardIndexedTree { * @returns Empty promise. * @remarks This method is inefficient and is here mostly for testing. Use batchInsert instead. */ - public async appendLeaves(leaves: Buffer[]): Promise { + public appendLeaves(leaves: Buffer[]): Promise { for (const leaf of leaves) { - await this.appendLeaf(leaf); + this.appendLeaf(leaf); } + + return Promise.resolve(); } private appendEmptyLeaf() { @@ -31,7 +33,7 @@ export class StandardIndexedTreeWithAppend extends StandardIndexedTree { * @param leaf - The leaf to append. * @returns Empty promise. */ - private async appendLeaf(leaf: Buffer): Promise { + private appendLeaf(leaf: Buffer): void { const newLeaf = this.leafFactory.fromBuffer(leaf); // Special case when appending zero @@ -40,13 +42,13 @@ export class StandardIndexedTreeWithAppend extends StandardIndexedTree { return; } - const lowLeafIndex = await this.findIndexOfPreviousKey(newLeaf.getKey(), true); + const lowLeafIndex = this.findIndexOfPreviousKey(newLeaf.getKey(), true); if (lowLeafIndex === undefined) { throw new Error(`Previous leaf not found!`); } const isUpdate = lowLeafIndex.alreadyPresent; - const lowLeafPreimage = (await this.getLatestLeafPreimageCopy(lowLeafIndex.index, true))!; + const lowLeafPreimage = this.getLatestLeafPreimageCopy(lowLeafIndex.index, true)!; const currentSize = this.getNumLeaves(true); if (isUpdate) { @@ -57,7 +59,7 @@ export class StandardIndexedTreeWithAppend extends StandardIndexedTree { lowLeafPreimage.getNextIndex(), ); - await this.updateLeaf(newLowLeafPreimage, BigInt(lowLeafIndex.index)); + this.updateLeaf(newLowLeafPreimage, BigInt(lowLeafIndex.index)); this.appendEmptyLeaf(); } else { const newLeafPreimage = this.leafPreimageFactory.fromLeaf( @@ -72,8 +74,8 @@ export class StandardIndexedTreeWithAppend extends StandardIndexedTree { newLeaf.getKey(), BigInt(currentSize), ); - await this.updateLeaf(newLowLeafPreimage, BigInt(lowLeafIndex.index)); - await this.updateLeaf(newLeafPreimage, currentSize); + this.updateLeaf(newLowLeafPreimage, BigInt(lowLeafIndex.index)); + this.updateLeaf(newLeafPreimage, currentSize); } } } diff --git a/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts b/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts index 34d8cc3b514..7da886753aa 100644 --- a/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts +++ b/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts @@ -1,23 +1,21 @@ import { randomBytes } from '@aztec/foundation/crypto'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; -import { default as levelup } from 'levelup'; - import { loadTree } from '../load_tree.js'; import { newTree } from '../new_tree.js'; import { standardBasedTreeTestSuite } from '../test/standard_based_test_suite.js'; import { treeTestSuite } from '../test/test_suite.js'; -import { createMemDown } from '../test/utils/create_mem_down.js'; import { PedersenWithCounter } from '../test/utils/pedersen_with_counter.js'; import { INITIAL_LEAF } from '../tree_base.js'; import { StandardTree } from './standard_tree.js'; -const createDb = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string, depth: number) => { - return await newTree(StandardTree, levelUp, hasher, name, depth); +const createDb = async (store: AztecKVStore, hasher: Hasher, name: string, depth: number) => { + return await newTree(StandardTree, store, hasher, name, depth); }; -const createFromName = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string) => { - return await loadTree(StandardTree, levelUp, hasher, name); +const createFromName = async (store: AztecKVStore, hasher: Hasher, name: string) => { + return await loadTree(StandardTree, store, hasher, name); }; treeTestSuite('StandardTree', createDb, createFromName); @@ -35,7 +33,7 @@ describe('StandardTree_batchAppend', () => { }); it('correctly computes root when batch appending and calls hash function expected num times', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 3); const leaves = Array.from({ length: 5 }, _ => randomBytes(32)); @@ -71,18 +69,18 @@ describe('StandardTree_batchAppend', () => { }); it('should be able to find indexes of leaves', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 3); const values = [Buffer.alloc(32, 1), Buffer.alloc(32, 2)]; await tree.appendLeaves([values[0]]); - expect(await tree.findLeafIndex(values[0], true)).toBeDefined(); - expect(await tree.findLeafIndex(values[0], false)).toBe(undefined); - expect(await tree.findLeafIndex(values[1], true)).toBe(undefined); + expect(tree.findLeafIndex(values[0], true)).toBeDefined(); + expect(tree.findLeafIndex(values[0], false)).toBe(undefined); + expect(tree.findLeafIndex(values[1], true)).toBe(undefined); await tree.commit(); - expect(await tree.findLeafIndex(values[0], false)).toBeDefined(); + expect(tree.findLeafIndex(values[0], false)).toBeDefined(); }); }); diff --git a/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts b/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts index cc587ee3a3d..c1dc29cda69 100644 --- a/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts +++ b/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts @@ -1,25 +1,26 @@ import { TreeInsertionStats } from '@aztec/circuit-types/stats'; import { Timer } from '@aztec/foundation/timer'; -import { AppendOnlySnapshotBuilder, TreeSnapshot } from '../index.js'; import { AppendOnlyTree } from '../interfaces/append_only_tree.js'; +import { AppendOnlySnapshotBuilder } from '../snapshots/append_only_snapshot.js'; +import { TreeSnapshot } from '../snapshots/snapshot_builder.js'; import { TreeBase } from '../tree_base.js'; /** * A Merkle tree implementation that uses a LevelDB database to store the tree. */ export class StandardTree extends TreeBase implements AppendOnlyTree { - #snapshotBuilder = new AppendOnlySnapshotBuilder(this.db, this, this.hasher); + #snapshotBuilder = new AppendOnlySnapshotBuilder(this.store, this, this.hasher); /** * Appends the given leaves to the tree. * @param leaves - The leaves to append. * @returns Empty promise. */ - public async appendLeaves(leaves: Buffer[]): Promise { + public appendLeaves(leaves: Buffer[]): Promise { this.hasher.reset(); const timer = new Timer(); - await super.appendLeaves(leaves); + super.appendLeaves(leaves); this.log(`Inserted ${leaves.length} leaves into ${this.getName()} tree`, { eventName: 'tree-insertion', duration: timer.ms(), @@ -29,19 +30,21 @@ export class StandardTree extends TreeBase implements AppendOnlyTree { treeType: 'append-only', ...this.hasher.stats(), } satisfies TreeInsertionStats); + + return Promise.resolve(); } - public snapshot(block: number): Promise { - return this.#snapshotBuilder.snapshot(block); + public snapshot(blockNumber: number): Promise { + return this.#snapshotBuilder.snapshot(blockNumber); } - public getSnapshot(block: number): Promise { - return this.#snapshotBuilder.getSnapshot(block); + public getSnapshot(blockNumber: number): Promise { + return this.#snapshotBuilder.getSnapshot(blockNumber); } - public async findLeafIndex(value: Buffer, includeUncommitted: boolean): Promise { + public findLeafIndex(value: Buffer, includeUncommitted: boolean): bigint | undefined { for (let i = 0n; i < this.getNumLeaves(includeUncommitted); i++) { - const currentValue = await this.getLeafValue(i, includeUncommitted); + const currentValue = this.getLeafValue(i, includeUncommitted); if (currentValue && currentValue.equals(value)) { return i; } diff --git a/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts b/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts index 29881831ee2..bfd95e7b349 100644 --- a/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts +++ b/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts @@ -1,21 +1,20 @@ +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; import { randomBytes } from 'crypto'; -import { default as levelup } from 'levelup'; import { INITIAL_LEAF, Pedersen } from '../index.js'; import { AppendOnlyTree } from '../interfaces/append_only_tree.js'; import { UpdateOnlyTree } from '../interfaces/update_only_tree.js'; import { appendLeaves } from './utils/append_leaves.js'; -import { createMemDown } from './utils/create_mem_down.js'; const TEST_TREE_DEPTH = 2; export const standardBasedTreeTestSuite = ( testName: string, createDb: ( - levelup: levelup.LevelUp, + store: AztecKVStore, hasher: Hasher, name: string, depth: number, @@ -36,21 +35,21 @@ export const standardBasedTreeTestSuite = ( }); it('should have correct empty tree root for depth 32', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 32); const root = tree.getRoot(false); expect(root.toString('hex')).toEqual('16642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb'); }); it('should throw when appending beyond max index', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 2); const leaves = Array.from({ length: 5 }, _ => randomBytes(32)); await expect(appendLeaves(tree, leaves)).rejects.toThrow(); }); it('should have correct root and sibling paths', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 2); const level1ZeroHash = pedersen.hash(INITIAL_LEAF, INITIAL_LEAF); diff --git a/yarn-project/merkle-tree/src/test/test_suite.ts b/yarn-project/merkle-tree/src/test/test_suite.ts index 31ee72a9b0e..fd2d5b038fb 100644 --- a/yarn-project/merkle-tree/src/test/test_suite.ts +++ b/yarn-project/merkle-tree/src/test/test_suite.ts @@ -1,13 +1,11 @@ +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; -import { default as levelup } from 'levelup'; - import { Pedersen } from '../index.js'; import { AppendOnlyTree } from '../interfaces/append_only_tree.js'; import { UpdateOnlyTree } from '../interfaces/update_only_tree.js'; import { appendLeaves } from './utils/append_leaves.js'; -import { createMemDown } from './utils/create_mem_down.js'; const expectSameTrees = async ( tree1: AppendOnlyTree | UpdateOnlyTree, @@ -28,12 +26,12 @@ const expectSameTrees = async ( export const treeTestSuite = ( testName: string, createDb: ( - levelup: levelup.LevelUp, + store: AztecKVStore, hasher: Hasher, name: string, depth: number, ) => Promise, - createFromName: (levelup: levelup.LevelUp, hasher: Hasher, name: string) => Promise, + createFromName: (store: AztecKVStore, hasher: Hasher, name: string) => Promise, ) => { describe(testName, () => { const values: Buffer[] = []; @@ -52,12 +50,10 @@ export const treeTestSuite = ( }); it('should revert changes on rollback', async () => { - const levelDownEmpty = createMemDown(); - const dbEmpty = levelup(levelDownEmpty); + const dbEmpty = await AztecLmdbStore.openTmp(); const emptyTree = await createDb(dbEmpty, pedersen, 'test', 10); - const levelDown = createMemDown(); - const db = levelup(levelDown); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test2', 10); await appendLeaves(tree, values.slice(0, 4)); @@ -89,12 +85,10 @@ export const treeTestSuite = ( }); it('should not revert changes after commit', async () => { - const levelDownEmpty = createMemDown(); - const dbEmpty = levelup(levelDownEmpty); + const dbEmpty = await AztecLmdbStore.openTmp(); const emptyTree = await createDb(dbEmpty, pedersen, 'test', 10); - const levelDown = createMemDown(); - const db = levelup(levelDown); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test2', 10); await appendLeaves(tree, values.slice(0, 4)); @@ -110,14 +104,12 @@ export const treeTestSuite = ( }); it('should be able to restore from previous committed data', async () => { - const levelDown = createMemDown(); - const db = levelup(levelDown); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 10); await appendLeaves(tree, values.slice(0, 4)); await tree.commit(); - const db2 = levelup(levelDown); - const tree2 = await createFromName(db2, pedersen, 'test'); + const tree2 = await createFromName(db, pedersen, 'test'); // both committed and uncommitted should be equal to the restored data expect(tree.getRoot(true)).toEqual(tree2.getRoot(true)); @@ -129,7 +121,7 @@ export const treeTestSuite = ( }); it('should throw an error if previous data does not exist for the given name', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); await expect( (async () => { await createFromName(db, pedersen, 'a_whole_new_tree'); @@ -138,7 +130,7 @@ export const treeTestSuite = ( }); it('should serialize sibling path data to a buffer and be able to deserialize it back', async () => { - const db = levelup(createMemDown()); + const db = await AztecLmdbStore.openTmp(); const tree = await createDb(db, pedersen, 'test', 10); await appendLeaves(tree, values.slice(0, 1)); diff --git a/yarn-project/merkle-tree/src/test/utils/create_mem_down.ts b/yarn-project/merkle-tree/src/test/utils/create_mem_down.ts deleted file mode 100644 index 0be5ac35604..00000000000 --- a/yarn-project/merkle-tree/src/test/utils/create_mem_down.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { type MemDown, default as memdown } from 'memdown'; - -export const createMemDown = () => (memdown as any)() as MemDown; diff --git a/yarn-project/merkle-tree/src/tree_base.ts b/yarn-project/merkle-tree/src/tree_base.ts index 36f9b12b444..5a24ec81280 100644 --- a/yarn-project/merkle-tree/src/tree_base.ts +++ b/yarn-project/merkle-tree/src/tree_base.ts @@ -1,10 +1,9 @@ import { toBigIntLE, toBufferLE } from '@aztec/foundation/bigint-buffer'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; +import { AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store'; import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; -import { LevelUp, LevelUpChain } from 'levelup'; - import { HasherWithStats } from './hasher_with_stats.js'; import { MerkleTree } from './interfaces/merkle_tree.js'; @@ -17,7 +16,7 @@ const encodeMeta = (root: Buffer, depth: number, size: bigint) => { data.writeUInt32LE(depth, 32); return Buffer.concat([data, toBufferLE(size, 32)]); }; -export const decodeMeta = (meta: Buffer) => { +const decodeMeta = (meta: Buffer) => { const root = meta.subarray(0, 32); const depth = meta.readUInt32LE(32); const size = toBigIntLE(meta.subarray(36)); @@ -28,6 +27,18 @@ export const decodeMeta = (meta: Buffer) => { }; }; +const openTreeMetaSingleton = (store: AztecKVStore, treeName: string): AztecSingleton => + store.openSingleton(`merkle_tree_${treeName}_meta`); + +export const getTreeMeta = (store: AztecKVStore, treeName: string) => { + const singleton = openTreeMetaSingleton(store, treeName); + const val = singleton.get(); + if (!val) { + throw new Error(); + } + return decodeMeta(val); +}; + export const INITIAL_LEAF = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); /** @@ -40,11 +51,13 @@ export abstract class TreeBase implements MerkleTree { private zeroHashes: Buffer[] = []; private cache: { [key: string]: Buffer } = {}; protected log: DebugLogger; - protected hasher: HasherWithStats; + private nodes: AztecMap; + private meta: AztecSingleton; + public constructor( - protected db: LevelUp, + protected store: AztecKVStore, hasher: Hasher, private name: string, private depth: number, @@ -56,6 +69,8 @@ export abstract class TreeBase implements MerkleTree { } this.hasher = new HasherWithStats(hasher); + this.nodes = store.openMap('merkle_tree_' + name); + this.meta = openTreeMetaSingleton(store, name); // Compute the zero values at each layer. let current = INITIAL_LEAF; @@ -111,34 +126,36 @@ export abstract class TreeBase implements MerkleTree { * @returns A sibling path for the element at the given index. * Note: The sibling path is an array of sibling hashes, with the lowest hash (leaf hash) first, and the highest hash last. */ - public async getSiblingPath(index: bigint, includeUncommitted: boolean): Promise> { + public getSiblingPath(index: bigint, includeUncommitted: boolean): Promise> { const path: Buffer[] = []; let level = this.depth; while (level > 0) { const isRight = index & 0x01n; - const sibling = await this.getLatestValueAtIndex(level, isRight ? index - 1n : index + 1n, includeUncommitted); + const sibling = this.getLatestValueAtIndex(level, isRight ? index - 1n : index + 1n, includeUncommitted); path.push(sibling); level -= 1; index >>= 1n; } - return new SiblingPath(this.depth as N, path); + return Promise.resolve(new SiblingPath(this.depth as N, path)); } /** * Commits the changes to the database. * @returns Empty promise. */ - public async commit(): Promise { - const batch = this.db.batch(); - const keys = Object.getOwnPropertyNames(this.cache); - for (const key of keys) { - batch.put(key, this.cache[key]); - } - this.size = this.getNumLeaves(true); - this.root = this.getRoot(true); - await this.writeMeta(batch); - await batch.write(); - this.clearCache(); + public commit(): Promise { + return this.store.transaction(() => { + const keys = Object.getOwnPropertyNames(this.cache); + for (const key of keys) { + void this.nodes.set(key, this.cache[key]); + } + this.size = this.getNumLeaves(true); + this.root = this.getRoot(true); + + this.clearCache(); + + void this.writeMeta(); + }); } /** @@ -156,11 +173,11 @@ export abstract class TreeBase implements MerkleTree { * @param includeUncommitted - Indicates whether to include uncommitted changes. * @returns Leaf value at the given index or undefined. */ - public getLeafValue(index: bigint, includeUncommitted: boolean): Promise { + public getLeafValue(index: bigint, includeUncommitted: boolean): Buffer | undefined { return this.getLatestValueAtIndex(this.depth, index, includeUncommitted); } - public getNode(level: number, index: bigint): Promise { + public getNode(level: number, index: bigint): Buffer | undefined { if (level < 0 || level > this.depth) { throw Error('Invalid level: ' + level); } @@ -193,14 +210,14 @@ export abstract class TreeBase implements MerkleTree { * @param leaf - Leaf to add to cache. * @param index - Index of the leaf (used to derive the cache key). */ - protected async addLeafToCacheAndHashToRoot(leaf: Buffer, index: bigint) { + protected addLeafToCacheAndHashToRoot(leaf: Buffer, index: bigint) { const key = indexToKeyHash(this.name, this.depth, index); let current = leaf; this.cache[key] = current; let level = this.depth; while (level > 0) { const isRight = index & 0x01n; - const sibling = await this.getLatestValueAtIndex(level, isRight ? index - 1n : index + 1n, true); + const sibling = this.getLatestValueAtIndex(level, isRight ? index - 1n : index + 1n, true); const lhs = isRight ? sibling : current; const rhs = isRight ? current : sibling; current = this.hasher.hash(lhs, rhs); @@ -219,12 +236,12 @@ export abstract class TreeBase implements MerkleTree { * @returns The latest value at the given index. * Note: If the value is not in the cache, it will be fetched from the database. */ - private async getLatestValueAtIndex(level: number, index: bigint, includeUncommitted: boolean): Promise { + private getLatestValueAtIndex(level: number, index: bigint, includeUncommitted: boolean): Buffer { const key = indexToKeyHash(this.name, level, index); if (includeUncommitted && this.cache[key] !== undefined) { return this.cache[key]; } - const committed = await this.dbGet(key); + const committed = this.dbGet(key); if (committed !== undefined) { return committed; } @@ -236,8 +253,8 @@ export abstract class TreeBase implements MerkleTree { * @param key - The key to by which to get the value. * @returns A value from the db based on the key. */ - private async dbGet(key: string): Promise { - return await this.db.get(key).catch(() => {}); + private dbGet(key: string): Buffer | undefined { + return this.nodes.get(key); } /** @@ -255,13 +272,9 @@ export abstract class TreeBase implements MerkleTree { * Writes meta data to the provided batch. * @param batch - The batch to which to write the meta data. */ - protected async writeMeta(batch?: LevelUpChain) { + protected writeMeta() { const data = encodeMeta(this.getRoot(true), this.depth, this.getNumLeaves(true)); - if (batch) { - batch.put(this.name, data); - } else { - await this.db.put(this.name, data); - } + return this.meta.set(data); } /** @@ -279,7 +292,7 @@ export abstract class TreeBase implements MerkleTree { * `getLatestValueAtIndex` will return a value from cache (because at least one of the 2 children was * touched in previous iteration). */ - protected async appendLeaves(leaves: Buffer[]): Promise { + protected appendLeaves(leaves: Buffer[]): void { const numLeaves = this.getNumLeaves(true); if (numLeaves + BigInt(leaves.length) - 1n > this.maxIndex) { throw Error(`Can't append beyond max index. Max index: ${this.maxIndex}`); @@ -300,8 +313,8 @@ export abstract class TreeBase implements MerkleTree { lastIndex >>= 1n; // 3.Iterate over all the affected nodes at this level and update them for (let index = firstIndex; index <= lastIndex; index++) { - const lhs = await this.getLatestValueAtIndex(level, index * 2n, true); - const rhs = await this.getLatestValueAtIndex(level, index * 2n + 1n, true); + const lhs = this.getLatestValueAtIndex(level, index * 2n, true); + const rhs = this.getLatestValueAtIndex(level, index * 2n + 1n, true); const cacheKey = indexToKeyHash(this.name, level - 1, index); this.cache[cacheKey] = this.hasher.hash(lhs, rhs); } @@ -317,5 +330,5 @@ export abstract class TreeBase implements MerkleTree { * @param includeUncommitted - Indicates whether to include uncommitted data. * @returns The index of the first leaf found with a given value (undefined if not found). */ - abstract findLeafIndex(value: Buffer, includeUncommitted: boolean): Promise; + abstract findLeafIndex(value: Buffer, includeUncommitted: boolean): bigint | undefined; } diff --git a/yarn-project/merkle-tree/tsconfig.json b/yarn-project/merkle-tree/tsconfig.json index 413464d606d..631083e52f4 100644 --- a/yarn-project/merkle-tree/tsconfig.json +++ b/yarn-project/merkle-tree/tsconfig.json @@ -12,6 +12,9 @@ { "path": "../foundation" }, + { + "path": "../kv-store" + }, { "path": "../types" }, diff --git a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts index ab40a9b78e8..ee3513d6b67 100644 --- a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts +++ b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts @@ -3,16 +3,10 @@ import { LogFn } from '@aztec/foundation/log'; import { Command } from 'commander'; import { dirname } from 'path'; -/** - * - */ export function addNoirCompilerCommanderActions(program: Command, log: LogFn = () => {}) { addCodegenCommanderAction(program, log); } -/** - * - */ export function addCodegenCommanderAction(program: Command, _: LogFn = () => {}) { program .command('codegen') diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr index 0e9ce6369fa..7d5c8ae1257 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -96,8 +96,16 @@ contract DocsExample { } #[aztec(private)] - fn insert_note(amount: u8) { - let mut note = CardNote::new(amount, 1, context.msg_sender()); + fn insert_notes(amounts: [u8; 10]) { + for i in 0..amounts.len() { + let mut note = CardNote::new(amounts[i], 1, context.msg_sender()); + storage.test.insert(&mut note, true); + } + } + + #[aztec(private)] + fn insert_note(amount: u8, randomness: Field) { + let mut note = CardNote::new(amount, randomness, context.msg_sender()); storage.test.insert(&mut note, true); } @@ -105,15 +113,6 @@ contract DocsExample { let options = NoteViewerOptions::new().select(0, amount, Option::some(comparator)); let notes = storage.test.view_notes(options); - for i in 0..notes.len() { - if notes[i].is_some() { - debug_log_format( - "NOTES THAT MATCH: {0}", - [notes[i].unwrap_unchecked().points as Field] - ); - } - } - notes } @@ -166,9 +165,11 @@ contract DocsExample { storage.legendary_card.view_note() } + // docs:start:singleton_is_initialized unconstrained fn is_legendary_initialized() -> pub bool { storage.legendary_card.is_initialized() } + // docs:end:singleton_is_initialized unconstrained fn get_imm_card() -> pub CardNote { storage.imm_singleton.view_note() diff --git a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 779c8debecc..d02320b5ea8 100644 --- a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -3,7 +3,7 @@ use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_unique_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }, oracle::{ nullifier_key::get_nullifier_secret_key, @@ -61,7 +61,7 @@ impl EcdsaPublicKeyNote { } pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field { - let unique_siloed_note_hash = compute_unique_siloed_note_hash(EcdsaPublicKeyNoteInterface, self); + let unique_siloed_note_hash = compute_note_hash_for_read_or_nullify(EcdsaPublicKeyNoteInterface, self); let secret = context.request_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ @@ -72,7 +72,7 @@ impl EcdsaPublicKeyNote { } pub fn compute_nullifier_without_context(self) -> Field { - let unique_siloed_note_hash = compute_unique_siloed_note_hash(EcdsaPublicKeyNoteInterface, self); + let unique_siloed_note_hash = compute_note_hash_for_read_or_nullify(EcdsaPublicKeyNoteInterface, self); let secret = get_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ diff --git a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 2db16db6be3..82330325d1a 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_unique_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }, hash::pedersen_hash, oracle::{ @@ -41,7 +41,7 @@ impl PublicKeyNote { } pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field { - let unique_siloed_note_hash = compute_unique_siloed_note_hash(PublicKeyNoteMethods, self); + let unique_siloed_note_hash = compute_note_hash_for_read_or_nullify(PublicKeyNoteMethods, self); let secret = context.request_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ @@ -52,7 +52,7 @@ impl PublicKeyNote { } pub fn compute_nullifier_without_context(self) -> Field { - let unique_siloed_note_hash = compute_unique_siloed_note_hash(PublicKeyNoteMethods, self); + let unique_siloed_note_hash = compute_note_hash_for_read_or_nullify(PublicKeyNoteMethods, self); let secret = get_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ diff --git a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index 98867d1225c..36658d459cc 100644 --- a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -3,7 +3,7 @@ use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }, hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext, @@ -75,8 +75,7 @@ impl TransparentNote { } pub fn compute_nullifier_without_context(self) -> Field { - // TODO(#1386): should use `compute_note_hash_for_read_or_nullify` once public functions inject nonce! - let siloed_note_hash = compute_siloed_note_hash(TransparentNoteMethods, self); + let siloed_note_hash = compute_note_hash_for_read_or_nullify(TransparentNoteMethods, self); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([self.secret, siloed_note_hash],0) } diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index deb2bcdf6f1..361413bc82b 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -3,7 +3,7 @@ use dep::aztec::{ note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }, hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext, @@ -75,8 +75,7 @@ impl TransparentNote { } pub fn compute_nullifier_without_context(self) -> Field { - // TODO(#1386): should use `compute_note_hash_for_read_or_nullify` once public functions inject nonce! - let siloed_note_hash = compute_siloed_note_hash(TransparentNoteMethods, self); + let siloed_note_hash = compute_note_hash_for_read_or_nullify(TransparentNoteMethods, self); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([self.secret, siloed_note_hash],0) } diff --git a/yarn-project/noir-protocol-circuits/package.json b/yarn-project/noir-protocol-circuits/package.json index 358e89ccc14..9d1845d8ee8 100644 --- a/yarn-project/noir-protocol-circuits/package.json +++ b/yarn-project/noir-protocol-circuits/package.json @@ -39,6 +39,7 @@ }, "devDependencies": { "@aztec/circuit-types": "workspace:^", + "@aztec/kv-store": "workspace:^", "@aztec/merkle-tree": "workspace:^", "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", diff --git a/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap index 62013a5826c..ded53766652 100644 --- a/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap @@ -105,41 +105,41 @@ KernelCircuitPublicInputs { "constants": CombinedConstantData { "blockHeader": BlockHeader { "archiveRoot": Fr { - "asBigInt": 10561895175368852737061915973188839857007468377789560793687187642867659280638n, + "asBigInt": 11760689266673761585698609357698254380616683897751261211845848484095655455234n, "asBuffer": { "data": [ - 23, - 89, - 210, - 33, - 121, - 84, - 25, + 26, + 0, 80, - 63, - 134, - 192, - 50, - 232, - 248, - 118, - 47, - 43, - 115, - 158, - 116, - 131, + 113, + 164, + 135, + 228, + 137, + 23, + 135, + 7, + 58, + 145, 80, - 153, - 88, - 75, - 101, - 49, - 245, - 242, - 115, - 144, - 254, + 79, + 230, + 234, + 85, + 40, + 11, + 198, + 246, + 90, + 2, + 31, + 214, + 247, + 202, + 31, + 16, + 170, + 2, ], "type": "Buffer", }, @@ -385,41 +385,41 @@ KernelCircuitPublicInputs { }, }, "publicDataTreeRoot": Fr { - "asBigInt": 5785871043333994658400733180052743689641713274194136017445890613179954325976n, + "asBigInt": 13940981882517738105981911020707002777955674699044852872880094407282064863456n, "asBuffer": { "data": [ - 12, - 202, - 175, - 220, - 156, - 53, - 55, - 67, - 151, - 13, + 30, + 210, + 80, + 237, + 115, + 219, + 110, + 112, + 128, + 92, 78, - 48, - 90, - 231, - 54, + 252, + 240, + 5, + 110, + 134, + 149, + 183, + 156, + 211, + 186, 65, - 206, - 105, - 79, - 7, - 219, - 103, - 136, - 109, - 39, - 105, - 201, - 237, - 136, - 233, - 105, - 216, + 142, + 130, + 124, + 24, + 77, + 238, + 108, + 111, + 176, + 224, ], "type": "Buffer", }, @@ -427,7 +427,7 @@ KernelCircuitPublicInputs { }, "txContext": TxContext { "chainId": Fr { - "asBigInt": 0n, + "asBigInt": 31337n, "asBuffer": { "data": [ 0, @@ -460,89 +460,89 @@ KernelCircuitPublicInputs { 0, 0, 0, - 0, - 0, + 122, + 105, ], "type": "Buffer", }, }, "contractDeploymentData": ContractDeploymentData { "constructorVkHash": Fr { - "asBigInt": 4946902893997605007258693448883037341256770656195244398892734919432197304822n, + "asBigInt": 1583326240861609738393684596312518968005858067213923665222866669013140837326n, "asBuffer": { "data": [ - 10, - 239, - 217, - 10, - 105, - 166, - 67, - 50, - 76, - 123, - 240, - 169, + 3, + 128, + 33, + 130, + 79, 189, - 59, - 35, - 173, - 160, - 144, - 173, - 136, - 55, - 115, - 253, - 240, - 176, - 173, - 82, - 169, + 152, + 187, + 14, + 56, + 139, + 14, + 254, + 24, 247, - 214, - 241, - 246, + 46, + 147, + 80, + 247, + 69, + 100, + 129, + 113, + 69, + 57, + 186, + 88, + 61, + 227, + 113, + 19, + 206, ], "type": "Buffer", }, }, "contractAddressSalt": Fr { - "asBigInt": 13918524182926832455178861490988425129196887976468020413394338716458484696156n, + "asBigInt": 5715788628466014564753145955124535735977317413547751808173820928060130010488n, "asBuffer": { "data": [ - 30, - 197, - 155, - 3, - 19, - 250, + 12, + 163, + 5, + 143, + 94, + 10, + 226, + 248, + 9, + 137, + 101, 80, - 67, - 2, - 195, - 51, + 33, + 77, 111, - 201, - 17, - 214, - 136, - 237, - 174, - 103, - 196, - 251, - 242, - 41, - 214, - 140, - 127, - 54, - 237, - 135, - 151, - 4, - 92, + 184, + 200, + 96, + 243, + 132, + 162, + 245, + 72, + 217, + 95, + 220, + 148, + 193, + 176, + 199, + 37, + 120, ], "type": "Buffer", }, @@ -550,122 +550,122 @@ KernelCircuitPublicInputs { "deployerPublicKey": Point { "kind": "point", "x": Fr { - "asBigInt": 13513162828633936749079339485623471377790691038584182237805001838837073529635n, + "asBigInt": 18040458897480127764142223692208684686831966101790881484314177406099286746304n, "asBuffer": { "data": [ - 29, - 224, - 45, - 218, - 202, - 198, - 210, - 244, 39, - 229, - 240, - 211, - 206, + 226, + 137, + 179, + 9, + 158, + 32, + 88, + 100, + 81, + 85, + 106, + 132, + 94, + 61, + 117, + 248, 89, - 215, - 41, + 187, 79, - 20, - 98, - 128, - 69, - 93, - 212, - 197, - 130, - 37, - 78, - 11, - 76, - 37, - 75, - 35, + 117, + 127, + 132, + 202, + 1, + 223, + 151, + 46, + 193, + 33, + 100, + 192, ], "type": "Buffer", }, }, "y": Fr { - "asBigInt": 16193209371316637857741102275574203818928254115376185574760513755303226932941n, + "asBigInt": 8351469406419082733708266903523540335749598199220619980033469638087926373102n, "asBuffer": { "data": [ - 35, - 205, - 8, - 29, - 254, - 156, - 13, - 24, - 115, - 182, - 90, - 54, + 18, + 118, + 195, 160, - 136, - 88, - 231, - 58, - 155, - 48, - 208, - 51, - 158, - 148, - 196, + 229, + 74, + 243, + 59, + 218, + 78, + 201, + 25, + 170, + 200, + 125, + 20, + 25, + 192, + 0, + 98, + 161, 145, - 93, - 113, - 16, - 226, - 240, - 126, - 205, + 42, + 19, + 10, + 221, + 248, + 170, + 135, + 60, + 90, + 238, ], "type": "Buffer", }, }, }, "functionTreeRoot": Fr { - "asBigInt": 5733828181279984846924392032049330885938310333906649337231112228024374578179n, + "asBigInt": 5586268305277371185225261204085928914807606659970509385734366170410186349015n, "asBuffer": { "data": [ 12, - 173, - 59, - 83, - 145, - 228, - 10, - 248, - 116, - 62, - 16, - 83, - 192, - 21, - 225, - 106, - 186, - 198, - 16, - 10, - 139, - 145, - 117, - 18, + 89, + 183, + 63, + 146, 192, - 131, - 203, - 76, - 187, - 140, - 204, - 3, + 134, + 236, + 93, + 146, + 14, + 103, + 147, + 231, + 103, + 216, + 7, + 110, + 141, + 70, + 108, + 212, + 159, + 159, + 39, + 183, + 67, + 24, + 246, + 194, + 153, + 215, ], "type": "Buffer", }, @@ -702,7 +702,7 @@ KernelCircuitPublicInputs { "isFeePaymentTx": false, "isRebatePaymentTx": false, "version": Fr { - "asBigInt": 0n, + "asBigInt": 1n, "asBuffer": { "data": [ 0, @@ -736,7 +736,7 @@ KernelCircuitPublicInputs { 0, 0, 0, - 0, + 1, ], "type": "Buffer", }, @@ -972,7 +972,7 @@ KernelCircuitPublicInputs { }, "encryptedLogsHash": [ Fr { - "asBigInt": 116881760094330735023399760917603536324n, + "asBigInt": 120473220418664237265653431576962926917n, "asBuffer": { "data": [ 0, @@ -991,28 +991,28 @@ KernelCircuitPublicInputs { 0, 0, 0, - 87, - 238, - 155, - 177, - 38, - 64, - 133, - 236, - 244, + 90, + 162, + 76, + 91, + 110, + 2, + 154, + 223, 186, - 130, - 116, - 178, - 51, - 205, - 196, + 105, + 154, + 203, + 110, + 138, + 9, + 69, ], "type": "Buffer", }, }, Fr { - "asBigInt": 184145148802329932417389828290829878776n, + "asBigInt": 180349442177515303320141638055784967680n, "asBuffer": { "data": [ 0, @@ -1031,22 +1031,22 @@ KernelCircuitPublicInputs { 0, 0, 0, - 138, - 137, - 16, - 204, - 107, - 147, - 180, + 135, + 174, + 10, + 3, + 101, + 105, + 244, + 51, + 139, + 102, + 231, + 79, 57, - 154, - 30, - 189, - 143, - 191, - 180, - 5, - 248, + 29, + 110, + 0, ], "type": "Buffer", }, @@ -1055,7 +1055,7 @@ KernelCircuitPublicInputs { "newCommitments": [ SideEffect { "counter": Fr { - "asBigInt": 0n, + "asBigInt": 3n, "asBuffer": { "data": [ 0, @@ -1089,47 +1089,47 @@ KernelCircuitPublicInputs { 0, 0, 0, - 0, + 3, ], "type": "Buffer", }, }, "value": Fr { - "asBigInt": 8240305160289019381083256608879877337799989644951984162356314972952353509340n, + "asBigInt": 4250178692161300648335692630634107512801639993593719645811608162083278411334n, "asBuffer": { "data": [ - 18, - 55, - 216, - 241, - 215, - 66, - 41, - 46, + 9, + 101, + 132, + 17, + 119, 0, - 125, - 4, - 230, - 109, - 173, - 105, - 145, - 109, - 210, - 57, - 161, - 19, - 69, - 62, - 207, - 135, - 242, - 27, + 158, + 5, + 144, + 223, + 22, + 216, + 29, + 97, + 16, + 78, + 209, + 183, + 192, + 126, + 83, + 25, + 28, + 253, + 243, + 100, + 48, + 3, + 85, + 151, + 214, 70, - 147, - 51, - 15, - 220, ], "type": "Buffer", }, @@ -6305,81 +6305,81 @@ KernelCircuitPublicInputs { "newContracts": [ NewContractData { "contractAddress": AztecAddress { - "asBigInt": 17136208615489370595324712951074318609059907391564891634353187633922419015940n, + "asBigInt": 10322537727899308771904012032333545782539712384974956048990598232687118880488n, "asBuffer": { "data": [ - 37, - 226, + 22, + 210, + 89, + 108, + 79, + 109, + 231, + 137, + 96, + 251, 192, - 23, - 245, + 216, + 208, + 145, + 85, + 178, 218, - 31, - 153, - 68, - 1, - 230, - 29, - 38, - 190, - 67, - 94, - 60, - 250, - 38, - 239, - 238, + 71, + 93, + 225, + 180, 120, - 76, + 185, + 218, 107, - 78, - 148, - 127, - 118, - 81, - 189, - 65, - 4, + 134, + 97, + 80, + 151, + 119, + 142, + 232, ], "type": "Buffer", }, }, "functionTreeRoot": Fr { - "asBigInt": 5733828181279984846924392032049330885938310333906649337231112228024374578179n, + "asBigInt": 5586268305277371185225261204085928914807606659970509385734366170410186349015n, "asBuffer": { "data": [ 12, - 173, - 59, - 83, - 145, - 228, - 10, - 248, - 116, - 62, - 16, - 83, - 192, - 21, - 225, - 106, - 186, - 198, - 16, - 10, - 139, - 145, - 117, - 18, + 89, + 183, + 63, + 146, 192, - 131, - 203, - 76, - 187, - 140, - 204, - 3, + 134, + 236, + 93, + 146, + 14, + 103, + 147, + 231, + 103, + 216, + 7, + 110, + 141, + 70, + 108, + 212, + 159, + 159, + 39, + 183, + 67, + 24, + 246, + 194, + 153, + 215, ], "type": "Buffer", }, @@ -6578,41 +6578,41 @@ KernelCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 2567833015098009695197683741929052765845567165156134398536953771337640275556n, + "asBigInt": 18557487041571647491253465533783572374900896515498607932207140777586604671909n, "asBuffer": { "data": [ - 5, - 173, - 87, - 140, - 34, - 169, - 107, - 104, - 191, - 247, - 76, - 132, - 57, - 231, - 109, - 208, - 71, - 246, - 205, - 22, - 148, - 50, - 20, - 219, - 39, + 41, + 7, + 42, + 90, + 194, + 77, + 156, + 63, + 252, + 37, + 82, 232, - 4, - 177, - 237, - 31, - 110, - 100, + 93, + 21, + 12, + 242, + 143, + 127, + 185, + 50, + 149, + 74, + 152, + 156, + 67, + 116, + 134, + 133, + 193, + 68, + 131, + 165, ], "type": "Buffer", }, @@ -6620,7 +6620,7 @@ KernelCircuitPublicInputs { }, SideEffectLinkedToNoteHash { "counter": Fr { - "asBigInt": 0n, + "asBigInt": 2n, "asBuffer": { "data": [ 0, @@ -6654,7 +6654,7 @@ KernelCircuitPublicInputs { 0, 0, 0, - 0, + 2, ], "type": "Buffer", }, @@ -6700,41 +6700,41 @@ KernelCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 131391450486342918604555900920288880952936359657946230216264970318333633026n, + "asBigInt": 16438423491489947124784078749911006131636547378036801833088015732454017068948n, "asBuffer": { "data": [ - 0, - 74, - 93, - 107, - 195, - 78, - 132, - 197, - 163, - 215, - 166, - 37, - 163, - 119, - 47, - 77, - 47, - 132, - 199, - 212, - 102, + 36, + 87, + 209, + 103, + 56, + 238, + 159, + 64, + 115, + 209, + 45, + 49, + 126, + 57, + 144, + 193, + 142, + 185, + 198, + 82, + 3, + 123, + 214, + 169, + 181, + 205, + 88, + 198, 55, - 105, - 30, - 246, - 78, - 226, - 113, - 30, - 108, - 98, - 2, + 33, + 239, + 148, ], "type": "Buffer", }, @@ -6822,41 +6822,41 @@ KernelCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 11322578994265849565401386951246010528140686424276775038536393177707801557130n, + "asBigInt": 428170714625336957264161727950592097398222784351822461854326875949878503109n, "asBuffer": { "data": [ - 25, - 8, - 90, - 68, - 120, - 196, - 170, - 57, - 148, - 212, - 165, - 147, - 94, - 175, - 94, - 13, - 88, - 114, - 106, - 117, - 141, - 57, - 138, + 0, + 242, + 86, + 6, + 123, + 121, + 171, + 124, + 214, + 109, 151, - 246, + 205, + 113, + 122, 52, - 223, - 34, - 211, - 61, - 56, - 138, + 127, + 63, + 219, + 103, + 94, + 131, + 233, + 251, + 176, + 206, + 215, + 44, + 137, + 41, + 216, + 102, + 197, ], "type": "Buffer", }, @@ -14305,9 +14305,9 @@ KernelCircuitPublicInputs { }, }, ], - "optionallyRevealedData": [ - OptionallyRevealedData { - "callStackItemHash": Fr { + "nullifierKeyValidationRequests": [ + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14347,46 +14347,90 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "vkHash": Fr { + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14427,8 +14471,8 @@ KernelCircuitPublicInputs { }, }, }, - OptionallyRevealedData { - "callStackItemHash": Fr { + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14468,20 +14512,92 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "secretKey": Fq { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -14503,11 +14619,313 @@ KernelCircuitPublicInputs { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14548,6 +14966,8 @@ KernelCircuitPublicInputs { }, }, }, + ], + "optionallyRevealedData": [ OptionallyRevealedData { "callStackItemHash": Fr { "asBigInt": 0n, @@ -14790,92 +15210,8 @@ KernelCircuitPublicInputs { }, }, }, - ], - "privateCallStack": [ - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + OptionallyRevealedData { + "callStackItemHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14915,7 +15251,46 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "calledFromL1": false, + "calledFromPublicL2": false, + "functionData": FunctionData { + "isConstructor": false, + "isInternal": false, + "isPrivate": false, + "selector": FunctionSelector { + "value": 0, + }, + }, + "payFeeFromL1": false, + "payFeeFromPublicL2": false, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "vkHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14955,7 +15330,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + OptionallyRevealedData { + "callStackItemHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14995,7 +15372,46 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "calledFromL1": false, + "calledFromPublicL2": false, + "functionData": FunctionData { + "isConstructor": false, + "isInternal": false, + "isPrivate": false, + "selector": FunctionSelector { + "value": 0, + }, + }, + "payFeeFromL1": false, + "payFeeFromPublicL2": false, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "vkHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15036,6 +15452,8 @@ KernelCircuitPublicInputs { }, }, }, + ], + "privateCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -16744,8 +17162,6 @@ KernelCircuitPublicInputs { }, }, }, - ], - "publicCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -16990,6 +17406,8 @@ KernelCircuitPublicInputs { }, }, }, + ], + "publicCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -18698,10 +19116,90 @@ KernelCircuitPublicInputs { }, }, }, - ], - "publicDataReads": [ - PublicDataRead { - "leafSlot": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18741,8 +19239,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18782,9 +19279,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - PublicDataRead { - "leafSlot": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18824,8 +19319,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18866,6 +19360,8 @@ KernelCircuitPublicInputs { }, }, }, + ], + "publicDataReads": [ PublicDataRead { "leafSlot": Fr { "asBigInt": 0n, @@ -20028,9 +20524,7 @@ KernelCircuitPublicInputs { }, }, }, - ], - "publicDataUpdateRequests": [ - PublicDataUpdateRequest { + PublicDataRead { "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { @@ -20071,47 +20565,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "oldValue": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20151,9 +20606,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { + PublicDataRead { "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { @@ -20194,47 +20648,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "oldValue": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20274,8 +20689,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, + ], + "publicDataUpdateRequests": [ PublicDataUpdateRequest { "leafSlot": Fr { "asBigInt": 0n, @@ -21998,50 +22414,8 @@ KernelCircuitPublicInputs { }, "sideEffectCounter": undefined, }, - ], - "readRequests": [ - SideEffect { - "counter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "value": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22081,9 +22455,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22123,7 +22495,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "oldValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22163,9 +22535,299 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "newValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "oldValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "sideEffectCounter": undefined, + }, + ], + "readRequests": [ + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32629,121 +33291,121 @@ KernelCircuitPublicInputs { "constants": CombinedConstantData { "blockHeader": BlockHeader { "archiveRoot": Fr { - "asBigInt": 20372018159471621712773206616781399243089284083897629004165638733497278836368n, + "asBigInt": 10158515181242313771272129266142503619553755184795631153806639415695924753064n, "asBuffer": { "data": [ - 45, - 10, - 39, - 86, - 151, - 28, - 147, - 221, - 193, - 180, + 22, + 117, + 132, + 13, + 235, + 208, + 214, + 90, + 177, + 75, + 34, + 241, + 226, + 46, + 102, 251, - 133, - 176, - 163, - 143, - 86, - 29, - 222, - 109, - 190, - 209, - 92, - 25, - 252, - 185, + 8, + 249, + 108, + 6, + 201, + 62, 2, + 137, + 233, 148, - 253, - 230, - 102, - 174, - 144, + 20, + 219, + 108, + 223, + 114, + 168, ], "type": "Buffer", }, }, "contractTreeRoot": Fr { - "asBigInt": 14917511466805779502198250944232247270950372922289035175844919622811814316704n, + "asBigInt": 6568415749042037984926757810931669596906945004802041565559932650144630077823n, "asBuffer": { "data": [ - 32, - 251, - 3, - 36, - 219, - 51, - 241, - 141, + 14, + 133, + 151, 112, - 62, - 65, - 78, - 49, - 138, - 228, - 237, - 96, + 247, + 88, + 33, + 185, + 132, + 119, 212, - 126, - 208, - 2, - 74, - 124, - 46, - 56, - 24, - 184, - 115, + 186, + 166, + 150, + 10, + 23, + 35, 169, - 153, - 202, - 160, + 142, + 209, + 176, + 118, + 188, + 77, + 74, + 183, + 69, + 108, + 237, + 224, + 121, + 127, ], "type": "Buffer", }, }, "globalVariablesHash": Fr { - "asBigInt": 2339684137567523517345226739343572726453743526214691264476956870525775001728n, + "asBigInt": 4957651144733684399923001854900234304058969119810162343440706384384366996898n, "asBuffer": { "data": [ - 5, - 44, - 54, - 219, - 239, - 243, - 182, - 206, - 85, - 90, - 124, - 142, - 224, - 106, - 84, - 231, - 191, - 155, - 56, + 10, + 245, + 238, + 93, 48, - 46, - 91, - 242, - 101, - 182, - 41, - 102, - 190, + 169, + 141, + 160, + 245, + 57, + 42, + 98, + 45, + 69, + 103, + 95, + 1, 62, - 204, - 56, - 128, + 64, + 164, + 141, + 169, + 183, + 138, + 25, + 234, + 183, + 51, + 143, + 83, + 237, + 162, ], "type": "Buffer", }, @@ -32789,81 +33451,81 @@ KernelCircuitPublicInputs { }, }, "noteHashTreeRoot": Fr { - "asBigInt": 981923962123739841860000837864904074407773873785560232542331187019926149423n, + "asBigInt": 21096372356742043613143668548970006127383930024852699713566094163642473651418n, "asBuffer": { "data": [ - 2, - 43, - 191, - 207, - 255, - 135, - 229, - 206, - 199, - 96, - 16, - 217, - 240, + 46, + 164, 31, - 71, - 249, - 233, - 174, - 64, - 191, - 114, - 239, - 27, - 52, - 163, - 196, - 167, - 143, - 3, - 163, - 25, - 47, + 165, + 7, + 55, + 231, + 190, + 240, + 216, + 74, + 67, + 190, + 145, + 170, + 244, + 134, + 250, + 103, + 201, + 24, + 137, + 127, + 246, + 213, + 201, + 80, + 231, + 90, + 30, + 28, + 218, ], "type": "Buffer", }, }, "nullifierTreeRoot": Fr { - "asBigInt": 13649330571405803453188645801233118952397925720323129467963581146586569980764n, + "asBigInt": 3854537502129371887220012912461119183373952203973454068004402307982707681096n, "asBuffer": { "data": [ - 30, - 45, - 63, - 81, - 21, - 13, - 218, - 53, - 98, - 33, - 245, - 88, - 96, - 244, - 62, - 153, - 244, - 25, - 156, - 226, - 242, - 63, - 191, - 240, - 25, + 8, + 133, + 151, + 70, + 28, + 10, + 140, + 109, + 207, + 34, + 217, + 106, + 254, 13, - 33, - 222, - 114, - 251, - 59, - 92, + 167, + 170, + 49, + 77, + 141, + 11, + 248, + 0, + 119, + 158, + 250, + 87, + 11, + 2, + 93, + 168, + 103, + 72, ], "type": "Buffer", }, @@ -33222,57 +33884,528 @@ KernelCircuitPublicInputs { }, }, }, - "isContractDeploymentTx": false, - "isFeePaymentTx": false, - "isRebatePaymentTx": false, - "version": Fr { - "asBigInt": 1n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - ], - "type": "Buffer", - }, - }, - }, - }, - "end": CombinedAccumulatedData { - "aggregationObject": AggregationObject { - "hasData": false, - "p0": G1AffineElement { - "x": Fq { - "asBigInt": 1n, + "isContractDeploymentTx": false, + "isFeePaymentTx": false, + "isRebatePaymentTx": false, + "version": Fr { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ], + "type": "Buffer", + }, + }, + }, + }, + "end": CombinedAccumulatedData { + "aggregationObject": AggregationObject { + "hasData": false, + "p0": G1AffineElement { + "x": Fq { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ], + "type": "Buffer", + }, + }, + "y": Fq { + "asBigInt": 2n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + ], + "type": "Buffer", + }, + }, + }, + "p1": G1AffineElement { + "x": Fq { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ], + "type": "Buffer", + }, + }, + "y": Fq { + "asBigInt": 2n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + ], + "type": "Buffer", + }, + }, + }, + "proofWitnessIndices": [ + 3027, + 3028, + 3029, + 3030, + 3031, + 3032, + 3033, + 3034, + 3035, + 3036, + 3037, + 3038, + 3039, + 3040, + 3041, + 3042, + ], + "publicInputs": [], + }, + "encryptedLogPreimagesLength": Fr { + "asBigInt": 12n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 12, + ], + "type": "Buffer", + }, + }, + "encryptedLogsHash": [ + Fr { + "asBigInt": 10654334908029642268226261618939201427n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 3, + 243, + 68, + 123, + 49, + 16, + 181, + 87, + 150, + 38, + 199, + 134, + 29, + 7, + 147, + ], + "type": "Buffer", + }, + }, + Fr { + "asBigInt": 133338275028334099210129003420909668908n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 100, + 80, + 4, + 133, + 110, + 109, + 121, + 70, + 184, + 235, + 48, + 170, + 28, + 9, + 138, + 44, + ], + "type": "Buffer", + }, + }, + ], + "newCommitments": [ + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -33306,13 +34439,13 @@ KernelCircuitPublicInputs { 0, 0, 0, - 1, + 0, ], "type": "Buffer", }, }, - "y": Fq { - "asBigInt": 2n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -33346,15 +34479,15 @@ KernelCircuitPublicInputs { 0, 0, 0, - 2, + 0, ], "type": "Buffer", }, }, }, - "p1": G1AffineElement { - "x": Fq { - "asBigInt": 1n, + SideEffect { + "counter": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -33388,13 +34521,13 @@ KernelCircuitPublicInputs { 0, 0, 0, - 1, + 0, ], "type": "Buffer", }, }, - "y": Fq { - "asBigInt": 2n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -33428,155 +34561,12 @@ KernelCircuitPublicInputs { 0, 0, 0, - 2, + 0, ], "type": "Buffer", }, }, }, - "proofWitnessIndices": [ - 3027, - 3028, - 3029, - 3030, - 3031, - 3032, - 3033, - 3034, - 3035, - 3036, - 3037, - 3038, - 3039, - 3040, - 3041, - 3042, - ], - "publicInputs": [], - }, - "encryptedLogPreimagesLength": Fr { - "asBigInt": 12n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 12, - ], - "type": "Buffer", - }, - }, - "encryptedLogsHash": [ - Fr { - "asBigInt": 10654334908029642268226261618939201427n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 8, - 3, - 243, - 68, - 123, - 49, - 16, - 181, - 87, - 150, - 38, - 199, - 134, - 29, - 7, - 147, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 133338275028334099210129003420909668908n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 100, - 80, - 4, - 133, - 110, - 109, - 121, - 70, - 184, - 235, - 48, - 170, - 28, - 9, - 138, - 44, - ], - "type": "Buffer", - }, - }, - ], - "newCommitments": [ SideEffect { "counter": Fr { "asBigInt": 0n, @@ -38497,8 +39487,10 @@ KernelCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ], + "newContracts": [ + NewContractData { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38538,7 +39530,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "functionTreeRoot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38578,8 +39570,119 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, }, - SideEffect { + ], + "newL2ToL1Msgs": [ + Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + ], + "newNullifiers": [ + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -38620,7 +39723,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38660,8 +39763,48 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "value": Fr { + "asBigInt": 21656661793333488699623133973291552050691035067334656041912224559552713545549n, + "asBuffer": { + "data": [ + 47, + 225, + 60, + 119, + 69, + 155, + 37, + 42, + 3, + 220, + 241, + 1, + 152, + 254, + 157, + 61, + 59, + 245, + 157, + 115, + 204, + 170, + 245, + 90, + 152, + 97, + 100, + 174, + 46, + 73, + 87, + 77, + ], + "type": "Buffer", + }, + }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -38702,7 +39845,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38742,9 +39885,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38784,7 +39925,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38824,11 +39967,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - ], - "newContracts": [ - NewContractData { - "contractAddress": AztecAddress { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38868,7 +40007,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "functionTreeRoot": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -38908,8 +40047,11 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "portalContractAddress": EthAddress { - "buffer": { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -38931,97 +40073,23 @@ KernelCircuitPublicInputs { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - }, - ], - "newL2ToL1Msgs": [ - Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - ], - "newNullifiers": [ - SideEffectLinkedToNoteHash { - "counter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -39061,7 +40129,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -39101,46 +40169,6 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { - "asBigInt": 6829908051101542233177273165904445376377164813196839000974832044882663163261n, - "asBuffer": { - "data": [ - 15, - 25, - 151, - 73, - 132, - 139, - 131, - 68, - 116, - 226, - 229, - 188, - 245, - 21, - 243, - 85, - 158, - 211, - 129, - 202, - 99, - 245, - 133, - 199, - 248, - 228, - 115, - 65, - 249, - 201, - 197, - 125, - ], - "type": "Buffer", - }, - }, }, SideEffectLinkedToNoteHash { "counter": Fr { @@ -46462,8 +47490,10 @@ KernelCircuitPublicInputs { }, }, }, - SideEffectLinkedToNoteHash { - "counter": Fr { + ], + "nullifierKeyValidationRequests": [ + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46503,47 +47533,90 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46584,8 +47657,8 @@ KernelCircuitPublicInputs { }, }, }, - SideEffectLinkedToNoteHash { - "counter": Fr { + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46625,7 +47698,90 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46665,7 +47821,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46705,9 +47863,90 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46747,7 +47986,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -46787,7 +48028,90 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -65153,41 +66477,41 @@ KernelCircuitPublicInputsFinal { "constants": CombinedConstantData { "blockHeader": BlockHeader { "archiveRoot": Fr { - "asBigInt": 10561895175368852737061915973188839857007468377789560793687187642867659280638n, + "asBigInt": 11760689266673761585698609357698254380616683897751261211845848484095655455234n, "asBuffer": { "data": [ - 23, - 89, - 210, - 33, - 121, - 84, - 25, + 26, + 0, 80, - 63, - 134, - 192, - 50, - 232, - 248, - 118, - 47, - 43, - 115, - 158, - 116, - 131, + 113, + 164, + 135, + 228, + 137, + 23, + 135, + 7, + 58, + 145, 80, - 153, - 88, - 75, - 101, - 49, - 245, - 242, - 115, - 144, - 254, + 79, + 230, + 234, + 85, + 40, + 11, + 198, + 246, + 90, + 2, + 31, + 214, + 247, + 202, + 31, + 16, + 170, + 2, ], "type": "Buffer", }, @@ -65433,41 +66757,41 @@ KernelCircuitPublicInputsFinal { }, }, "publicDataTreeRoot": Fr { - "asBigInt": 5785871043333994658400733180052743689641713274194136017445890613179954325976n, + "asBigInt": 13940981882517738105981911020707002777955674699044852872880094407282064863456n, "asBuffer": { "data": [ - 12, - 202, - 175, - 220, - 156, - 53, - 55, - 67, - 151, - 13, + 30, + 210, + 80, + 237, + 115, + 219, + 110, + 112, + 128, + 92, 78, - 48, - 90, - 231, - 54, + 252, + 240, + 5, + 110, + 134, + 149, + 183, + 156, + 211, + 186, 65, - 206, - 105, - 79, - 7, - 219, - 103, - 136, - 109, - 39, - 105, - 201, - 237, - 136, - 233, - 105, - 216, + 142, + 130, + 124, + 24, + 77, + 238, + 108, + 111, + 176, + 224, ], "type": "Buffer", }, @@ -65475,7 +66799,7 @@ KernelCircuitPublicInputsFinal { }, "txContext": TxContext { "chainId": Fr { - "asBigInt": 0n, + "asBigInt": 31337n, "asBuffer": { "data": [ 0, @@ -65508,89 +66832,89 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 0, - 0, + 122, + 105, ], "type": "Buffer", }, }, "contractDeploymentData": ContractDeploymentData { "constructorVkHash": Fr { - "asBigInt": 4946902893997605007258693448883037341256770656195244398892734919432197304822n, + "asBigInt": 1583326240861609738393684596312518968005858067213923665222866669013140837326n, "asBuffer": { "data": [ - 10, - 239, - 217, - 10, - 105, - 166, - 67, - 50, - 76, - 123, - 240, - 169, + 3, + 128, + 33, + 130, + 79, 189, - 59, - 35, - 173, - 160, - 144, - 173, - 136, - 55, - 115, - 253, - 240, - 176, - 173, - 82, - 169, + 152, + 187, + 14, + 56, + 139, + 14, + 254, + 24, 247, - 214, - 241, - 246, + 46, + 147, + 80, + 247, + 69, + 100, + 129, + 113, + 69, + 57, + 186, + 88, + 61, + 227, + 113, + 19, + 206, ], "type": "Buffer", }, }, "contractAddressSalt": Fr { - "asBigInt": 13918524182926832455178861490988425129196887976468020413394338716458484696156n, + "asBigInt": 5715788628466014564753145955124535735977317413547751808173820928060130010488n, "asBuffer": { "data": [ - 30, - 197, - 155, - 3, - 19, - 250, + 12, + 163, + 5, + 143, + 94, + 10, + 226, + 248, + 9, + 137, + 101, 80, - 67, - 2, - 195, - 51, + 33, + 77, 111, - 201, - 17, - 214, - 136, - 237, - 174, - 103, - 196, - 251, - 242, - 41, - 214, - 140, - 127, - 54, - 237, - 135, - 151, - 4, - 92, + 184, + 200, + 96, + 243, + 132, + 162, + 245, + 72, + 217, + 95, + 220, + 148, + 193, + 176, + 199, + 37, + 120, ], "type": "Buffer", }, @@ -65598,122 +66922,122 @@ KernelCircuitPublicInputsFinal { "deployerPublicKey": Point { "kind": "point", "x": Fr { - "asBigInt": 13513162828633936749079339485623471377790691038584182237805001838837073529635n, + "asBigInt": 18040458897480127764142223692208684686831966101790881484314177406099286746304n, "asBuffer": { "data": [ - 29, - 224, - 45, - 218, - 202, - 198, - 210, - 244, 39, - 229, - 240, - 211, - 206, + 226, + 137, + 179, + 9, + 158, + 32, + 88, + 100, + 81, + 85, + 106, + 132, + 94, + 61, + 117, + 248, 89, - 215, - 41, + 187, 79, - 20, - 98, - 128, - 69, - 93, - 212, - 197, - 130, - 37, - 78, - 11, - 76, - 37, - 75, - 35, + 117, + 127, + 132, + 202, + 1, + 223, + 151, + 46, + 193, + 33, + 100, + 192, ], "type": "Buffer", }, }, "y": Fr { - "asBigInt": 16193209371316637857741102275574203818928254115376185574760513755303226932941n, + "asBigInt": 8351469406419082733708266903523540335749598199220619980033469638087926373102n, "asBuffer": { "data": [ - 35, - 205, - 8, - 29, - 254, - 156, - 13, - 24, - 115, - 182, - 90, - 54, + 18, + 118, + 195, 160, - 136, - 88, - 231, - 58, - 155, - 48, - 208, - 51, - 158, - 148, - 196, + 229, + 74, + 243, + 59, + 218, + 78, + 201, + 25, + 170, + 200, + 125, + 20, + 25, + 192, + 0, + 98, + 161, 145, - 93, - 113, - 16, - 226, - 240, - 126, - 205, + 42, + 19, + 10, + 221, + 248, + 170, + 135, + 60, + 90, + 238, ], "type": "Buffer", }, }, }, "functionTreeRoot": Fr { - "asBigInt": 5733828181279984846924392032049330885938310333906649337231112228024374578179n, + "asBigInt": 5586268305277371185225261204085928914807606659970509385734366170410186349015n, "asBuffer": { "data": [ 12, - 173, - 59, - 83, - 145, - 228, - 10, - 248, - 116, - 62, - 16, - 83, - 192, - 21, - 225, - 106, - 186, - 198, - 16, - 10, - 139, - 145, - 117, - 18, + 89, + 183, + 63, + 146, 192, - 131, - 203, - 76, - 187, - 140, - 204, - 3, + 134, + 236, + 93, + 146, + 14, + 103, + 147, + 231, + 103, + 216, + 7, + 110, + 141, + 70, + 108, + 212, + 159, + 159, + 39, + 183, + 67, + 24, + 246, + 194, + 153, + 215, ], "type": "Buffer", }, @@ -65750,7 +67074,7 @@ KernelCircuitPublicInputsFinal { "isFeePaymentTx": false, "isRebatePaymentTx": false, "version": Fr { - "asBigInt": 0n, + "asBigInt": 1n, "asBuffer": { "data": [ 0, @@ -65784,7 +67108,7 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 0, + 1, ], "type": "Buffer", }, @@ -66020,7 +67344,7 @@ KernelCircuitPublicInputsFinal { }, "encryptedLogsHash": [ Fr { - "asBigInt": 116881760094330735023399760917603536324n, + "asBigInt": 120473220418664237265653431576962926917n, "asBuffer": { "data": [ 0, @@ -66039,28 +67363,28 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 87, - 238, - 155, - 177, - 38, - 64, - 133, - 236, - 244, + 90, + 162, + 76, + 91, + 110, + 2, + 154, + 223, 186, - 130, - 116, - 178, - 51, - 205, - 196, + 105, + 154, + 203, + 110, + 138, + 9, + 69, ], "type": "Buffer", }, }, Fr { - "asBigInt": 184145148802329932417389828290829878776n, + "asBigInt": 180349442177515303320141638055784967680n, "asBuffer": { "data": [ 0, @@ -66079,22 +67403,22 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 138, - 137, - 16, - 204, - 107, - 147, - 180, + 135, + 174, + 10, + 3, + 101, + 105, + 244, + 51, + 139, + 102, + 231, + 79, 57, - 154, - 30, - 189, - 143, - 191, - 180, - 5, - 248, + 29, + 110, + 0, ], "type": "Buffer", }, @@ -66103,7 +67427,7 @@ KernelCircuitPublicInputsFinal { "newCommitments": [ SideEffect { "counter": Fr { - "asBigInt": 0n, + "asBigInt": 3n, "asBuffer": { "data": [ 0, @@ -66137,47 +67461,47 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 0, + 3, ], "type": "Buffer", }, }, "value": Fr { - "asBigInt": 12771775224118191483898915169603387229405021446030587347982956765852896294728n, + "asBigInt": 19405992485366774859947666833557573771278578023241022468020211386079897703171n, "asBuffer": { "data": [ - 28, - 60, - 145, - 144, 42, - 59, - 23, - 71, - 27, - 191, - 185, - 73, - 59, - 54, - 69, - 245, - 187, - 21, - 225, - 58, - 128, - 182, - 212, - 12, - 224, - 176, - 240, - 147, - 18, - 147, - 119, - 72, + 231, + 103, + 10, + 222, + 129, + 122, + 215, + 5, + 246, + 181, + 87, + 22, + 29, + 178, + 221, + 11, + 40, + 94, + 239, + 172, + 84, + 194, + 158, + 121, + 122, + 231, + 139, + 25, + 19, + 211, + 3, ], "type": "Buffer", }, @@ -71353,81 +72677,81 @@ KernelCircuitPublicInputsFinal { "newContracts": [ NewContractData { "contractAddress": AztecAddress { - "asBigInt": 17136208615489370595324712951074318609059907391564891634353187633922419015940n, + "asBigInt": 10322537727899308771904012032333545782539712384974956048990598232687118880488n, "asBuffer": { "data": [ - 37, - 226, + 22, + 210, + 89, + 108, + 79, + 109, + 231, + 137, + 96, + 251, 192, - 23, - 245, + 216, + 208, + 145, + 85, + 178, 218, - 31, - 153, - 68, - 1, - 230, - 29, - 38, - 190, - 67, - 94, - 60, - 250, - 38, - 239, - 238, + 71, + 93, + 225, + 180, 120, - 76, + 185, + 218, 107, - 78, - 148, - 127, - 118, - 81, - 189, - 65, - 4, + 134, + 97, + 80, + 151, + 119, + 142, + 232, ], "type": "Buffer", }, }, "functionTreeRoot": Fr { - "asBigInt": 5733828181279984846924392032049330885938310333906649337231112228024374578179n, + "asBigInt": 5586268305277371185225261204085928914807606659970509385734366170410186349015n, "asBuffer": { "data": [ 12, - 173, - 59, - 83, - 145, - 228, - 10, - 248, - 116, - 62, - 16, - 83, - 192, - 21, - 225, - 106, - 186, - 198, - 16, - 10, - 139, - 145, - 117, - 18, + 89, + 183, + 63, + 146, 192, - 131, - 203, - 76, - 187, - 140, - 204, - 3, + 134, + 236, + 93, + 146, + 14, + 103, + 147, + 231, + 103, + 216, + 7, + 110, + 141, + 70, + 108, + 212, + 159, + 159, + 39, + 183, + 67, + 24, + 246, + 194, + 153, + 215, ], "type": "Buffer", }, @@ -71626,41 +72950,41 @@ KernelCircuitPublicInputsFinal { }, }, "value": Fr { - "asBigInt": 11322578994265849565401386951246010528140686424276775038536393177707801557130n, + "asBigInt": 18557487041571647491253465533783572374900896515498607932207140777586604671909n, "asBuffer": { "data": [ - 25, - 8, + 41, + 7, + 42, 90, + 194, + 77, + 156, + 63, + 252, + 37, + 82, + 232, + 93, + 21, + 12, + 242, + 143, + 127, + 185, + 50, + 149, + 74, + 152, + 156, + 67, + 116, + 134, + 133, + 193, 68, - 120, - 196, - 170, - 57, - 148, - 212, + 131, 165, - 147, - 94, - 175, - 94, - 13, - 88, - 114, - 106, - 117, - 141, - 57, - 138, - 151, - 246, - 52, - 223, - 34, - 211, - 61, - 56, - 138, ], "type": "Buffer", }, @@ -71748,41 +73072,41 @@ KernelCircuitPublicInputsFinal { }, }, "value": Fr { - "asBigInt": 7094590644143379362066385400655107720501862419669243795306142485975929345465n, + "asBigInt": 428170714625336957264161727950592097398222784351822461854326875949878503109n, "asBuffer": { "data": [ - 15, - 175, - 101, - 96, - 137, - 229, - 168, - 211, - 33, - 182, - 79, - 66, - 15, - 192, - 8, 0, - 87, - 54, - 160, - 180, - 240, - 184, - 88, - 136, - 145, - 36, - 19, - 146, - 200, - 38, - 85, - 185, + 242, + 86, + 6, + 123, + 121, + 171, + 124, + 214, + 109, + 151, + 205, + 113, + 122, + 52, + 127, + 63, + 219, + 103, + 94, + 131, + 233, + 251, + 176, + 206, + 215, + 44, + 137, + 41, + 216, + 102, + 197, ], "type": "Buffer", }, @@ -71870,41 +73194,41 @@ KernelCircuitPublicInputsFinal { }, }, "value": Fr { - "asBigInt": 131391450486342918604555900920288880952936359657946230216264970318333633026n, + "asBigInt": 16438423491489947124784078749911006131636547378036801833088015732454017068948n, "asBuffer": { "data": [ - 0, - 74, - 93, - 107, - 195, - 78, - 132, - 197, - 163, - 215, - 166, - 37, - 163, - 119, - 47, - 77, - 47, - 132, - 199, - 212, - 102, + 36, + 87, + 209, + 103, + 56, + 238, + 159, + 64, + 115, + 209, + 45, + 49, + 126, + 57, + 144, + 193, + 142, + 185, + 198, + 82, + 3, + 123, + 214, + 169, + 181, + 205, + 88, + 198, 55, - 105, - 30, - 246, - 78, - 226, - 113, - 30, - 108, - 98, - 2, + 33, + 239, + 148, ], "type": "Buffer", }, diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr index 44f36ddbee9..3e0ce8bbe8a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr @@ -7,6 +7,7 @@ use dep::types::{ kernel_circuit_public_inputs::KernelCircuitPublicInputsBuilder, membership_witness::ReadRequestMembershipWitness, new_contract_data::NewContractData, + nullifier_key_validation_request::NullifierKeyValidationRequestContext, private_circuit_public_inputs::PrivateCircuitPublicInputs, private_kernel::private_call_data::PrivateCallData, previous_kernel_data::PreviousKernelData, @@ -20,7 +21,9 @@ use dep::types::{ MAX_NEW_COMMITMENTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, }, + grumpkin_private_key::GrumpkinPrivateKey, hash::{ compute_constructor_hash, compute_l2_to_l1_hash, @@ -28,6 +31,7 @@ use dep::types::{ compute_new_contract_address_hash, contract_tree_root_from_siblings, function_tree_root_from_siblings, + pedersen_hash, read_request_root_from_siblings, silo_commitment, silo_nullifier, @@ -41,7 +45,7 @@ use dep::types::{ }, bounded_vec::BoundedVec, }, - traits::is_empty_array, + traits::{is_empty, is_empty_array}, }; pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) { @@ -51,6 +55,7 @@ pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) { validate_array(app_public_inputs.return_values); validate_array(app_public_inputs.read_requests); + validate_array(app_public_inputs.nullifier_key_validation_requests); validate_array(app_public_inputs.new_commitments); validate_array(app_public_inputs.new_nullifiers); validate_array(app_public_inputs.private_call_stack_hashes); @@ -106,6 +111,7 @@ pub fn initialize_end_values( let start = previous_kernel.public_inputs.end; public_inputs.end.read_requests = array_to_bounded_vec(start.read_requests); + public_inputs.end.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); public_inputs.end.new_commitments = array_to_bounded_vec(start.new_commitments); public_inputs.end.new_nullifiers = array_to_bounded_vec(start.new_nullifiers); @@ -173,6 +179,8 @@ pub fn update_end_values(private_call: PrivateCallData, public_inputs: &mut Kern let read_requests = private_call_public_inputs.read_requests; let read_request_membership_witnesses = private_call.read_request_membership_witnesses; + let nullifier_key_validation_requests = private_call_public_inputs.nullifier_key_validation_requests; + let new_commitments = private_call_public_inputs.new_commitments; let new_nullifiers = private_call_public_inputs.new_nullifiers; @@ -192,6 +200,14 @@ pub fn update_end_values(private_call: PrivateCallData, public_inputs: &mut Kern } public_inputs.end.read_requests.push_vec(siloed_read_requests); + // Nullifier key validation requests. + for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL { + let request = nullifier_key_validation_requests[i]; + if !is_empty(request) { + public_inputs.end.nullifier_key_validation_requests.push(request.to_context(storage_contract_address)); + } + } + // Enhance commitments and nullifiers with domain separation whereby domain is the contract. // // nullifiers @@ -408,3 +424,28 @@ pub fn validate_call_against_request(private_call: PrivateCallData, request: Cal ); } } + +fn field_to_grumpkin_private_key(val: Field) -> GrumpkinPrivateKey { + let bytes = val.to_be_bytes(32); + let mut v = 1; + let mut high = 0; + let mut low = 0; + + for i in 0..16 { + high = high + (bytes[15 - i] as Field) * v; + low = low + (bytes[16 + 15 - i] as Field) * v; + v = v * 256; + } + + GrumpkinPrivateKey { high, low } +} + +pub fn compute_siloed_nullifier_secret_key(secret_key: GrumpkinPrivateKey, contract_address: AztecAddress) -> GrumpkinPrivateKey { + // TODO: Temporary hack. Should replace it with a secure way to derive the secret key. + // Match the way keys are derived in circuits.js/src/keys/index.ts + let hash = pedersen_hash( + [secret_key.high, secret_key.low, contract_address.to_field()], + 0 + ); + field_to_grumpkin_private_key(hash) +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr index 5b215d82971..77e9066ee18 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr @@ -124,10 +124,13 @@ mod tests { abis::{ complete_address::CompleteAddress, kernel_circuit_public_inputs::KernelCircuitPublicInputs, + nullifier_key_validation_request::NullifierKeyValidationRequest, private_kernel::private_call_data::PrivateCallData, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, }, address::AztecAddress, + grumpkin_point::GrumpkinPoint, + grumpkin_private_key::GrumpkinPrivateKey, hash::{ compute_constructor_hash, compute_logs_hash, @@ -619,4 +622,23 @@ mod tests { // non-transient read requests are NOT forwarded assert_eq(array_length(public_inputs.end.read_requests), MAX_READ_REQUESTS_PER_CALL); } + + #[test] + fn propagate_nullifier_key_validation_requests() { + let mut builder = PrivateKernelInitInputsBuilder::new_constructor(); + + let request = NullifierKeyValidationRequest { public_key: GrumpkinPoint { x: 1, y: 2 }, secret_key: GrumpkinPrivateKey { high: 3, low: 4 } }; + builder.private_call.public_inputs.nullifier_key_validation_requests.push(request); + + let public_inputs = builder.execute(); + + assert_eq(array_length(public_inputs.end.nullifier_key_validation_requests), 1); + + let request_context = public_inputs.end.nullifier_key_validation_requests[0]; + assert_eq(request_context.public_key, request.public_key); + assert_eq(request_context.secret_key, request.secret_key); + assert_eq( + request_context.contract_address, builder.private_call.public_inputs.call_context.storage_contract_address + ); + } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr index 8ba937ce90e..c937d43d832 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr @@ -1,10 +1,13 @@ use crate::common; -use dep::std::unsafe; -use dep::std::option::Option; -use dep::std::cmp::Eq; +use dep::std::{ + cmp::Eq, + option::Option, + unsafe, +}; use dep::types::{ abis::{ call_request::CallRequest, + nullifier_key_validation_request::NullifierKeyValidationRequestContext, previous_kernel_data::PreviousKernelData, kernel_circuit_public_inputs::{ KernelCircuitPublicInputsBuilder, @@ -16,7 +19,9 @@ use dep::types::{ MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, }, + grumpkin_private_key::GrumpkinPrivateKey, hash::{ compute_commitment_nonce, compute_unique_siloed_commitment, @@ -36,6 +41,7 @@ struct PrivateKernelInputsOrdering { sorted_new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], sorted_new_nullifiers_indexes: [u32; MAX_NEW_NULLIFIERS_PER_TX], nullifier_commitment_hints: [Field; MAX_NEW_NULLIFIERS_PER_TX], + master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], } impl PrivateKernelInputsOrdering { @@ -44,6 +50,24 @@ impl PrivateKernelInputsOrdering { "Private call stack must be empty when executing the ordering circuit"); } + fn validate_nullifier_keys(self, public_inputs: &mut KernelCircuitPublicInputsBuilder) { + let requests = self.previous_kernel.public_inputs.end.nullifier_key_validation_requests; + for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { + let request = requests[i]; + if !is_empty(request) { + let master_secret_key = self.master_nullifier_secret_keys[i]; + let computed_public_key = master_secret_key.derive_public_key(); + assert(computed_public_key.eq(request.public_key), "Cannot derive nullifier public key from the master key."); + + let computed_secret_key = common::compute_siloed_nullifier_secret_key(master_secret_key, request.contract_address); + assert(computed_secret_key.eq(request.secret_key), "Cannot derive siloed secret key from the master key."); + } + } + + // Empty out nullifier key validation requests after verifying them. + public_inputs.end.nullifier_key_validation_requests = BoundedVec::new(NullifierKeyValidationRequestContext::empty()); + } + fn match_reads_to_commitments(self, public_inputs: &mut KernelCircuitPublicInputsBuilder) { let new_commitments = public_inputs.end.new_commitments; let read_requests = public_inputs.end.read_requests; @@ -181,6 +205,8 @@ impl PrivateKernelInputsOrdering { // Do this before any functions can modify the inputs. common::initialize_end_values(self.previous_kernel, &mut public_inputs); + self.validate_nullifier_keys(&mut public_inputs); + self.sort_arrays(&mut public_inputs); self.match_reads_to_commitments(&mut public_inputs); @@ -312,6 +338,7 @@ mod tests { sorted_new_nullifiers, sorted_new_nullifiers_indexes, nullifier_commitment_hints: sorted_nullifier_commitment_hints, + master_nullifier_secret_keys: dep::std::unsafe::zeroed(), }; kernel.native_private_kernel_circuit_ordering() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr index 4a6579a2044..2b5b0e7f15f 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -648,7 +648,7 @@ mod tests { for i in 0..MAX_PUBLIC_DATA_WRITES_PER_TEST { if i < (public_data_writes.len() as u64) { - let (_, leaf): (u64, PublicDataTreeLeaf) = public_data_writes.get_unchecked(i as Field); + let leaf = public_data_writes.get_unchecked(i as Field).1; kernel_data.public_inputs.end.public_data_update_requests[i] = PublicDataUpdateRequest { leaf_slot : leaf.slot, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr index 55b17f76ecb..ee294cf94f1 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr @@ -14,6 +14,7 @@ mod contract_leaf_preimage; mod block_header; mod combined_constant_data; +mod nullifier_key_validation_request; mod public_data_read; mod public_data_update_request; mod optionally_revealed_data; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr index 3e5edcc91d0..7ada51b7a52 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr @@ -2,6 +2,7 @@ use crate::{ abis::{ call_request::CallRequest, new_contract_data::NewContractData, + nullifier_key_validation_request::NullifierKeyValidationRequestContext, optionally_revealed_data::OptionallyRevealedData, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, @@ -12,6 +13,7 @@ use crate::{ }; use crate::constants::{ MAX_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, @@ -28,6 +30,7 @@ struct CombinedAccumulatedData { aggregation_object: AggregationObject, read_requests: [SideEffect; MAX_READ_REQUESTS_PER_TX], + nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], new_commitments: [SideEffect; MAX_NEW_COMMITMENTS_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], @@ -79,6 +82,7 @@ struct CombinedAccumulatedDataBuilder { aggregation_object: AggregationObject, read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, new_commitments: BoundedVec, new_nullifiers: BoundedVec, @@ -110,6 +114,7 @@ impl CombinedAccumulatedDataBuilder { aggregation_object: self.aggregation_object, read_requests: self.read_requests.storage, + nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, @@ -136,6 +141,7 @@ impl CombinedAccumulatedDataBuilder { pub fn to_final(self) -> FinalAccumulatedData { assert_eq(self.read_requests.len, 0, "Final accumulated data: read requests not empty"); + assert_eq(self.nullifier_key_validation_requests.len, 0, "Final accumulated data: nullifier key validation requests not empty"); assert_eq(self.public_data_update_requests.len, 0, "Final accumulated data: public data update requests not empty"); assert_eq(self.public_data_reads.len, 0, "Final accumulated data: public data reads not empty"); diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr new file mode 100644 index 00000000000..190b477f8c7 --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr @@ -0,0 +1,101 @@ +use dep::std::cmp::Eq; +use crate::{ + address::AztecAddress, + traits::Empty, + grumpkin_point::GrumpkinPoint, + grumpkin_private_key::GrumpkinPrivateKey, +}; + +global NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN = 4; +global NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_SERIALIZED_LEN = 5; + +struct NullifierKeyValidationRequest { + public_key: GrumpkinPoint, + secret_key: GrumpkinPrivateKey, +} + +impl Eq for NullifierKeyValidationRequest { + fn eq(self, request: NullifierKeyValidationRequest) -> bool { + (request.public_key.eq(self.public_key)) + & (request.secret_key.eq(self.secret_key)) + } +} + +impl Empty for NullifierKeyValidationRequest { + fn empty() -> Self { + NullifierKeyValidationRequest { + public_key: GrumpkinPoint::zero(), + secret_key: GrumpkinPrivateKey::zero(), + } + } +} + +impl NullifierKeyValidationRequest { + pub fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN] { + [ + self.public_key.x, + self.public_key.y, + self.secret_key.high, + self.secret_key.low, + ] + } + + pub fn deserialise(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN]) -> Self { + Self { + public_key: GrumpkinPoint::new(fields[0], fields[1]), + secret_key: GrumpkinPrivateKey::new(fields[2], fields[3]), + } + } + + pub fn to_context(self, contract_address: AztecAddress) -> NullifierKeyValidationRequestContext { + NullifierKeyValidationRequestContext { + public_key: self.public_key, + secret_key: self.secret_key, + contract_address, + } + } +} + +struct NullifierKeyValidationRequestContext { + public_key: GrumpkinPoint, + secret_key: GrumpkinPrivateKey, + contract_address: AztecAddress, +} + +impl Eq for NullifierKeyValidationRequestContext { + fn eq(self, request: NullifierKeyValidationRequestContext) -> bool { + (request.public_key.eq(self.public_key)) + & (request.secret_key.eq(self.secret_key)) + & (request.contract_address.eq(self.contract_address)) + } +} + +impl Empty for NullifierKeyValidationRequestContext { + fn empty() -> Self { + NullifierKeyValidationRequestContext { + public_key: GrumpkinPoint::zero(), + secret_key: GrumpkinPrivateKey::zero(), + contract_address: AztecAddress::zero(), + } + } +} + +impl NullifierKeyValidationRequestContext { + pub fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_SERIALIZED_LEN] { + [ + self.public_key.x, + self.public_key.y, + self.secret_key.high, + self.secret_key.low, + self.contract_address.to_field(), + ] + } + + pub fn deserialise(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_SERIALIZED_LEN]) -> Self { + Self { + public_key: GrumpkinPoint::new(fields[0], fields[1]), + secret_key: GrumpkinPrivateKey::new(fields[2], fields[3]), + contract_address: AztecAddress::from_field(fields[4]), + } + } +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr index 85b208776d3..614eb54067c 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr @@ -2,6 +2,7 @@ use crate::{ abis::{ call_context::CallContext, block_header::BlockHeader, + nullifier_key_validation_request::NullifierKeyValidationRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, }, contrakt::deployment_data::ContractDeploymentData, @@ -12,6 +13,7 @@ use crate::{ }; use crate::constants::{ MAX_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, @@ -32,6 +34,7 @@ struct PrivateCircuitPublicInputs { return_values: [Field; RETURN_VALUES_LENGTH], read_requests: [SideEffect; MAX_READ_REQUESTS_PER_CALL], + nullifier_key_validation_requests: [NullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], new_commitments: [SideEffect; MAX_NEW_COMMITMENTS_PER_CALL], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_CALL], diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr index ae5fa0d5e19..ddb569c43cd 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr @@ -31,6 +31,7 @@ global MAX_NEW_L2_TO_L1_MSGS_PER_CALL: Field = 2; global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL: Field = 16; global MAX_PUBLIC_DATA_READS_PER_CALL: Field = 16; global MAX_READ_REQUESTS_PER_CALL: Field = 32; +global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL: Field = 1; // "PER TRANSACTION" CONSTANTS global MAX_NEW_COMMITMENTS_PER_TX: Field = 64; @@ -43,6 +44,7 @@ global MAX_PUBLIC_DATA_READS_PER_TX: Field = 16; global MAX_NEW_CONTRACTS_PER_TX: Field = 1; global MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX: Field = 4; global MAX_READ_REQUESTS_PER_TX: Field = 128; +global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX: Field = 4; global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: Field = 1; global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: Field = 1; // docs:end:constants @@ -108,7 +110,7 @@ global CONTRACT_STORAGE_READ_LENGTH: Field = 2; // Change this ONLY if you have changed the PublicCircuitPublicInputs structure. global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 190; global GET_NOTES_ORACLE_RETURN_LENGTH: Field = 674; -global CALL_PRIVATE_FUNCTION_RETURN_SIZE: Field = 195; +global CALL_PRIVATE_FUNCTION_RETURN_SIZE: Field = 199; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 87; global PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 177; global COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr index 364d19a1549..6afee7c4df0 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr @@ -1,3 +1,5 @@ +use dep::std::cmp::Eq; + global GRUMPKIN_POINT_SERIALIZED_LEN: Field = 2; struct GrumpkinPoint { @@ -5,6 +7,12 @@ struct GrumpkinPoint { y: Field, } +impl Eq for GrumpkinPoint { + fn eq(self, point: GrumpkinPoint) -> bool { + (point.x == self.x) & (point.y == self.y) + } +} + impl GrumpkinPoint { pub fn new(x: Field, y: Field) -> Self { Self { x, y } @@ -17,6 +25,10 @@ impl GrumpkinPoint { } } + pub fn is_zero(self) -> bool { + (self.x == 0) & (self.y == 0) + } + fn serialize(self) -> [Field; GRUMPKIN_POINT_SERIALIZED_LEN] { [self.x, self.y] } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr new file mode 100644 index 00000000000..b88381ee118 --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr @@ -0,0 +1,45 @@ +use dep::std::{ + cmp::Eq, + grumpkin_scalar::GrumpkinScalar, + grumpkin_scalar_mul::grumpkin_fixed_base, +}; +use crate::grumpkin_point::GrumpkinPoint; + +global GRUMPKIN_PRIVATE_KEY_SERIALIZED_LEN: Field = 2; + +struct GrumpkinPrivateKey { + high: Field, + low: Field, +} + +impl Eq for GrumpkinPrivateKey { + fn eq(self, key: GrumpkinPrivateKey) -> bool { + (key.high == self.high) & (key.low == self.low) + } +} + +impl GrumpkinPrivateKey { + pub fn new(high: Field, low: Field) -> Self { + GrumpkinPrivateKey { high, low } + } + + pub fn zero() -> Self { + Self { + high: 0, + low: 0, + } + } + + pub fn is_zero(self) -> bool { + (self.high == 0) & (self.low == 0) + } + + pub fn serialize(self) -> [Field; GRUMPKIN_PRIVATE_KEY_SERIALIZED_LEN] { + [self.high, self.low] + } + + pub fn derive_public_key(self) -> GrumpkinPoint { + let public_key = grumpkin_fixed_base(GrumpkinScalar { high: self.high, low: self.low }); + GrumpkinPoint { x: public_key[0], y: public_key[1] } + } +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr index 1c3c82c15f1..0bbcd8eecda 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/lib.nr @@ -1,6 +1,7 @@ mod utils; mod address; mod grumpkin_point; +mod grumpkin_private_key; // This is intentionally spelled like this // since contract is a reserved keyword, so it cannot // be used as an ident. diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 2d09777ef07..293e862a396 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -3,6 +3,7 @@ use crate::{ call_context::CallContext, complete_address::CompleteAddress, block_header::BlockHeader, + nullifier_key_validation_request::NullifierKeyValidationRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, }, @@ -16,6 +17,7 @@ use crate::{ }; use crate::constants::{ MAX_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, @@ -32,6 +34,7 @@ struct PrivateCircuitPublicInputsBuilder { return_values: BoundedVec, read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, new_commitments: BoundedVec, new_nullifiers: BoundedVec, @@ -112,6 +115,7 @@ impl PrivateCircuitPublicInputsBuilder { return_values: self.return_values.storage, read_requests: self.read_requests.storage, + nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, diff --git a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex new file mode 100644 index 00000000000..eb1a73f2ce3 --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex @@ -0,0 +1 @@ +16d2596c4f6de78960fbc0d8d09155b2da475de1b478b9da6b86615097778ee8af9f8c440001012e524f85d95e8fa38f77391385df385a7a1a918642efcbbc49ac3f12e0a2d6d600000127e289b3099e20586451556a845e3d75f859bb4f757f84ca01df972ec12164c01276c3a0e54af33bda4ec919aac87d1419c00062a1912a130addf8aa873c5aee038021824fbd98bb0e388b0efe18f72e9350f7456481714539ba583de37113ce0c59b73f92c086ec5d920e6793e767d8076e8d466cd49f9f27b74318f6c299d70ca3058f5e0ae2f809896550214d6fb8c860f384a2f548d95fdc94c1b0c7257800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000116d2596c4f6de78960fbc0d8d09155b2da475de1b478b9da6b86615097778ee8af9f8c44000101000000000000000000000000000000000000000000000000000000000000000016d2596c4f6de78960fbc0d8d09155b2da475de1b478b9da6b86615097778ee80000000000000000000000000000000000000000000000000000000000000000af9f8c44000001000000022e524f85d95e8fa38f77391385df385a7a1a918642efcbbc49ac3f12e0a2d6d600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000079d727c3024940dd1aa7a74c061ed27a8de22f4c464e7837a59c4b3f878c612000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000f0d91f67256590a414cfbb398de2bd00000000000000000000000000000000650871b6772a84d6f6f9ad61b862afd500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000000000000000000000000000000000f8000000000000000000000000000000000000000000000000000000000000000416642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb0bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f2781864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f801a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa0200000000000000000000000000000000000000000000000000000000000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d27e289b3099e20586451556a845e3d75f859bb4f757f84ca01df972ec12164c01276c3a0e54af33bda4ec919aac87d1419c00062a1912a130addf8aa873c5aee038021824fbd98bb0e388b0efe18f72e9350f7456481714539ba583de37113ce0c59b73f92c086ec5d920e6793e767d8076e8d466cd49f9f27b74318f6c299d70ca3058f5e0ae2f809896550214d6fb8c860f384a2f548d95fdc94c1b0c7257800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b1301bc5321eae0e761ecea83f7f3a4be7da44c1d5664b7574b029f7389c2f70795770e6b327df89fa57f0d476aa0e8b8fdffcb5f544c3a315abdbecdfab6312b5ac8eca3afd0371dddcc78379dc80d849682168c535ed170e776b0094270671815c075eca513bce742e9f29095020b3950373e725a18df06db0ae1ae74ec5a088e24f56e7369ae790a14d8ed7eec981cb1597f960c380345374b0f4c72b74a0c49057400ccf3c52b1da4b585fd0aa68a7ed28d714956c6d085b34a8733ce5d2ae9b2906669e826e5e376ce2ff3327b1e028867d50d4930f681e09874bfd1351ce17a75c19d9d6a2807761abcd228d0890acc38274beb0dea5154562365a02e166b40dd0be40ad157209f8056f2a608bf307850e4bb8da812643409faf5441e203ad62a41c8e7d3e07d3b614ed4ecb1543286061ddf0be411e7e96db5de72a10451503884f41c251ffb99a8c3256382f4d27093e3676b5e55032c13883d729514baec9c8829457251cb3442bb18caa4611c62f88277f82be8ba6e2c9da37eb3067009c9cdd247d1312c91a929629d0ed027ba5523f16d741791835a1ea73cdf0474e7d5f472577f7bab0198ff26249088d4cf5eccd14ed6e53352efd4c8363a199b635523c221dafb684a3a4d48da495293c72fb8396d41b919f0ac53c3735a1bf94004107944602259d6b068468ee5cac4897884f6d3be21444b2f33e7f34a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex index cf767299f91..89ad1f2ec0b 100644 --- a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex +++ b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex @@ -1 +1 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f199749848b834474e2e5bcf515f3559ed381ca63f585c7f8e47341f9c9c57d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c2c4914c4adc9d775bd7eeee09cc5a37fc71593bd318e6b486221e53ee87b911c94912f5dcbc89ea72a8a498cdf68c5b74512b32b5ebc27dfd044cde2c6369600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022bbfcfff87e5cec76010d9f01f47f9e9ae40bf72ef1b34a3c4a78f03a3192f1e2d3f51150dda356221f55860f43e99f4199ce2f23fbff0190d21de72fb3b5c20fb0324db33f18d703e414e318ae4ed60d47ed0024a7c2e3818b873a999caa01864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f802d0a2756971c93ddc1b4fb85b0a38f561dde6dbed15c19fcb90294fde666ae9000000000000000000000000000000000000000000000000000000000000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0052c36dbeff3b6ce555a7c8ee06a54e7bf9b38302e5bf265b62966be3ecc38800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000021f11a5439c373c3d91f5e4910a93aa16f061a642d7d2706be18a85ca84956d92fdcf6231c3596a614cfaa28a09bc402a7a34bf9382931cfed022a77d99f3c8825d97e44dac3772af165e47e72c0e495c079c18217001478c687ec883706c41d090f534a8ef74012c96f8b4b842a0107e0ab6b043ab130d394cdad8f21518c9e0906bca10001001c94912f5dcbc89ea72a8a498cdf68c5b74512b32b5ebc27dfd044cde2c63696090f534a8ef74012c96f8b4b842a0107e0ab6b043ab130d394cdad8f21518c9e00000000000000000000000000000000000000000000000000000000000000000906bca1000000000000021124bf00bac5cd7fc8570fe0e40c34b8d093801a155d53e0b478d960b3a424810000000000000000000000000000000000000000000000000000000000007a6a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004022bbfcfff87e5cec76010d9f01f47f9e9ae40bf72ef1b34a3c4a78f03a3192f1e2d3f51150dda356221f55860f43e99f4199ce2f23fbff0190d21de72fb3b5c20fb0324db33f18d703e414e318ae4ed60d47ed0024a7c2e3818b873a999caa01864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f802d0a2756971c93ddc1b4fb85b0a38f561dde6dbed15c19fcb90294fde666ae9000000000000000000000000000000000000000000000000000000000000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0052c36dbeff3b6ce555a7c8ee06a54e7bf9b38302e5bf265b62966be3ecc38800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000000000000000000000000000000000000000000000000000000000000722a1419dd08e208cd862bb66fb009fa540fb7178d01108f79eb78a891064685603f30687851ce0bc4df8e4fa8a5809643e9ae7f752a3ec1e3c120b251036c92e14ae899cd34041169f2476b70040373713d6eb363e74dca7f7f70f36d286b92f044b59fe1a64065611c9ec171fc760af4337fd13bbb833a9b021cfdde27a7f621a9fdb505152f9c2baaffe4a30ee80775b58ebf8c2dde76435835b085c6f70ca0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000027b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed0136d5c45fb886add133b29521494cbb3b13851ed146d0bfa6448d71dacb7c170bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa015d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f268ed1e1c94c3a45a14db4108bc306613a1c23fab68e0466a002dfb0a3f8d2ab0cd8d5695bc2dde99dd531671f76f1482f14ddba8eeca7cb9686d4a62359c257047fbb7eb974155702149e58ea6ad91f4c6e953e693db35e953e250d8ceac9a900c5ae2526e665e2c7c698c11a06098b7159f720606d50e7660deb55758b0b022ced19489ab456b8b6c424594cdbbae59c36dfdd4c4621c4032da2d8a9674be51df5a245ffc1da14b46fe56a605f2a47b1cff1592bab4f66cfe5dfe990af6ab52871d090615d14eadb52228c635c90e0adf31176f0814f6525c23e7d7b318c931a2b85ff013d4b2b25074297c7e44aa61f4836d0862b36db2e6ce2b5542f9ea9177b9a10bbee32f77c719c6f8d071a18476cbeb021e155c642bbf93c716ce94300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fe13c77459b252a03dcf10198fe9d3d3bf59d73ccaaf55a986164ae2e49574d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013342ec9b3ada56cd39725be22a81b6d98c50e21224698310d94275d598b93a10096732a5d448ecb65a295b6240ac087994c5ca64b9da239004ad7a8b49e8c6200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb2000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ea41fa50737e7bef0d84a43be91aaf486fa67c918897ff6d5c950e75a1e1cda088597461c0a8c6dcf22d96afe0da7aa314d8d0bf800779efa570b025da867480e859770f75821b98477d4baa6960a1723a98ed1b076bc4d4ab7456cede0797f1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f801675840debd0d65ab14b22f1e22e66fb08f96c06c93e0289e99414db6cdf72a800000000000000000000000000000000000000000000000000000000000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e00af5ee5d30a98da0f5392a622d45675f013e40a48da9b78a19eab7338f53eda20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002ef02854e1cd336c9781167973c2650a4afa61b3bc29a24d854b7344c0fcbcc218d8ccd26bc265098021e3d3460534dc9549563a0d60bd9647177abed77e78e815b022a028c19417864ca9fa91ecc53ea55dac9c85dd5f2850b99e0986505c381fe48c5f818c1bc15f37f9014b5d80b345bbc6f4fceeb3189b25ed525b52369f0906bca10001000096732a5d448ecb65a295b6240ac087994c5ca64b9da239004ad7a8b49e8c621fe48c5f818c1bc15f37f9014b5d80b345bbc6f4fceeb3189b25ed525b52369f00000000000000000000000000000000000000000000000000000000000000000906bca1000000000000031124bf00bac5cd7fc8570fe0e40c34b8d093801a155d53e0b478d960b3a424810000000000000000000000000000000000000000000000000000000000007a6a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000042ea41fa50737e7bef0d84a43be91aaf486fa67c918897ff6d5c950e75a1e1cda088597461c0a8c6dcf22d96afe0da7aa314d8d0bf800779efa570b025da867480e859770f75821b98477d4baa6960a1723a98ed1b076bc4d4ab7456cede0797f1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f801675840debd0d65ab14b22f1e22e66fb08f96c06c93e0289e99414db6cdf72a800000000000000000000000000000000000000000000000000000000000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e00af5ee5d30a98da0f5392a622d45675f013e40a48da9b78a19eab7338f53eda20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000000000000000000000000000000000000000000000000000000000004117957eae867c3a73358ea71d42be6920041849595ce05bf5b2067fb52d854772d6e08f4bcb48e1725e18fb89faa36164b86f5ed9d8825e33389d2d63ea5f54211a8166baa0849ba660891d24d5cf2a1b3edefe030b60b55a31180ce1d7f7c2a0803aa8ad8a2355c621c88da55b38f2c2ff74855db99adf11e9caf517a0177321a9fdb505152f9c2baaffe4a30ee80775b58ebf8c2dde76435835b085c6f70ca0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000027b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed14c17ee934da7e9640962565bea1610b3f22dee4a2b7fc337c33894261bad3430bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa015d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f268ed1e1c94c3a45a14db4108bc306613a1c23fab68e0466a002dfb0a3f8d2ab0cd8d5695bc2dde99dd531671f76f1482f14ddba8eeca7cb9686d4a62359c257047fbb7eb974155702149e58ea6ad91f4c6e953e693db35e953e250d8ceac9a900c5ae2526e665e2c7c698c11a06098b7159f720606d50e7660deb55758b0b022ced19489ab456b8b6c424594cdbbae59c36dfdd4c4621c4032da2d8a9674be51df5a245ffc1da14b46fe56a605f2a47b1cff1592bab4f66cfe5dfe990af6ab52871d090615d14eadb52228c635c90e0adf31176f0814f6525c23e7d7b318c931a2b85ff013d4b2b25074297c7e44aa61f4836d0862b36db2e6ce2b5542f9ea9177b9a10bbee32f77c719c6f8d071a18476cbeb021e155c642bbf93c716ce94300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex new file mode 100644 index 00000000000..eacfd2fb52c --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex @@ -0,0 +1 @@ +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000965841177009e0590df16d81d61104ed1b7c07e53191cfdf36430035597d646000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029072a5ac24d9c3ffc2552e85d150cf28f7fb932954a989c43748685c14483a5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002457d16738ee9f4073d12d317e3990c18eb9c652037bd6a9b5cd58c63721ef940000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200f256067b79ab7cd66d97cd717a347f3fdb675e83e9fbb0ced72c8929d866c50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005aa24c5b6e029adfba699acb6e8a09450000000000000000000000000000000087ae0a036569f4338b66e74f391d6e00000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000000f8000000000000000000000000000000000000000000000000000000000000000416d2596c4f6de78960fbc0d8d09155b2da475de1b478b9da6b86615097778ee800000000000000000000000000000000000000000000000000000000000000000c59b73f92c086ec5d920e6793e767d8076e8d466cd49f9f27b74318f6c299d700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb0bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f2781864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f801a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa0200000000000000000000000000000000000000000000000000000000000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d00000127e289b3099e20586451556a845e3d75f859bb4f757f84ca01df972ec12164c01276c3a0e54af33bda4ec919aac87d1419c00062a1912a130addf8aa873c5aee038021824fbd98bb0e388b0efe18f72e9350f7456481714539ba583de37113ce0c59b73f92c086ec5d920e6793e767d8076e8d466cd49f9f27b74318f6c299d70ca3058f5e0ae2f809896550214d6fb8c860f384a2f548d95fdc94c1b0c7257800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000001d86f35530ce6e4503b61ca79a0bc9478cdb17197ccccbdccc9de7a9fc938d172b2cc343733e841e9f9f645a5c8ffd45233353cf0f8b86b4f77e7368496954f9063894ea629fc50bde88d48566bcfa398bdd69eccb13e38936364f477218336c0965841177009e0590df16d81d61104ed1b7c07e53191cfdf36430035597d6460000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029072a5ac24d9c3ffc2552e85d150cf28f7fb932954a989c43748685c14483a50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f256067b79ab7cd66d97cd717a347f3fdb675e83e9fbb0ced72c8929d866c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012457d16738ee9f4073d12d317e3990c18eb9c652037bd6a9b5cd58c63721ef9400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000001000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits/src/index.test.ts b/yarn-project/noir-protocol-circuits/src/index.test.ts index 1be172d23ac..3fe9e1afbc3 100644 --- a/yarn-project/noir-protocol-circuits/src/index.test.ts +++ b/yarn-project/noir-protocol-circuits/src/index.test.ts @@ -1,60 +1,21 @@ import { - AggregationObject, AztecAddress, - BlockHeader, - CONTRACT_TREE_HEIGHT, - CallContext, - CallRequest, - CombinedAccumulatedData, - CombinedConstantData, ContractDeploymentData, EthAddress, - FUNCTION_TREE_HEIGHT, FunctionData, FunctionLeafPreimage, FunctionSelector, - KernelCircuitPublicInputs, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_READ_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_TX, - MembershipWitness, - NewContractData, - OptionallyRevealedData, Point, - PreviousKernelData, - PrivateCallData, - PrivateCallStackItem, - PrivateCircuitPublicInputs, PrivateKernelInputsInit, PrivateKernelInputsInner, PrivateKernelInputsOrdering, PublicCallStackItem, PublicCircuitPublicInputs, - PublicDataRead, - PublicDataUpdateRequest, - RETURN_VALUES_LENGTH, - ReadRequestMembershipWitness, SideEffect, - SideEffectLinkedToNoteHash, TxContext, TxRequest, - VK_TREE_HEIGHT, - VerificationKey, - makeEmptyProof, } from '@aztec/circuits.js'; import { computeCompleteAddress, computeFunctionLeaf, computeTxHash } from '@aztec/circuits.js/abis'; -import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { fileURLToPath } from '@aztec/foundation/url'; @@ -64,225 +25,31 @@ import { dirname, resolve } from 'path'; import { executeInit, executeInner, executeOrdering } from './index.js'; -function _makeEmptyReadRequest() { - return makeTuple(MAX_READ_REQUESTS_PER_TX, () => SideEffect.empty()); -} - describe('Private kernel', () => { let logger: DebugLogger; + beforeAll(() => { logger = createDebugLogger('noir-private-kernel'); }); - // Taken from e2e_nested_contract => performs nested calls => first deployment + // Taken from e2e_nested_contract => performs nested calls => first init (corresponds to deployment) + // To regenerate fixture data run the following on the yarn-project/e2e folder + // AZTEC_GENERATE_TEST_DATA=1 yarn test e2e_nested_contract -t 'performs nested calls' it('Executes private kernel init circuit for a contract deployment', async () => { logger('Initialized Noir instance with private kernel init circuit'); - const txOrigin = AztecAddress.fromString('0x25e2c017f5da1f994401e61d26be435e3cfa26efee784c6b4e947f7651bd4104'); - const argsHash = Fr.fromString('0x113c609cd625d5afd9f09daa2031011af161334e7508be0b1310ad2b7ff166af'); - const deployerPubKey = new Point( - Fr.fromString('0x1de02ddacac6d2f427e5f0d3ce59d7294f146280455dd4c582254e0b4c254b23'), - Fr.fromString('0x23cd081dfe9c0d1873b65a36a08858e73a9b30d0339e94c4915d7110e2f07ecd'), - ); - const contractDeploymentData = new ContractDeploymentData( - deployerPubKey, - Fr.fromString('0x0aefd90a69a643324c7bf0a9bd3b23ada090ad883773fdf0b0ad52a9f7d6f1f6'), - Fr.fromString('0x0cad3b5391e40af8743e1053c015e16abac6100a8b917512c083cb4cbb8ccc03'), - Fr.fromString('0x1ec59b0313fa504302c3336fc911d688edae67c4fbf229d68c7f36ed8797045c'), - EthAddress.ZERO, - ); - const selector = FunctionSelector.fromString('0xaf9f8c44'); - const functionData = new FunctionData(selector, false, true, true); - const txContext = new TxContext(false, false, true, contractDeploymentData, Fr.ZERO, Fr.ZERO); - const txRequest = new TxRequest(txOrigin, functionData, argsHash, txContext); - - const contractAddress = AztecAddress.fromString( - '0x25e2c017f5da1f994401e61d26be435e3cfa26efee784c6b4e947f7651bd4104', - ); - - const newCommitments = makeTuple(MAX_NEW_COMMITMENTS_PER_CALL, () => SideEffect.empty()); - newCommitments[0] = new SideEffect( - Fr.fromString('0x0aced88c953b70873e4a33dde4620dc43a709c15013c46c60d167de8e1c32315'), - Fr.ZERO, - ); - - const newNullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, () => SideEffectLinkedToNoteHash.empty()); - newNullifiers[0] = new SideEffectLinkedToNoteHash( - Fr.fromString('0x03579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa'), - Fr.ZERO, - Fr.ZERO, - ); - - const callContext = new CallContext(AztecAddress.ZERO, contractAddress, Fr.ZERO, selector, false, false, true, 0); - - const blockHeader = new BlockHeader( - Fr.fromString('0x16642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb'), - Fr.fromString('0x0bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278'), - Fr.fromString('0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80'), - Fr.fromString('0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80'), - Fr.fromString('0x1759d221795419503f86c032e8f8762f2b739e74835099584b6531f5f27390fe'), - Fr.ZERO, // TODO(#3441) - Fr.fromString('0x0ccaafdc9c353743970d4e305ae73641ce694f07db67886d2769c9ed88e969d8'), - Fr.fromString('0x200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d'), - ); - - const appPublicInputs = new PrivateCircuitPublicInputs( - callContext, - argsHash, - makeTuple(RETURN_VALUES_LENGTH, () => Fr.ZERO), - makeTuple(MAX_READ_REQUESTS_PER_CALL, () => SideEffect.empty()), - newCommitments, - newNullifiers, - makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, () => Fr.ZERO), - makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, () => Fr.ZERO), - makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, () => Fr.ZERO), - Fr.ZERO, - [Fr.fromString('0x9cc0744c0dde14f24854659b052ffb7e'), Fr.fromString('0x28120e19a5cc9ec344f3d6d41b6fada2')], - [Fr.fromString('0xe3b0c44298fc1c149afbf4c8996fb924'), Fr.fromString('0x27ae41e4649b934ca495991b7852b855')], - Fr.fromString('0xf8'), - Fr.fromString('0x04'), - blockHeader, - contractDeploymentData, - Fr.ZERO, - Fr.ZERO, - ); - - const callStackItem = new PrivateCallStackItem(contractAddress, functionData, appPublicInputs, false); + const filepath = resolve(dirname(fileURLToPath(import.meta.url)), './fixtures/nested-call-private-kernel-init.hex'); + const serialized = Buffer.from(readFileSync(filepath).toString(), 'hex'); + const kernelInputs = PrivateKernelInputsInit.fromBuffer(serialized); - const privateCall = new PrivateCallData( - callStackItem, - makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, () => CallRequest.empty()), - makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, () => CallRequest.empty()), - makeEmptyProof(), - VerificationKey.makeFake(), - MembershipWitness.empty(FUNCTION_TREE_HEIGHT, 0n), - MembershipWitness.empty(CONTRACT_TREE_HEIGHT, 0n), - makeTuple(MAX_READ_REQUESTS_PER_CALL, () => ReadRequestMembershipWitness.empty(0n)), - Fr.ZERO, - Fr.ZERO, - ); - const kernelInputs = new PrivateKernelInputsInit(txRequest, privateCall); + // We check that the test data is for a contract deployment + expect(kernelInputs.txRequest.txContext.isContractDeploymentTx).toBe(true); const kernelOutputs = await executeInit(kernelInputs); expect(kernelOutputs).toMatchSnapshot(); }); - // Taken from e2e_nested_contract => performs nested calls => first ordering - it('Executes private kernel ordering after a deployment', async () => { - const contractAddress = AztecAddress.fromString( - '0x25e2c017f5da1f994401e61d26be435e3cfa26efee784c6b4e947f7651bd4104', - ); - - const deployerPubKey = new Point( - Fr.fromString('0x1de02ddacac6d2f427e5f0d3ce59d7294f146280455dd4c582254e0b4c254b23'), - Fr.fromString('0x23cd081dfe9c0d1873b65a36a08858e73a9b30d0339e94c4915d7110e2f07ecd'), - ); - - const contractDeploymentData = new ContractDeploymentData( - deployerPubKey, - Fr.fromString('0x0aefd90a69a643324c7bf0a9bd3b23ada090ad883773fdf0b0ad52a9f7d6f1f6'), - Fr.fromString('0x0cad3b5391e40af8743e1053c015e16abac6100a8b917512c083cb4cbb8ccc03'), - Fr.fromString('0x1ec59b0313fa504302c3336fc911d688edae67c4fbf229d68c7f36ed8797045c'), - EthAddress.ZERO, - ); - const txContext = new TxContext(false, false, true, contractDeploymentData, Fr.ZERO, Fr.ZERO); - - const newCommitments = makeTuple(MAX_NEW_COMMITMENTS_PER_TX, () => SideEffect.empty()); - newCommitments[0] = new SideEffect( - Fr.fromString('0x0aced88c953b70873e4a33dde4620dc43a709c15013c46c60d167de8e1c32315'), - Fr.ZERO, - ); - - const newNullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, () => SideEffectLinkedToNoteHash.empty()); - const sortedNewNullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => newNullifiers[i]); - - newNullifiers[0] = new SideEffectLinkedToNoteHash( - Fr.fromString('0x0faf656089e5a8d321b64f420fc008005736a0b4f0b8588891241392c82655b9'), - Fr.ZERO, - new Fr(1), - ); - newNullifiers[1] = new SideEffectLinkedToNoteHash( - Fr.fromString('0x4a5d6bc34e84c5a3d7a625a3772f4d2f84c7d46637691ef64ee2711e6c6202'), - Fr.ZERO, - new Fr(2), - ); - newNullifiers[2] = new SideEffectLinkedToNoteHash( - Fr.fromString('0x19085a4478c4aa3994d4a5935eaf5e0d58726a758d398a97f634df22d33d388a'), - Fr.ZERO, - Fr.ZERO, - ); - - sortedNewNullifiers[0] = newNullifiers[2]; - sortedNewNullifiers[1] = newNullifiers[0]; - sortedNewNullifiers[2] = newNullifiers[1]; - - const sortedNewNullifiersIndexes = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => - sortedNewNullifiers.indexOf(newNullifiers[i]), - ); - - const combinedAccumulatedData = new CombinedAccumulatedData( - AggregationObject.makeFake(), - makeTuple(MAX_READ_REQUESTS_PER_TX, () => SideEffect.empty()), - newCommitments, - newNullifiers, - makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, () => CallRequest.empty()), - makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, () => CallRequest.empty()), - makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, () => new Fr(0n)), - [Fr.fromString('0x57ee9bb1264085ecf4ba8274b233cdc4'), Fr.fromString('0x8a8910cc6b93b4399a1ebd8fbfb405f8')], - [Fr.fromString('0x1c9ecec90e28d2461650418635878a5c'), Fr.fromString('0x91e49f47586ecf75f2b0cbb94e897112')], - Fr.fromString('0xf8'), - new Fr(4), - [ - new NewContractData( - contractAddress, - EthAddress.ZERO, - Fr.fromString('0x0cad3b5391e40af8743e1053c015e16abac6100a8b917512c083cb4cbb8ccc03'), - ), - ], - makeTuple(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, () => OptionallyRevealedData.empty()), - makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, () => PublicDataUpdateRequest.empty()), - makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PublicDataRead.empty()), - ); - - const blockHeader = new BlockHeader( - Fr.fromString('0x16642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb'), - Fr.fromString('0x0bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278'), - Fr.fromString('0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80'), - Fr.fromString('0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80'), - Fr.fromString('0x1759d221795419503f86c032e8f8762f2b739e74835099584b6531f5f27390fe'), - Fr.ZERO, // TODO(#3441) - Fr.fromString('0x0ccaafdc9c353743970d4e305ae73641ce694f07db67886d2769c9ed88e969d8'), - Fr.fromString('0x200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d'), - ); - - const constants = new CombinedConstantData(blockHeader, txContext); - - const kernelPublicInputs = new KernelCircuitPublicInputs(combinedAccumulatedData, constants, true); - - const previousKernelData = new PreviousKernelData( - kernelPublicInputs, - makeEmptyProof(), - VerificationKey.makeFake(), - 0, - makeTuple(VK_TREE_HEIGHT, () => Fr.ZERO), - ); - - const kernelInputs = new PrivateKernelInputsOrdering( - previousKernelData, - newCommitments, - makeTuple(MAX_NEW_COMMITMENTS_PER_TX, i => i), - makeTuple(MAX_READ_REQUESTS_PER_TX, () => Fr.ZERO), - sortedNewNullifiers, - sortedNewNullifiersIndexes, - makeTuple(MAX_NEW_NULLIFIERS_PER_TX, () => Fr.ZERO), - ); - - const kernelOutputs = await executeOrdering(kernelInputs); - - expect(kernelOutputs).toMatchSnapshot(); - }); - // Taken from e2e_nested_contract => performs nested calls => last inner // To regenerate fixture data run the following on the yarn-project/e2e folder // AZTEC_GENERATE_TEST_DATA=1 yarn test e2e_nested_contract -t 'performs nested calls' @@ -300,6 +67,22 @@ describe('Private kernel', () => { expect(kernelOutputs).toMatchSnapshot(); }); + + // Taken from e2e_nested_contract => performs nested calls => first ordering + // To regenerate fixture data run the following on the yarn-project/e2e folder + // AZTEC_GENERATE_TEST_DATA=1 yarn test e2e_nested_contract -t 'performs nested calls' + it('Executes private kernel ordering after a deployment', async () => { + const filepath = resolve( + dirname(fileURLToPath(import.meta.url)), + './fixtures/nested-call-private-kernel-ordering.hex', + ); + const serialized = Buffer.from(readFileSync(filepath).toString(), 'hex'); + const kernelInputs = PrivateKernelInputsOrdering.fromBuffer(serialized); + + const kernelOutputs = await executeOrdering(kernelInputs); + + expect(kernelOutputs).toMatchSnapshot(); + }); }); describe('Noir compatibility tests (interop_testing.nr)', () => { diff --git a/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts b/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts index 149a6db9575..765ab453388 100644 --- a/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts +++ b/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts @@ -16,11 +16,9 @@ import { computeFunctionTreeRoot, } from '@aztec/circuits.js/abis'; import { Fr } from '@aztec/foundation/fields'; +import { AztecLmdbStore } from '@aztec/kv-store'; import { Pedersen, StandardTree } from '@aztec/merkle-tree'; -import { default as levelup } from 'levelup'; -import memdown from 'memdown'; - describe('Data generation for noir tests', () => { const defaultContract = { address: AztecAddress.fromField(new Fr(12345)), @@ -73,7 +71,7 @@ describe('Data generation for noir tests', () => { return contractLeaf.toBuffer(); }); - const db = levelup((memdown as any)()); + const db = await AztecLmdbStore.openTmp(); const tree = new StandardTree( db, new Pedersen(), @@ -94,7 +92,7 @@ describe('Data generation for noir tests', () => { const indexes = new Array(128).fill(null).map((_, i) => BigInt(i)); const leaves = indexes.map(i => new Fr(i + 1n).toBuffer()); - const db = levelup((memdown as any)()); + const db = await AztecLmdbStore.openTmp(); const noteHashTree = new StandardTree( db, diff --git a/yarn-project/noir-protocol-circuits/src/type_conversion.ts b/yarn-project/noir-protocol-circuits/src/type_conversion.ts index 9b598111b4a..0ddb88ad5af 100644 --- a/yarn-project/noir-protocol-circuits/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits/src/type_conversion.ts @@ -23,6 +23,8 @@ import { FunctionData, FunctionSelector, GlobalVariables, + GrumpkinPrivateKey, + GrumpkinScalar, Header, KernelCircuitPublicInputs, KernelCircuitPublicInputsFinal, @@ -30,6 +32,7 @@ import { MAX_NEW_CONTRACTS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, @@ -41,6 +44,8 @@ import { NULLIFIER_TREE_HEIGHT, NUM_FIELDS_PER_SHA256, NewContractData, + NullifierKeyValidationRequest, + NullifierKeyValidationRequestContext, NullifierLeafPreimage, OptionallyRevealedData, PUBLIC_DATA_TREE_HEIGHT, @@ -86,12 +91,15 @@ import { FunctionData as FunctionDataNoir, FunctionLeafMembershipWitness as FunctionLeafMembershipWitnessNoir, FunctionSelector as FunctionSelectorNoir, + GrumpkinPrivateKey as GrumpkinPrivateKeyNoir, KernelCircuitPublicInputs as KernelCircuitPublicInputsNoir, NewContractData as NewContractDataNoir, AztecAddress as NoirAztecAddress, EthAddress as NoirEthAddress, Field as NoirField, GrumpkinPoint as NoirPoint, + NullifierKeyValidationRequestContext as NullifierKeyValidationRequestContextNoir, + NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, OptionallyRevealedData as OptionallyRevealedDataNoir, PrivateCallData as PrivateCallDataNoir, PrivateCallStackItem as PrivateCallStackItemNoir, @@ -177,9 +185,6 @@ export function mapNumberFromNoir(number: NoirField): number { return Number(Fr.fromString(number).toBigInt()); } -/** - * - */ export function mapNumberToNoir(number: number): NoirField { return new Fr(BigInt(number)).toString(); } @@ -205,6 +210,27 @@ export function mapPointFromNoir(point: NoirPoint): Point { return new Point(mapFieldFromNoir(point.x), mapFieldFromNoir(point.y)); } +/** + * Maps a GrumpkinPrivateKey to a noir GrumpkinPrivateKey. + * @param privateKey - The GrumpkinPrivateKey. + * @returns The noir GrumpkinPrivateKey. + */ +export function mapGrumpkinPrivateKeyToNoir(privateKey: GrumpkinPrivateKey): GrumpkinPrivateKeyNoir { + return { + high: mapFieldToNoir(privateKey.high), + low: mapFieldToNoir(privateKey.low), + }; +} + +/** + * Maps a noir GrumpkinPrivateKey to a GrumpkinPrivateKey. + * @param privateKey - The noir GrumpkinPrivateKey. + * @returns The GrumpkinPrivateKey. + */ +export function mapGrumpkinPrivateKeyFromNoir(privateKey: GrumpkinPrivateKeyNoir): GrumpkinPrivateKey { + return GrumpkinScalar.fromHighLow(mapFieldFromNoir(privateKey.high), mapFieldFromNoir(privateKey.low)); +} + /** * Maps an aztec address to a noir aztec address. * @param address - The address. @@ -430,7 +456,7 @@ export function mapCallerContextToNoir(callerContext: CallerContext): CallerCont } /** - * Maps a noit call request to a call request. + * Maps a noir call request to a call request. * @param callRequest - The noir call request. * @returns The call request. */ @@ -510,6 +536,64 @@ export function mapSideEffectLinkedFromNoir( ); } +/** + * Maps a NullifierKeyValidationRequest to a noir NullifierKeyValidationRequest. + * @param request - The NullifierKeyValidationRequest. + * @returns The noir NullifierKeyValidationRequest. + */ +export function mapNullifierKeyValidationRequestToNoir( + request: NullifierKeyValidationRequest, +): NullifierKeyValidationRequestNoir { + return { + public_key: mapPointToNoir(request.publicKey), + secret_key: mapGrumpkinPrivateKeyToNoir(request.secretKey), + }; +} + +/** + * Maps a noir NullifierKeyValidationRequest to NullifierKeyValidationRequest. + * @param request - The noir NullifierKeyValidationRequest. + * @returns The TS NullifierKeyValidationRequest. + */ +export function mapNullifierKeyValidationRequestFromNoir( + request: NullifierKeyValidationRequestNoir, +): NullifierKeyValidationRequest { + return new NullifierKeyValidationRequest( + mapPointFromNoir(request.public_key), + mapGrumpkinPrivateKeyFromNoir(request.secret_key), + ); +} + +/** + * Maps a NullifierKeyValidationRequest to a noir NullifierKeyValidationRequest. + * @param request - The NullifierKeyValidationRequest. + * @returns The noir NullifierKeyValidationRequest. + */ +export function mapNullifierKeyValidationRequestContextToNoir( + request: NullifierKeyValidationRequestContext, +): NullifierKeyValidationRequestContextNoir { + return { + public_key: mapPointToNoir(request.publicKey), + secret_key: mapGrumpkinPrivateKeyToNoir(request.secretKey), + contract_address: mapAztecAddressToNoir(request.contractAddress), + }; +} + +/** + * Maps a noir NullifierKeyValidationRequestContext to NullifierKeyValidationRequestContext. + * @param request - The noir NullifierKeyValidationRequestContext. + * @returns The TS NullifierKeyValidationRequestContext. + */ +export function mapNullifierKeyValidationRequestContextFromNoir( + request: NullifierKeyValidationRequestContextNoir, +): NullifierKeyValidationRequestContext { + return new NullifierKeyValidationRequestContext( + mapPointFromNoir(request.public_key), + mapGrumpkinPrivateKeyFromNoir(request.secret_key), + mapAztecAddressFromNoir(request.contract_address), + ); +} + /** * Maps a block header to a noir block header. * @param blockHeader - The block header. @@ -559,6 +643,10 @@ export function mapPrivateCircuitPublicInputsToNoir( args_hash: mapFieldToNoir(privateCircuitPublicInputs.argsHash), return_values: mapTuple(privateCircuitPublicInputs.returnValues, mapFieldToNoir), read_requests: mapTuple(privateCircuitPublicInputs.readRequests, mapSideEffectToNoir), + nullifier_key_validation_requests: mapTuple( + privateCircuitPublicInputs.nullifierKeyValidationRequests, + mapNullifierKeyValidationRequestToNoir, + ), new_commitments: mapTuple(privateCircuitPublicInputs.newCommitments, mapSideEffectToNoir), new_nullifiers: mapTuple(privateCircuitPublicInputs.newNullifiers, mapSideEffectLinkedToNoir), private_call_stack_hashes: mapTuple(privateCircuitPublicInputs.privateCallStackHashes, mapFieldToNoir), @@ -818,6 +906,11 @@ export function mapCombinedAccumulatedDataFromNoir( // TODO aggregation object AggregationObject.makeFake(), mapTupleFromNoir(combinedAccumulatedData.read_requests, MAX_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), + mapTupleFromNoir( + combinedAccumulatedData.nullifier_key_validation_requests, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + mapNullifierKeyValidationRequestContextFromNoir, + ), mapTupleFromNoir(combinedAccumulatedData.new_commitments, MAX_NEW_COMMITMENTS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(combinedAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -900,6 +993,10 @@ export function mapCombinedAccumulatedDataToNoir( return { aggregation_object: {}, read_requests: mapTuple(combinedAccumulatedData.readRequests, mapSideEffectToNoir), + nullifier_key_validation_requests: mapTuple( + combinedAccumulatedData.nullifierKeyValidationRequests, + mapNullifierKeyValidationRequestContextToNoir, + ), new_commitments: mapTuple(combinedAccumulatedData.newCommitments, mapSideEffectToNoir), new_nullifiers: mapTuple(combinedAccumulatedData.newNullifiers, mapSideEffectLinkedToNoir), private_call_stack: mapTuple(combinedAccumulatedData.privateCallStack, mapCallRequestToNoir), @@ -1047,6 +1144,7 @@ export function mapPrivateKernelInputsOrderingToNoir( sorted_new_nullifiers: mapTuple(inputs.sortedNewNullifiers, mapSideEffectLinkedToNoir), sorted_new_nullifiers_indexes: mapTuple(inputs.sortedNewNullifiersIndexes, mapNumberToNoir), nullifier_commitment_hints: mapTuple(inputs.nullifierCommitmentHints, mapFieldToNoir), + master_nullifier_secret_keys: mapTuple(inputs.masterNullifierSecretKeys, mapGrumpkinPrivateKeyToNoir), }; } diff --git a/yarn-project/noir-protocol-circuits/tsconfig.json b/yarn-project/noir-protocol-circuits/tsconfig.json index 917d509e475..a2e4cd63239 100644 --- a/yarn-project/noir-protocol-circuits/tsconfig.json +++ b/yarn-project/noir-protocol-circuits/tsconfig.json @@ -21,6 +21,9 @@ { "path": "../circuit-types" }, + { + "path": "../kv-store" + }, { "path": "../merkle-tree" } diff --git a/yarn-project/p2p-bootstrap/scripts/docker-compose-bootstrap.yml b/yarn-project/p2p-bootstrap/scripts/docker-compose-bootstrap.yml index ce5913b9e75..9ea2293cb24 100644 --- a/yarn-project/p2p-bootstrap/scripts/docker-compose-bootstrap.yml +++ b/yarn-project/p2p-bootstrap/scripts/docker-compose-bootstrap.yml @@ -1,11 +1,11 @@ version: '3' services: p2p-bootstrap: - image: 278380418400.dkr.ecr.eu-west-2.amazonaws.com/aztec-sandbox:latest + image: 278380418400.dkr.ecr.eu-west-2.amazonaws.com/aztec:latest + command: 'start --p2p-bootstrap' ports: - '40400:40400' environment: - MODE: 'p2p-bootstrap' DEBUG: 'aztec:*' P2P_TCP_LISTEN_PORT: 40400 PEER_ID: '0a260024080112205ea53185db2e52dae74d0d4d6cadc494174810d0a713cd09b0ac517c38bc781e1224080112205ea53185db2e52dae74d0d4d6cadc494174810d0a713cd09b0ac517c38bc781e1a44080112402df8b977f356c6e34fa021c9647973234dff4df706c185794405aafb556723cf5ea53185db2e52dae74d0d4d6cadc494174810d0a713cd09b0ac517c38bc781e' diff --git a/yarn-project/p2p-bootstrap/terraform/main.tf b/yarn-project/p2p-bootstrap/terraform/main.tf index 659133d4f42..376d59c134b 100644 --- a/yarn-project/p2p-bootstrap/terraform/main.tf +++ b/yarn-project/p2p-bootstrap/terraform/main.tf @@ -105,7 +105,8 @@ resource "aws_ecs_task_definition" "p2p-bootstrap" { [ { "name": "${var.DEPLOY_TAG}-p2p-bootstrap-${count.index + 1}", - "image": "${var.DOCKERHUB_ACCOUNT}/aztec-sandbox:${var.DEPLOY_TAG}", + "image": "${var.DOCKERHUB_ACCOUNT}/aztec:${var.DEPLOY_TAG}", + "command": ["start", "--p2p-bootstrap"], "essential": true, "command": ["start"], "memoryReservation": 3776, diff --git a/yarn-project/p2p/src/client/p2p_client.test.ts b/yarn-project/p2p/src/client/p2p_client.test.ts index 4de4f519f13..0ca27e09752 100644 --- a/yarn-project/p2p/src/client/p2p_client.test.ts +++ b/yarn-project/p2p/src/client/p2p_client.test.ts @@ -1,5 +1,4 @@ import { L2BlockSource, mockTx } from '@aztec/circuit-types'; -import { EthAddress } from '@aztec/circuits.js'; import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { expect, jest } from '@jest/globals'; @@ -42,7 +41,7 @@ describe('In-Memory P2P Client', () => { blockSource = new MockBlockSource(); - kvStore = await AztecLmdbStore.create(EthAddress.random()); + kvStore = await AztecLmdbStore.openTmp(); client = new P2PClient(kvStore, blockSource, txPool, p2pService); }); diff --git a/yarn-project/p2p/src/client/p2p_client.ts b/yarn-project/p2p/src/client/p2p_client.ts index 6c9789259ac..8fb1b520cb0 100644 --- a/yarn-project/p2p/src/client/p2p_client.ts +++ b/yarn-project/p2p/src/client/p2p_client.ts @@ -132,9 +132,9 @@ export class P2PClient implements P2P { private p2pService: P2PService, private log = createDebugLogger('aztec:p2p'), ) { - const { p2pBlockCheckIntervalMS: checkInterval, l2QueueSize } = getP2PConfigEnvVars(); - this.blockDownloader = new L2BlockDownloader(l2BlockSource, l2QueueSize, checkInterval); - this.synchedBlockNumber = store.createSingleton('p2p_pool_last_l2_block'); + const { p2pBlockCheckIntervalMS: checkInterval, p2pL2QueueSize } = getP2PConfigEnvVars(); + this.blockDownloader = new L2BlockDownloader(l2BlockSource, p2pL2QueueSize, checkInterval); + this.synchedBlockNumber = store.openSingleton('p2p_pool_last_l2_block'); } /** diff --git a/yarn-project/p2p/src/config.ts b/yarn-project/p2p/src/config.ts index 8e4d4d1af94..a995bcb8195 100644 --- a/yarn-project/p2p/src/config.ts +++ b/yarn-project/p2p/src/config.ts @@ -15,7 +15,7 @@ export interface P2PConfig { /** * Size of queue of L2 blocks to store. */ - l2QueueSize: number; + p2pL2QueueSize: number; /** * The tcp port on which the P2P service should listen for connections. @@ -96,7 +96,7 @@ export function getP2PConfigEnvVars(): P2PConfig { const envVars: P2PConfig = { p2pEnabled: P2P_ENABLED === 'true', p2pBlockCheckIntervalMS: P2P_BLOCK_CHECK_INTERVAL_MS ? +P2P_BLOCK_CHECK_INTERVAL_MS : 100, - l2QueueSize: P2P_L2_BLOCK_QUEUE_SIZE ? +P2P_L2_BLOCK_QUEUE_SIZE : 1000, + p2pL2QueueSize: P2P_L2_BLOCK_QUEUE_SIZE ? +P2P_L2_BLOCK_QUEUE_SIZE : 1000, tcpListenPort: P2P_TCP_LISTEN_PORT ? +P2P_TCP_LISTEN_PORT : 40400, tcpListenIp: P2P_TCP_LISTEN_IP ? P2P_TCP_LISTEN_IP : '0.0.0.0', peerIdPrivateKey: PEER_ID_PRIVATE_KEY, diff --git a/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts b/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts index 126779f9dd5..fe030abe6d7 100644 --- a/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts +++ b/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts @@ -1,4 +1,3 @@ -import { EthAddress } from '@aztec/circuits.js'; import { AztecLmdbStore } from '@aztec/kv-store'; import { AztecKVTxPool } from './aztec_kv_tx_pool.js'; @@ -7,7 +6,7 @@ import { describeTxPool } from './tx_pool_test_suite.js'; describe('In-Memory TX pool', () => { let txPool: AztecKVTxPool; beforeEach(async () => { - txPool = new AztecKVTxPool(await AztecLmdbStore.create(EthAddress.random())); + txPool = new AztecKVTxPool(await AztecLmdbStore.openTmp()); }); describeTxPool(() => txPool); diff --git a/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.ts b/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.ts index 1d8d723ab5d..fd1eba930e2 100644 --- a/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.ts +++ b/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.ts @@ -24,7 +24,7 @@ export class AztecKVTxPool implements TxPool { * @param log - A logger. */ constructor(store: AztecKVStore, log = createDebugLogger('aztec:tx_pool')) { - this.#txs = store.createMap('txs'); + this.#txs = store.openMap('txs'); this.#store = store; this.#log = log; } diff --git a/yarn-project/package.json b/yarn-project/package.json index 8bd7ef891ce..ca1849aef71 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -22,7 +22,7 @@ "aztec-faucet", "aztec-node", "pxe", - "aztec-sandbox", + "aztec", "aztec.js", "circuits.js", "circuit-types", @@ -32,6 +32,7 @@ "ethereum", "foundation", "key-store", + "kv-store", "l1-artifacts", "merkle-tree", "noir-compiler", @@ -45,8 +46,7 @@ "scripts", "types", "world-state", - "yarn-project-base", - "kv-store" + "yarn-project-base" ], "prettier": "@aztec/foundation/prettier", "devDependencies": { diff --git a/yarn-project/pxe/src/config/index.ts b/yarn-project/pxe/src/config/index.ts index eaf7133944d..3f22e3caab2 100644 --- a/yarn-project/pxe/src/config/index.ts +++ b/yarn-project/pxe/src/config/index.ts @@ -12,8 +12,7 @@ export interface PXEServiceConfig { l2BlockPollingIntervalMS: number; /** L2 block to start scanning from for new accounts */ l2StartingBlock: number; - - /** Where to store PXE data. If not set will store in memory */ + /** Where to store PXE data. If not set, will store in memory */ dataDirectory?: string; } @@ -21,12 +20,12 @@ export interface PXEServiceConfig { * Creates an instance of PXEServiceConfig out of environment variables using sensible defaults for integration testing if not set. */ export function getPXEServiceConfig(): PXEServiceConfig { - const { PXE_BLOCK_POLLING_INTERVAL_MS, PXE_L2_STARTING_BLOCK, DATA_DIRECTORY } = process.env; + const { PXE_BLOCK_POLLING_INTERVAL_MS, PXE_L2_STARTING_BLOCK, PXE_DATA_DIRECTORY } = process.env; return { l2BlockPollingIntervalMS: PXE_BLOCK_POLLING_INTERVAL_MS ? +PXE_BLOCK_POLLING_INTERVAL_MS : 1000, l2StartingBlock: PXE_L2_STARTING_BLOCK ? +PXE_L2_STARTING_BLOCK : INITIAL_L2_BLOCK_NUM, - dataDirectory: DATA_DIRECTORY, + dataDirectory: PXE_DATA_DIRECTORY, }; } diff --git a/yarn-project/pxe/src/database/index.ts b/yarn-project/pxe/src/database/index.ts index 35d4e000a20..4685cc2f7a8 100644 --- a/yarn-project/pxe/src/database/index.ts +++ b/yarn-project/pxe/src/database/index.ts @@ -1,2 +1 @@ export * from './pxe_database.js'; -export * from './memory_db.js'; diff --git a/yarn-project/pxe/src/database/kv_pxe_database.test.ts b/yarn-project/pxe/src/database/kv_pxe_database.test.ts index a9054af0719..27e0da25f37 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.test.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.test.ts @@ -1,4 +1,3 @@ -import { EthAddress } from '@aztec/circuits.js'; import { AztecLmdbStore } from '@aztec/kv-store'; import { KVPxeDatabase } from './kv_pxe_database.js'; @@ -8,7 +7,7 @@ describe('KVPxeDatabase', () => { let database: KVPxeDatabase; beforeEach(async () => { - database = new KVPxeDatabase(await AztecLmdbStore.create(EthAddress.random())); + database = new KVPxeDatabase(await AztecLmdbStore.openTmp()); }); describePxeDatabase(() => database); diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index 2b1956efa98..2f6e6053b15 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -1,6 +1,7 @@ import { ContractDao, MerkleTreeId, NoteFilter, PublicKey } from '@aztec/circuit-types'; import { AztecAddress, BlockHeader, CompleteAddress } from '@aztec/circuits.js'; import { ContractArtifact } from '@aztec/foundation/abi'; +import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { Fr, Point } from '@aztec/foundation/fields'; import { AztecArray, AztecKVStore, AztecMap, AztecMultiMap, AztecSingleton } from '@aztec/kv-store'; import { contractArtifactFromBuffer, contractArtifactToBuffer } from '@aztec/types/abi'; @@ -30,44 +31,49 @@ export class KVPxeDatabase implements PxeDatabase { #authWitnesses: AztecMap; #capsules: AztecArray; #contracts: AztecMap; - #notes: AztecArray; - #nullifiedNotes: AztecMap; - #notesByContract: AztecMultiMap; - #notesByStorageSlot: AztecMultiMap; - #notesByTxHash: AztecMultiMap; - #notesByOwner: AztecMultiMap; - #deferredNotes: AztecArray; + #notes: AztecMap; + #nullifierToNoteId: AztecMap; + #notesByContract: AztecMultiMap; + #notesByStorageSlot: AztecMultiMap; + #notesByTxHash: AztecMultiMap; + #notesByOwner: AztecMultiMap; + #deferredNotes: AztecArray; #deferredNotesByContract: AztecMultiMap; #syncedBlockPerPublicKey: AztecMap; #contractArtifacts: AztecMap; #contractInstances: AztecMap; #db: AztecKVStore; - constructor(db: AztecKVStore) { + constructor(private db: AztecKVStore) { this.#db = db; - this.#addresses = db.createArray('addresses'); - this.#addressIndex = db.createMap('address_index'); + this.#addresses = db.openArray('addresses'); + this.#addressIndex = db.openMap('address_index'); - this.#authWitnesses = db.createMap('auth_witnesses'); - this.#capsules = db.createArray('capsules'); - this.#contracts = db.createMap('contracts'); - this.#contractArtifacts = db.createMap('contract_artifacts'); - this.#contractInstances = db.createMap('contracts_instances'); + this.#authWitnesses = db.openMap('auth_witnesses'); + this.#capsules = db.openArray('capsules'); + this.#contracts = db.openMap('contracts'); - this.#synchronizedBlock = db.createSingleton('block_header'); - this.#syncedBlockPerPublicKey = db.createMap('synced_block_per_public_key'); + this.#contractArtifacts = db.openMap('contract_artifacts'); + this.#contractInstances = db.openMap('contracts_instances'); + this.#notesByOwner = db.openMultiMap('notes_by_owner'); - this.#notes = db.createArray('notes'); - this.#nullifiedNotes = db.createMap('nullified_notes'); + this.#synchronizedBlock = db.openSingleton('block_header'); + this.#syncedBlockPerPublicKey = db.openMap('synced_block_per_public_key'); - this.#notesByContract = db.createMultiMap('notes_by_contract'); - this.#notesByStorageSlot = db.createMultiMap('notes_by_storage_slot'); - this.#notesByTxHash = db.createMultiMap('notes_by_tx_hash'); - this.#notesByOwner = db.createMultiMap('notes_by_owner'); + this.#notes = db.openMap('notes'); + this.#nullifierToNoteId = db.openMap('nullifier_to_note'); + this.#notesByContract = db.openMultiMap('notes_by_contract'); + this.#notesByStorageSlot = db.openMultiMap('notes_by_storage_slot'); + this.#notesByTxHash = db.openMultiMap('notes_by_tx_hash'); - this.#deferredNotes = db.createArray('deferred_notes'); - this.#deferredNotesByContract = db.createMultiMap('deferred_notes_by_contract'); + this.#notesByContract = db.openMultiMap('notes_by_contract'); + this.#notesByStorageSlot = db.openMultiMap('notes_by_storage_slot'); + this.#notesByTxHash = db.openMultiMap('notes_by_tx_hash'); + this.#notesByOwner = db.openMultiMap('notes_by_owner'); + + this.#deferredNotes = db.openArray('deferred_notes'); + this.#deferredNotesByContract = db.openMultiMap('deferred_notes_by_contract'); } public async addContractArtifact(id: Fr, contract: ContractArtifact): Promise { @@ -117,17 +123,22 @@ export class KVPxeDatabase implements PxeDatabase { await this.addNotes([note]); } - async addNotes(notes: NoteDao[]): Promise { - const newLength = await this.#notes.push(...notes.map(note => note.toBuffer())); - for (const [index, note] of notes.entries()) { - const noteId = newLength - notes.length + index; - await Promise.all([ - this.#notesByContract.set(note.contractAddress.toString(), noteId), - this.#notesByStorageSlot.set(note.storageSlot.toString(), noteId), - this.#notesByTxHash.set(note.txHash.toString(), noteId), - this.#notesByOwner.set(note.publicKey.toString(), noteId), - ]); - } + addNotes(notes: NoteDao[]): Promise { + return this.db.transaction(() => { + for (const dao of notes) { + // store notes by their index in the notes hash tree + // this provides the uniqueness we need to store individual notes + // and should also return notes in the order that they were created. + // Had we stored them by their nullifier, they would be returned in random order + const noteIndex = toBufferBE(dao.index, 32).toString('hex'); + void this.#notes.set(noteIndex, dao.toBuffer()); + void this.#nullifierToNoteId.set(dao.siloedNullifier.toString(), noteIndex); + void this.#notesByContract.set(dao.contractAddress.toString(), noteIndex); + void this.#notesByStorageSlot.set(dao.storageSlot.toString(), noteIndex); + void this.#notesByTxHash.set(dao.txHash.toString(), noteIndex); + void this.#notesByOwner.set(dao.publicKey.toString(), noteIndex); + } + }); } async addDeferredNotes(deferredNotes: DeferredNoteDao[]): Promise { @@ -158,11 +169,6 @@ export class KVPxeDatabase implements PxeDatabase { * Removes all deferred notes for a given contract address. * @param contractAddress - the contract address to remove deferred notes for * @returns an array of the removed deferred notes - * - * @remarks We only remove indices from the deferred notes by contract map, but not the actual deferred notes. - * This is safe because our only getter for deferred notes is by contract address. - * If we should add a more general getter, we will need a delete vector for deferred notes as well, - * analogous to this.#nullifiedNotes. */ removeDeferredNotesByContract(contractAddress: AztecAddress): Promise { return this.#db.transaction(() => { @@ -178,25 +184,16 @@ export class KVPxeDatabase implements PxeDatabase { } void this.#deferredNotesByContract.deleteValue(contractAddress.toString(), index); + void this.#deferredNotes.setAt(index, null); } return deferredNotes; }); } - *#getAllNonNullifiedNotes(): IterableIterator { - for (const [index, serialized] of this.#notes.entries()) { - if (this.#nullifiedNotes.has(index)) { - continue; - } - - yield NoteDao.fromBuffer(serialized); - } - } - - async getNotes(filter: NoteFilter): Promise { + #getNotes(filter: NoteFilter = {}): NoteDao[] { const publicKey: PublicKey | undefined = filter.owner - ? (await this.getCompleteAddress(filter.owner))?.publicKey + ? this.#getCompleteAddress(filter.owner)?.publicKey : undefined; const initialNoteIds = publicKey @@ -207,15 +204,11 @@ export class KVPxeDatabase implements PxeDatabase { ? this.#notesByContract.getValues(filter.contractAddress.toString()) : filter.storageSlot ? this.#notesByStorageSlot.getValues(filter.storageSlot.toString()) - : undefined; - - if (!initialNoteIds) { - return Array.from(this.#getAllNonNullifiedNotes()); - } + : this.#notes.keys(); const result: NoteDao[] = []; for (const noteId of initialNoteIds) { - const serializedNote = this.#notes.at(noteId); + const serializedNote = this.#notes.get(noteId); if (!serializedNote) { continue; } @@ -243,26 +236,46 @@ export class KVPxeDatabase implements PxeDatabase { return result; } + getNotes(filter: NoteFilter): Promise { + return Promise.resolve(this.#getNotes(filter)); + } + removeNullifiedNotes(nullifiers: Fr[], account: PublicKey): Promise { if (nullifiers.length === 0) { return Promise.resolve([]); } - const nullifierSet = new Set(nullifiers.map(n => n.toString())); + return this.#db.transaction(() => { - const notesIds = this.#notesByOwner.getValues(account.toString()); const nullifiedNotes: NoteDao[] = []; - for (const noteId of notesIds) { - const note = NoteDao.fromBuffer(this.#notes.at(noteId)!); - if (nullifierSet.has(note.siloedNullifier.toString())) { - nullifiedNotes.push(note); + for (const nullifier of nullifiers) { + const noteIndex = this.#nullifierToNoteId.get(nullifier.toString()); + if (!noteIndex) { + continue; + } + + const noteBuffer = noteIndex ? this.#notes.get(noteIndex) : undefined; - void this.#nullifiedNotes.set(noteId, true); - void this.#notesByOwner.deleteValue(account.toString(), noteId); - void this.#notesByTxHash.deleteValue(note.txHash.toString(), noteId); - void this.#notesByContract.deleteValue(note.contractAddress.toString(), noteId); - void this.#notesByStorageSlot.deleteValue(note.storageSlot.toString(), noteId); + if (!noteBuffer) { + // note doesn't exist. Maybe it got nullified already + continue; + } + + const note = NoteDao.fromBuffer(noteBuffer); + if (!note.publicKey.equals(account)) { + // tried to nullify someone else's note + continue; } + + nullifiedNotes.push(note); + + void this.#notes.delete(noteIndex); + void this.#notesByOwner.deleteValue(account.toString(), noteIndex); + void this.#notesByTxHash.deleteValue(note.txHash.toString(), noteIndex); + void this.#notesByContract.deleteValue(note.contractAddress.toString(), noteIndex); + void this.#notesByStorageSlot.deleteValue(note.storageSlot.toString(), noteIndex); + + void this.#nullifierToNoteId.delete(nullifier.toString()); } return nullifiedNotes; @@ -349,14 +362,18 @@ export class KVPxeDatabase implements PxeDatabase { }); } - getCompleteAddress(address: AztecAddress): Promise { + #getCompleteAddress(address: AztecAddress): CompleteAddress | undefined { const index = this.#addressIndex.get(address.toString()); if (typeof index === 'undefined') { - return Promise.resolve(undefined); + return undefined; } const value = this.#addresses.at(index); - return Promise.resolve(value ? CompleteAddress.fromBuffer(value) : undefined); + return value ? CompleteAddress.fromBuffer(value) : undefined; + } + + getCompleteAddress(address: AztecAddress): Promise { + return Promise.resolve(this.#getCompleteAddress(address)); } getCompleteAddresses(): Promise { @@ -372,7 +389,7 @@ export class KVPxeDatabase implements PxeDatabase { } estimateSize(): number { - const notesSize = Array.from(this.#getAllNonNullifiedNotes()).reduce((sum, note) => sum + note.getSize(), 0); + const notesSize = Array.from(this.#getNotes({})).reduce((sum, note) => sum + note.getSize(), 0); const authWitsSize = Array.from(this.#authWitnesses.values()).reduce( (sum, value) => sum + value.length * Fr.SIZE_IN_BYTES, 0, diff --git a/yarn-project/pxe/src/database/memory_db.test.ts b/yarn-project/pxe/src/database/memory_db.test.ts deleted file mode 100644 index f505efa4a79..00000000000 --- a/yarn-project/pxe/src/database/memory_db.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { AztecAddress, Fr } from '@aztec/circuits.js'; - -import { MemoryDB } from './memory_db.js'; -import { randomNoteDao } from './note_dao.test.js'; -import { describePxeDatabase } from './pxe_database_test_suite.js'; - -describe('Memory DB', () => { - let db: MemoryDB; - - beforeEach(() => { - db = new MemoryDB(); - }); - - describePxeDatabase(() => db); - - describe('NoteDao', () => { - const contractAddress = AztecAddress.random(); - const storageSlot = Fr.random(); - - const createNotes = (numberOfNotes: number, sameStorage = true) => - Array(numberOfNotes) - .fill(0) - .map(() => - randomNoteDao({ - contractAddress: sameStorage ? contractAddress : AztecAddress.random(), - storageSlot: sameStorage ? storageSlot : Fr.random(), - }), - ); - - it('should add and get notes', async () => { - const notes = createNotes(3, false); - for (let i = 0; i < notes.length; ++i) { - await db.addNote(notes[i]); - } - - for (let i = 0; i < notes.length; ++i) { - const result = await db.getNotes({ - contractAddress: notes[i].contractAddress, - storageSlot: notes[i].storageSlot, - }); - expect(result).toEqual([notes[i]]); - } - }); - - it('should batch add notes', async () => { - const notes = createNotes(3, false); - await db.addNotes(notes); - - for (let i = 0; i < notes.length; ++i) { - const result = await db.getNotes({ - contractAddress: notes[i].contractAddress, - storageSlot: notes[i].storageSlot, - }); - expect(result).toEqual([notes[i]]); - } - }); - - it('should get all notes with the same contract storage slot', async () => { - const notes = createNotes(3); - await db.addNotes(notes); - - const result = await db.getNotes({ contractAddress, storageSlot }); - expect(result.length).toBe(notes.length); - expect(result).toEqual(expect.objectContaining(notes)); - }); - }); -}); diff --git a/yarn-project/pxe/src/database/memory_db.ts b/yarn-project/pxe/src/database/memory_db.ts deleted file mode 100644 index 5390c654b94..00000000000 --- a/yarn-project/pxe/src/database/memory_db.ts +++ /dev/null @@ -1,248 +0,0 @@ -import { MerkleTreeId, NoteFilter } from '@aztec/circuit-types'; -import { BlockHeader, CompleteAddress, PublicKey } from '@aztec/circuits.js'; -import { ContractArtifact } from '@aztec/foundation/abi'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { Fr, Point } from '@aztec/foundation/fields'; -import { createDebugLogger } from '@aztec/foundation/log'; -import { ContractInstanceWithAddress } from '@aztec/types/contracts'; - -import { MemoryContractDatabase } from '../contract_database/index.js'; -import { DeferredNoteDao } from './deferred_note_dao.js'; -import { NoteDao } from './note_dao.js'; -import { PxeDatabase } from './pxe_database.js'; - -/** - * The MemoryDB class provides an in-memory implementation of a database to manage transactions and auxiliary data. - * It extends the MemoryContractDatabase, allowing it to store contract-related data as well. - * The class offers methods to add, fetch, and remove transaction records and auxiliary data based on various filters such as transaction hash, address, and storage slot. - * As an in-memory database, the stored data will not persist beyond the life of the application instance. - */ -export class MemoryDB extends MemoryContractDatabase implements PxeDatabase { - private notesTable: NoteDao[] = []; - private deferredNotesTable: DeferredNoteDao[] = []; - private treeRoots: Record | undefined; - private globalVariablesHash: Fr | undefined; - private blockNumber: number | undefined; - private addresses: CompleteAddress[] = []; - private authWitnesses: Record = {}; - private syncedBlockPerPublicKey = new Map(); - // A capsule is a "blob" of data that is passed to the contract through an oracle. - // We are using a stack to keep track of the capsules that are passed to the contract. - private capsuleStack: Fr[][] = []; - - private contractArtifacts = new Map(); - private contractInstances = new Map(); - - constructor(logSuffix?: string) { - super(createDebugLogger(logSuffix ? 'aztec:memory_db_' + logSuffix : 'aztec:memory_db')); - } - - public addContractArtifact(id: Fr, contract: ContractArtifact): Promise { - this.contractArtifacts.set(id.toString(), contract); - return Promise.resolve(); - } - - public getContractArtifact(id: Fr): Promise { - const contract = this.contractArtifacts.get(id.toString()); - return Promise.resolve(contract); - } - - public addContractInstance(contract: ContractInstanceWithAddress): Promise { - this.contractInstances.set(contract.address.toString(), contract); - return Promise.resolve(); - } - - public getContractInstance(address: AztecAddress): Promise { - const contract = this.contractInstances.get(address.toString()); - return Promise.resolve(contract); - } - - /** - * Add a auth witness to the database. - * @param messageHash - The message hash. - * @param witness - An array of field elements representing the auth witness. - */ - public addAuthWitness(messageHash: Fr, witness: Fr[]): Promise { - this.authWitnesses[messageHash.toString()] = witness; - return Promise.resolve(); - } - - /** - * Fetching the auth witness for a given message hash. - * @param messageHash - The message hash. - * @returns A Promise that resolves to an array of field elements representing the auth witness. - */ - public getAuthWitness(messageHash: Fr): Promise { - return Promise.resolve(this.authWitnesses[messageHash.toString()]); - } - - public addNote(note: NoteDao): Promise { - this.notesTable.push(note); - return Promise.resolve(); - } - - public addDeferredNotes(notes: DeferredNoteDao[]): Promise { - this.deferredNotesTable.push(...notes); - return Promise.resolve(); - } - - public getDeferredNotesByContract(contractAddress: AztecAddress): Promise { - return Promise.resolve(this.deferredNotesTable.filter(note => note.contractAddress.equals(contractAddress))); - } - - public removeDeferredNotesByContract(contractAddress: AztecAddress): Promise { - const removed: DeferredNoteDao[] = []; - this.deferredNotesTable = this.deferredNotesTable.filter(note => { - if (note.contractAddress.equals(contractAddress)) { - removed.push(note); - return false; - } - return true; - }); - return Promise.resolve(removed); - } - - public addCapsule(capsule: Fr[]): Promise { - this.capsuleStack.push(capsule); - return Promise.resolve(); - } - - public popCapsule(): Promise { - return Promise.resolve(this.capsuleStack.pop()); - } - - public addNotes(notes: NoteDao[]) { - this.notesTable.push(...notes); - return Promise.resolve(); - } - - public async getNotes(filter: NoteFilter): Promise { - let ownerPublicKey: PublicKey | undefined; - if (filter.owner !== undefined) { - const ownerCompleteAddress = await this.getCompleteAddress(filter.owner); - if (ownerCompleteAddress === undefined) { - throw new Error(`Owner ${filter.owner.toString()} not found in memory database`); - } - ownerPublicKey = ownerCompleteAddress.publicKey; - } - - return this.notesTable.filter( - note => - (filter.contractAddress == undefined || note.contractAddress.equals(filter.contractAddress)) && - (filter.txHash == undefined || note.txHash.equals(filter.txHash)) && - (filter.storageSlot == undefined || note.storageSlot.equals(filter.storageSlot!)) && - (ownerPublicKey == undefined || note.publicKey.equals(ownerPublicKey!)), - ); - } - - public removeNullifiedNotes(nullifiers: Fr[], account: PublicKey) { - const nullifierSet = new Set(nullifiers.map(nullifier => nullifier.toString())); - const [remaining, removed] = this.notesTable.reduce( - (acc: [NoteDao[], NoteDao[]], note) => { - const nullifier = note.siloedNullifier.toString(); - if (note.publicKey.equals(account) && nullifierSet.has(nullifier)) { - acc[1].push(note); - } else { - acc[0].push(note); - } - return acc; - }, - [[], []], - ); - - this.notesTable = remaining; - - return Promise.resolve(removed); - } - - public getTreeRoots(): Record { - const roots = this.treeRoots; - if (!roots) { - throw new Error(`Tree roots not set in memory database`); - } - return roots; - } - - private setTreeRoots(roots: Record) { - this.treeRoots = roots; - } - - public getBlockHeader(): BlockHeader { - const roots = this.getTreeRoots(); - if (!this.globalVariablesHash) { - throw new Error(`Global variables hash not set in memory database`); - } - return new BlockHeader( - roots[MerkleTreeId.NOTE_HASH_TREE], - roots[MerkleTreeId.NULLIFIER_TREE], - roots[MerkleTreeId.CONTRACT_TREE], - roots[MerkleTreeId.L1_TO_L2_MESSAGE_TREE], - roots[MerkleTreeId.ARCHIVE], - Fr.ZERO, // todo: private kernel vk tree root - roots[MerkleTreeId.PUBLIC_DATA_TREE], - this.globalVariablesHash, - ); - } - - public setBlockData(blockNumber: number, blockHeader: BlockHeader): Promise { - this.globalVariablesHash = blockHeader.globalVariablesHash; - this.blockNumber = blockNumber; - this.setTreeRoots({ - [MerkleTreeId.NOTE_HASH_TREE]: blockHeader.noteHashTreeRoot, - [MerkleTreeId.NULLIFIER_TREE]: blockHeader.nullifierTreeRoot, - [MerkleTreeId.CONTRACT_TREE]: blockHeader.contractTreeRoot, - [MerkleTreeId.L1_TO_L2_MESSAGE_TREE]: blockHeader.l1ToL2MessageTreeRoot, - [MerkleTreeId.ARCHIVE]: blockHeader.archiveRoot, - [MerkleTreeId.PUBLIC_DATA_TREE]: blockHeader.publicDataTreeRoot, - }); - - return Promise.resolve(); - } - - public getBlockNumber(): number | undefined { - return this.blockNumber; - } - - public addCompleteAddress(completeAddress: CompleteAddress): Promise { - const accountIndex = this.addresses.findIndex(r => r.address.equals(completeAddress.address)); - if (accountIndex !== -1) { - if (this.addresses[accountIndex].equals(completeAddress)) { - return Promise.resolve(false); - } - - return Promise.reject( - new Error( - `Complete address with aztec address ${completeAddress.address.toString()} but different public key or partial key already exists in memory database`, - ), - ); - } - this.addresses.push(completeAddress); - return Promise.resolve(true); - } - - public getCompleteAddress(address: AztecAddress): Promise { - const recipient = this.addresses.find(r => r.address.equals(address)); - return Promise.resolve(recipient); - } - - public getCompleteAddresses(): Promise { - return Promise.resolve(this.addresses); - } - - getSynchedBlockNumberForPublicKey(publicKey: Point): number | undefined { - return this.syncedBlockPerPublicKey.get(publicKey.toString()); - } - - setSynchedBlockNumberForPublicKey(publicKey: Point, blockNumber: number): Promise { - this.syncedBlockPerPublicKey.set(publicKey.toString(), blockNumber); - return Promise.resolve(true); - } - - public estimateSize() { - const notesSize = this.notesTable.reduce((sum, note) => sum + note.getSize(), 0); - const treeRootsSize = this.treeRoots ? Object.entries(this.treeRoots).length * Fr.SIZE_IN_BYTES : 0; - const authWits = Object.entries(this.authWitnesses); - const authWitsSize = authWits.reduce((sum, [key, value]) => sum + key.length + value.length * Fr.SIZE_IN_BYTES, 0); - return notesSize + treeRootsSize + authWitsSize + this.addresses.length * CompleteAddress.SIZE_IN_BYTES; - } -} diff --git a/yarn-project/pxe/src/database/note_dao.test.ts b/yarn-project/pxe/src/database/note_dao.test.ts index 34baa9a14dd..113f2de5fba 100644 --- a/yarn-project/pxe/src/database/note_dao.test.ts +++ b/yarn-project/pxe/src/database/note_dao.test.ts @@ -11,7 +11,7 @@ export const randomNoteDao = ({ nonce = Fr.random(), innerNoteHash = Fr.random(), siloedNullifier = Fr.random(), - index = BigInt(0), + index = Fr.random().toBigInt(), publicKey = Point.random(), }: Partial = {}) => { return new NoteDao( diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 5f0a7ebccbf..6dce43c5a3f 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -112,6 +112,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { contractAddress: contractAddresses[i % contractAddresses.length], storageSlot: storageSlots[i % storageSlots.length], publicKey: owners[i % owners.length].publicKey, + index: BigInt(i), }), ); }); diff --git a/yarn-project/pxe/src/kernel_oracle/index.ts b/yarn-project/pxe/src/kernel_oracle/index.ts index af05c8dafb6..ddbc325020a 100644 --- a/yarn-project/pxe/src/kernel_oracle/index.ts +++ b/yarn-project/pxe/src/kernel_oracle/index.ts @@ -1,5 +1,12 @@ -import { AztecNode, MerkleTreeId } from '@aztec/circuit-types'; -import { AztecAddress, Fr, FunctionSelector, MembershipWitness, NOTE_HASH_TREE_HEIGHT } from '@aztec/circuits.js'; +import { AztecNode, KeyStore, MerkleTreeId } from '@aztec/circuit-types'; +import { + AztecAddress, + Fr, + FunctionSelector, + MembershipWitness, + NOTE_HASH_TREE_HEIGHT, + Point, +} from '@aztec/circuits.js'; import { Tuple } from '@aztec/foundation/serialize'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; @@ -9,7 +16,7 @@ import { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js'; * A data oracle that provides information needed for simulating a transaction. */ export class KernelOracle implements ProvingDataOracle { - constructor(private contractDataOracle: ContractDataOracle, private node: AztecNode) {} + constructor(private contractDataOracle: ContractDataOracle, private keyStore: KeyStore, private node: AztecNode) {} public async getContractMembershipWitness(contractAddress: AztecAddress) { return await this.contractDataOracle.getContractMembershipWitness(contractAddress); @@ -36,4 +43,8 @@ export class KernelOracle implements ProvingDataOracle { const roots = await this.node.getTreeRoots(); return roots[MerkleTreeId.NOTE_HASH_TREE]; } + + public getMasterNullifierSecretKey(nullifierPublicKey: Point) { + return this.keyStore.getNullifierSecretKeyFromPublicKey(nullifierPublicKey); + } } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 0fe2966c80a..7dc509c4986 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -4,13 +4,16 @@ import { CONTRACT_TREE_HEIGHT, CallRequest, Fr, + GrumpkinScalar, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, MAX_READ_REQUESTS_PER_TX, MembershipWitness, + NullifierKeyValidationRequestContext, PreviousKernelData, PrivateCallData, PrivateKernelInputsInit, @@ -138,6 +141,7 @@ export class KernelProver { if (firstIteration) { const proofInput = new PrivateKernelInputsInit(txRequest, privateCallData); + pushTestData('private-kernel-inputs-init', proofInput); output = await this.proofCreator.createProofInit(proofInput); } else { const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey); @@ -185,6 +189,10 @@ export class KernelProver { sortedCommitments, ); + const masterNullifierSecretKeys = await this.getMasterNullifierSecretKeys( + output.publicInputs.end.nullifierKeyValidationRequests, + ); + const privateInputs = new PrivateKernelInputsOrdering( previousKernelData, sortedCommitments, @@ -193,7 +201,9 @@ export class KernelProver { sortedNullifiers, sortedNullifiersIndexes, nullifierCommitmentHints, + masterNullifierSecretKeys, ); + pushTestData('private-kernel-inputs-ordering', privateInputs); const outputFinal = await this.proofCreator.createProofOrdering(privateInputs); // Only return the notes whose commitment is in the commitments of the final proof. @@ -356,4 +366,21 @@ export class KernelProver { } return hints; } + + private async getMasterNullifierSecretKeys( + nullifierKeyValidationRequests: Tuple< + NullifierKeyValidationRequestContext, + typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + >, + ) { + const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar.zero); + for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) { + const request = nullifierKeyValidationRequests[i]; + if (request.isEmpty()) { + break; + } + keys[i] = await this.oracle.getMasterNullifierSecretKey(request.publicKey); + } + return keys; + } } diff --git a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts index 78fce87a48e..edc6c6c5227 100644 --- a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts +++ b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts @@ -3,8 +3,10 @@ import { FUNCTION_TREE_HEIGHT, Fr, FunctionSelector, + GrumpkinPrivateKey, MembershipWitness, NOTE_HASH_TREE_HEIGHT, + Point, VK_TREE_HEIGHT, VerificationKey, } from '@aztec/circuits.js'; @@ -66,4 +68,12 @@ export interface ProvingDataOracle { * @returns the root of the note hash tree. */ getNoteHashTreeRoot(): Promise; + + /** + * Get the master secret key of the nullifier public key. + * + * @param nullifierPublicKey - The nullifier public key. + * @returns the master nullifier secret key. + */ + getMasterNullifierSecretKey(nullifierPublicKey: Point): Promise; } diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index 64d91fb4dcc..0b97ebf0326 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -12,7 +12,7 @@ import { Note, TxL2Logs, } from '@aztec/circuit-types'; -import { EthAddress, Fr, MAX_NEW_COMMITMENTS_PER_TX } from '@aztec/circuits.js'; +import { Fr, MAX_NEW_COMMITMENTS_PER_TX } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Point } from '@aztec/foundation/fields'; @@ -119,7 +119,7 @@ describe('Note Processor', () => { }); beforeEach(async () => { - database = new KVPxeDatabase(await AztecLmdbStore.create(EthAddress.random())); + database = new KVPxeDatabase(await AztecLmdbStore.openTmp()); addNotesSpy = jest.spyOn(database, 'addNotes'); aztecNode = mock(); diff --git a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts index 336f35b710c..300da326589 100644 --- a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts +++ b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts @@ -23,9 +23,6 @@ import { Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields'; import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; import http from 'http'; -import { foundry } from 'viem/chains'; - -export const localAnvil = foundry; /** * Wraps an instance of Private eXecution Environment (PXE) implementation to a JSON RPC HTTP interface. @@ -55,7 +52,6 @@ export function createPXERpcServer(pxeService: PXE): JsonRpcServer { LogId, }, { Tx, TxReceipt, L2BlockL2Logs }, - false, ['start', 'stop'], ); } diff --git a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts index 2b52e0dfc3b..00d800f1e7a 100644 --- a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts @@ -35,11 +35,8 @@ export async function createPXEService( const keyStorePath = config.dataDirectory ? join(config.dataDirectory, 'pxe_key_store') : undefined; const l1Contracts = await aztecNode.getL1ContractAddresses(); - const keyStore = new TestKeyStore( - new Grumpkin(), - await AztecLmdbStore.create(l1Contracts.rollupAddress, keyStorePath), - ); - const db = new KVPxeDatabase(await AztecLmdbStore.create(l1Contracts.rollupAddress, pxeDbPath)); + const keyStore = new TestKeyStore(new Grumpkin(), await AztecLmdbStore.open(l1Contracts.rollupAddress, keyStorePath)); + const db = new KVPxeDatabase(await AztecLmdbStore.open(l1Contracts.rollupAddress, pxeDbPath)); const server = new PXEService(keyStore, aztecNode, db, config, logSuffix); diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index b7e3ac38a08..2ac154c6eeb 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -489,7 +489,7 @@ export class PXEService implements PXE { const contract = await this.db.getContract(to); if (!contract) { throw new Error( - `Unknown contract ${to}: add it to PXE Service by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`, + `Unknown contract ${to}: add it to PXE Service by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/developers/debugging/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`, ); } @@ -641,7 +641,7 @@ export class PXEService implements PXE { // Get values that allow us to reconstruct the block hash const executionResult = await this.#simulate(txExecutionRequest); - const kernelOracle = new KernelOracle(this.contractDataOracle, this.node); + const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node); const kernelProver = new KernelProver(kernelOracle); this.log(`Executing kernel prover...`); const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult); diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 617fdd3de96..7caf5668e35 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -14,7 +14,7 @@ import { PXEService } from '../pxe_service.js'; import { pxeTestSuite } from './pxe_test_suite.js'; async function createPXEService(): Promise { - const kvStore = await AztecLmdbStore.create(EthAddress.random()); + const kvStore = await AztecLmdbStore.openTmp(); const keyStore = new TestKeyStore(new Grumpkin(), kvStore); const node = mock(); const db = new KVPxeDatabase(kvStore); @@ -46,7 +46,7 @@ describe('PXEService', () => { let config: PXEServiceConfig; beforeEach(async () => { - const kvStore = await AztecLmdbStore.create(EthAddress.random()); + const kvStore = await AztecLmdbStore.openTmp(); keyStore = new TestKeyStore(new Grumpkin(), kvStore); node = mock(); db = new KVPxeDatabase(kvStore); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 50d62d00996..edd402aa5a9 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -37,7 +37,7 @@ export class SimulatorOracle implements DBOracle { const completeAddress = await this.db.getCompleteAddress(address); if (!completeAddress) { throw new Error( - `No public key registered for address ${address.toString()}. Register it by calling pxe.registerRecipient(...) or pxe.registerAccount(...).\nSee docs for context: https://docs.aztec.network/dev_docs/debugging/aztecnr-errors#simulation-error-No-public-key-registered-for-address-0x0-Register-it-by-calling-pxeregisterRecipient-or-pxeregisterAccount`, + `No public key registered for address ${address.toString()}. Register it by calling pxe.registerRecipient(...) or pxe.registerAccount(...).\nSee docs for context: https://docs.aztec.network/developers/debugging/aztecnr-errors#simulation-error-No-public-key-registered-for-address-0x0-Register-it-by-calling-pxeregisterRecipient-or-pxeregisterAccount`, ); } return completeAddress; diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index 19f10de11c8..44754f4c543 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -1,5 +1,5 @@ import { AztecNode, INITIAL_L2_BLOCK_NUM, L2Block, MerkleTreeId } from '@aztec/circuit-types'; -import { BlockHeader, CompleteAddress, EthAddress, Fr, GrumpkinScalar } from '@aztec/circuits.js'; +import { BlockHeader, CompleteAddress, Fr, GrumpkinScalar } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { SerialQueue } from '@aztec/foundation/fifo'; import { TestKeyStore } from '@aztec/key-store'; @@ -32,7 +32,7 @@ describe('Synchronizer', () => { }; aztecNode = mock(); - database = new KVPxeDatabase(await AztecLmdbStore.create(EthAddress.random())); + database = new KVPxeDatabase(await AztecLmdbStore.openTmp()); jobQueue = new SerialQueue(); synchronizer = new TestSynchronizer(aztecNode, database, jobQueue); }); @@ -121,7 +121,7 @@ describe('Synchronizer', () => { expect(await synchronizer.isGlobalStateSynchronized()).toBe(true); // Manually adding account to database so that we can call synchronizer.isAccountStateSynchronized - const keyStore = new TestKeyStore(new Grumpkin(), await AztecLmdbStore.create(EthAddress.random())); + const keyStore = new TestKeyStore(new Grumpkin(), await AztecLmdbStore.openTmp()); const addAddress = async (startingBlockNum: number) => { const privateKey = GrumpkinScalar.random(); await keyStore.addAccount(privateKey); diff --git a/yarn-project/sequencer-client/package.json b/yarn-project/sequencer-client/package.json index 8c11e1f877f..40bf5fd98ee 100644 --- a/yarn-project/sequencer-client/package.json +++ b/yarn-project/sequencer-client/package.json @@ -49,6 +49,7 @@ "viem": "^1.2.5" }, "devDependencies": { + "@aztec/kv-store": "workspace:^", "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", "@types/levelup": "^5.1.2", diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 3ab5e249e60..90b42751fb7 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -49,10 +49,10 @@ import { makeTuple, range } from '@aztec/foundation/array'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { times } from '@aztec/foundation/collection'; import { to2Fields } from '@aztec/foundation/serialize'; +import { AztecLmdbStore } from '@aztec/kv-store'; import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; import { MockProxy, mock } from 'jest-mock-extended'; -import { default as levelup } from 'levelup'; import { type MemDown, default as memdown } from 'memdown'; import { VerificationKeys, getVerificationKeys } from '../mocks/verification_keys.js'; @@ -96,8 +96,8 @@ describe('sequencer/solo_block_builder', () => { blockNumber = 3; globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO); - builderDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); - expectsDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); + builderDb = await MerkleTrees.new(await AztecLmdbStore.openTmp()).then(t => t.asLatest()); + expectsDb = await MerkleTrees.new(await AztecLmdbStore.openTmp()).then(t => t.asLatest()); vks = getVerificationKeys(); simulator = mock(); prover = mock(); diff --git a/yarn-project/sequencer-client/tsconfig.json b/yarn-project/sequencer-client/tsconfig.json index 92a83cff65d..7a1f29b1488 100644 --- a/yarn-project/sequencer-client/tsconfig.json +++ b/yarn-project/sequencer-client/tsconfig.json @@ -38,6 +38,9 @@ }, { "path": "../world-state" + }, + { + "path": "../kv-store" } ], "include": ["src"] diff --git a/yarn-project/tsconfig.json b/yarn-project/tsconfig.json index 2ffee350c7e..f648e5691f1 100644 --- a/yarn-project/tsconfig.json +++ b/yarn-project/tsconfig.json @@ -25,7 +25,7 @@ { "path": "aztec.js/tsconfig.json" }, { "path": "aztec-node/tsconfig.json" }, { "path": "pxe/tsconfig.json" }, - { "path": "aztec-sandbox/tsconfig.json" }, + { "path": "aztec/tsconfig.json" }, { "path": "circuits.js/tsconfig.json" }, { "path": "circuit-types/tsconfig.json" }, { "path": "cli/tsconfig.json" }, @@ -46,4 +46,4 @@ { "path": "scripts/tsconfig.json" } ], "files": ["./@types/jest/index.d.ts"] -} +} \ No newline at end of file diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index 34fd9160a1f..798887d2ede 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -7,7 +7,7 @@ "archiver", "aztec-cli", "pxe", - "aztec-sandbox", + "aztec", "aztec.js", "key-store", "noir-contracts", @@ -20,4 +20,4 @@ "world-state", "merkle-tree" ] -} +} \ No newline at end of file diff --git a/yarn-project/world-state/package.json b/yarn-project/world-state/package.json index 7fc61040e0e..e65cae9fcc1 100644 --- a/yarn-project/world-state/package.json +++ b/yarn-project/world-state/package.json @@ -33,10 +33,9 @@ "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/kv-store": "workspace:^", "@aztec/merkle-tree": "workspace:^", "@aztec/types": "workspace:^", - "levelup": "^5.1.1", - "memdown": "^6.1.1", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts index 65addf22ff3..8c0f0e23351 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts @@ -2,13 +2,12 @@ import { L2Block, L2BlockSource, MerkleTreeId } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; +import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; import { INITIAL_LEAF, Pedersen } from '@aztec/merkle-tree'; import { SiblingPath } from '@aztec/types/membership'; import { jest } from '@jest/globals'; import { mock } from 'jest-mock-extended'; -import levelup from 'levelup'; -import { default as memdown } from 'memdown'; import { MerkleTreeDb, MerkleTrees, WorldStateConfig } from '../index.js'; import { ServerWorldStateSynchronizer } from './server_world_state_synchronizer.js'; @@ -33,30 +32,10 @@ const getMockBlock = (blockNumber: number, newContractsCommitments?: Buffer[]) = return block; }; -const createMockDb = () => levelup((memdown as any)()); - -const createSynchronizer = async ( - db: levelup.LevelUp, - merkleTreeDb: any, - rollupSource: any, - blockCheckInterval = 100, -) => { - const worldStateConfig: WorldStateConfig = { - worldStateBlockCheckIntervalMS: blockCheckInterval, - l2QueueSize: 1000, - }; - - return await ServerWorldStateSynchronizer.new( - db, - merkleTreeDb as MerkleTrees, - rollupSource as L2BlockSource, - worldStateConfig, - ); -}; - const log = createDebugLogger('aztec:server_world_state_synchronizer_test'); describe('server_world_state_synchronizer', () => { + let db: AztecKVStore; const rollupSource = mock({ getBlockNumber: jest.fn(getLatestBlockNumber), getBlocks: jest.fn(consumeNextBlocks), @@ -111,12 +90,30 @@ describe('server_world_state_synchronizer', () => { expect(status.syncedToL2Block).toBe(LATEST_BLOCK_NUMBER + count); }; - it('can be constructed', async () => { - await expect(createSynchronizer(createMockDb(), merkleTreeDb, rollupSource)).resolves.toBeTruthy(); + const createSynchronizer = (blockCheckInterval = 100) => { + const worldStateConfig: WorldStateConfig = { + worldStateBlockCheckIntervalMS: blockCheckInterval, + l2QueueSize: 1000, + }; + + return new ServerWorldStateSynchronizer( + db, + merkleTreeDb as any as MerkleTrees, + rollupSource as L2BlockSource, + worldStateConfig, + ); + }; + + beforeEach(async () => { + db = await AztecLmdbStore.openTmp(); + }); + + it('can be constructed', () => { + expect(createSynchronizer()).toBeTruthy(); }); it('updates sync progress', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource); + const server = createSynchronizer(); // test initial state let status = await server.status(); @@ -165,7 +162,7 @@ describe('server_world_state_synchronizer', () => { }); it('enables blocking until synced', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource); + const server = createSynchronizer(); let currentBlockNumber = 0; const newBlocks = async () => { @@ -196,7 +193,7 @@ describe('server_world_state_synchronizer', () => { }); it('handles multiple calls to start', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource); + const server = createSynchronizer(); let currentBlockNumber = 0; const newBlocks = async () => { @@ -223,7 +220,7 @@ describe('server_world_state_synchronizer', () => { }); it('immediately syncs if no new blocks', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource); + const server = createSynchronizer(); rollupSource.getBlockNumber.mockImplementationOnce(() => { return Promise.resolve(0); }); @@ -241,7 +238,7 @@ describe('server_world_state_synchronizer', () => { }); it("can't be started if already stopped", async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource); + const server = createSynchronizer(); rollupSource.getBlockNumber.mockImplementationOnce(() => { return Promise.resolve(0); }); @@ -256,7 +253,7 @@ describe('server_world_state_synchronizer', () => { it('adds the received L2 blocks', async () => { merkleTreeDb.handleL2Block.mockClear(); - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource); + const server = createSynchronizer(); const totalBlocks = LATEST_BLOCK_NUMBER + 1; nextBlocks = Array(totalBlocks) .fill(0) @@ -269,7 +266,7 @@ describe('server_world_state_synchronizer', () => { }); it('can immediately sync to latest', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(10000); await performInitialSync(server); @@ -297,7 +294,7 @@ describe('server_world_state_synchronizer', () => { }); it('can immediately sync to a minimum block number', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(10000); await performInitialSync(server); @@ -322,7 +319,7 @@ describe('server_world_state_synchronizer', () => { }); it('can immediately sync to a minimum block in the past', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(10000); await performInitialSync(server); // syncing to a block in the past should succeed @@ -344,7 +341,7 @@ describe('server_world_state_synchronizer', () => { }); it('throws if you try to sync to an unavailable block', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(); await performInitialSync(server); @@ -370,7 +367,7 @@ describe('server_world_state_synchronizer', () => { }); it('throws if you try to immediate sync when not running', async () => { - const server = await createSynchronizer(createMockDb(), merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(10000); // test initial state const status = await server.status(); @@ -386,13 +383,12 @@ describe('server_world_state_synchronizer', () => { }); it('restores the last synced block', async () => { - const db = createMockDb(); - const initialServer = await createSynchronizer(db, merkleTreeDb, rollupSource, 10000); + const initialServer = createSynchronizer(10000); await performInitialSync(initialServer); await initialServer.stop(); - const server = await createSynchronizer(db, merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(10000); const status = await server.status(); expect(status).toEqual({ state: WorldStateRunningState.IDLE, @@ -401,13 +397,12 @@ describe('server_world_state_synchronizer', () => { }); it('starts syncing from the last block', async () => { - const db = createMockDb(); - const initialServer = await createSynchronizer(db, merkleTreeDb, rollupSource, 10000); + const initialServer = createSynchronizer(10000); await performInitialSync(initialServer); await initialServer.stop(); - const server = await createSynchronizer(db, merkleTreeDb, rollupSource, 10000); + const server = createSynchronizer(10000); await performSubsequentSync(server, 2); await server.stop(); }); diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts index ee0349ade38..3c25882bfed 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts @@ -3,8 +3,7 @@ import { L2BlockHandledStats } from '@aztec/circuit-types/stats'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; - -import { LevelUp } from 'levelup'; +import { AztecKVStore, AztecSingleton } from '@aztec/kv-store'; import { HandleL2BlockResult, MerkleTreeOperations, MerkleTrees } from '../world-state-db/index.js'; import { MerkleTreeOperationsFacade } from '../world-state-db/merkle_tree_operations_facade.js'; @@ -12,15 +11,12 @@ import { MerkleTreeSnapshotOperationsFacade } from '../world-state-db/merkle_tre import { WorldStateConfig } from './config.js'; import { WorldStateRunningState, WorldStateStatus, WorldStateSynchronizer } from './world_state_synchronizer.js'; -const DB_KEY_BLOCK_NUMBER = 'latestBlockNumber'; - /** * Synchronizes the world state with the L2 blocks from a L2BlockSource. * The synchronizer will download the L2 blocks from the L2BlockSource and insert the new commitments into the merkle * tree. */ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { - private currentL2BlockNum = 0; private latestBlockNumberAtStart = 0; private l2BlockDownloader: L2BlockDownloader; @@ -30,14 +26,16 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { private stopping = false; private runningPromise: Promise = Promise.resolve(); private currentState: WorldStateRunningState = WorldStateRunningState.IDLE; + private blockNumber: AztecSingleton; - private constructor( - private db: LevelUp, + constructor( + store: AztecKVStore, private merkleTreeDb: MerkleTrees, private l2BlockSource: L2BlockSource, config: WorldStateConfig, private log = createDebugLogger('aztec:world_state'), ) { + this.blockNumber = store.openSingleton('world_state_synch_last_block_number'); this.l2BlockDownloader = new L2BlockDownloader( l2BlockSource, config.l2QueueSize, @@ -57,22 +55,6 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { return new MerkleTreeSnapshotOperationsFacade(this.merkleTreeDb, blockNumber); } - public static async new( - db: LevelUp, - merkleTreeDb: MerkleTrees, - l2BlockSource: L2BlockSource, - config: WorldStateConfig, - log = createDebugLogger('aztec:world_state'), - ) { - const server = new ServerWorldStateSynchronizer(db, merkleTreeDb, l2BlockSource, config, log); - await server.#init(); - return server; - } - - async #init() { - await this.restoreCurrentL2BlockNumber(); - } - public async start() { if (this.currentState === WorldStateRunningState.STOPPED) { throw new Error('Synchronizer already stopped'); @@ -123,11 +105,13 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { await this.merkleTreeDb.stop(); this.log('Awaiting promise'); await this.runningPromise; - this.log('Commiting current block number'); - await this.commitCurrentL2BlockNumber(); this.setCurrentState(WorldStateRunningState.STOPPED); } + private get currentL2BlockNum(): number { + return this.blockNumber.get() ?? 0; + } + public status(): Promise { const status = { syncedToL2Block: this.currentL2BlockNum, @@ -184,7 +168,6 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { // This request for blocks will timeout after 1 second if no blocks are received const blocks = await this.l2BlockDownloader.getBlocks(1); await this.handleL2Blocks(blocks); - await this.commitCurrentL2BlockNumber(); } /** @@ -210,11 +193,9 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { */ private async handleL2Block(l2Block: L2Block): Promise { const result = await this.merkleTreeDb.handleL2Block(l2Block); - this.currentL2BlockNum = l2Block.number; - if ( - this.currentState === WorldStateRunningState.SYNCHING && - this.currentL2BlockNum >= this.latestBlockNumberAtStart - ) { + await this.blockNumber.set(l2Block.number); + + if (this.currentState === WorldStateRunningState.SYNCHING && l2Block.number >= this.latestBlockNumberAtStart) { this.setCurrentState(WorldStateRunningState.RUNNING); if (this.syncResolve !== undefined) { this.syncResolve(); @@ -231,22 +212,4 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { this.currentState = newState; this.log(`Moved to state ${WorldStateRunningState[this.currentState]}`); } - - private async commitCurrentL2BlockNumber() { - const hex = this.currentL2BlockNum.toString(16); - const encoded = Buffer.from(hex.length % 2 === 1 ? '0' + hex : hex, 'hex'); - - await this.db.put(DB_KEY_BLOCK_NUMBER, encoded); - } - - private async restoreCurrentL2BlockNumber() { - try { - const encoded: Buffer = await this.db.get(DB_KEY_BLOCK_NUMBER); - this.currentL2BlockNum = parseInt(encoded.toString('hex'), 16); - this.log.debug(`Restored current L2 block number ${this.currentL2BlockNum} from db`); - } catch (err) { - this.log.debug('No current L2 block number found in db, starting from 0'); - this.currentL2BlockNum = 0; - } - } } diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index b8a0d5c44ee..59d11217e8b 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -21,6 +21,7 @@ import { Committable } from '@aztec/foundation/committable'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; +import { AztecKVStore, AztecSingleton } from '@aztec/kv-store'; import { AppendOnlyTree, BatchInsertionResult, @@ -35,8 +36,6 @@ import { import { Hasher } from '@aztec/types/interfaces'; import { SiblingPath } from '@aztec/types/membership'; -import { default as levelup } from 'levelup'; - import { INITIAL_NULLIFIER_TREE_SIZE, INITIAL_PUBLIC_DATA_TREE_SIZE, MerkleTreeDb } from './merkle_tree_db.js'; import { CurrentTreeRoots, @@ -63,8 +62,8 @@ const LAST_GLOBAL_VARS_HASH = 'lastGlobalVarsHash'; * The nullifier tree is an indexed tree. */ class NullifierTree extends StandardIndexedTree { - constructor(db: levelup.LevelUp, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { - super(db, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root); + constructor(store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { + super(store, hasher, name, depth, size, NullifierLeafPreimage, NullifierLeaf, root); } } @@ -72,8 +71,8 @@ class NullifierTree extends StandardIndexedTree { * The public data tree is an indexed tree. */ class PublicDataTree extends StandardIndexedTree { - constructor(db: levelup.LevelUp, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { - super(db, hasher, name, depth, size, PublicDataTreeLeafPreimage, PublicDataTreeLeaf, root); + constructor(store: AztecKVStore, hasher: Hasher, name: string, depth: number, size: bigint = 0n, root?: Buffer) { + super(store, hasher, name, depth, size, PublicDataTreeLeafPreimage, PublicDataTreeLeaf, root); } } @@ -85,8 +84,11 @@ export class MerkleTrees implements MerkleTreeDb { private latestGlobalVariablesHash: Committable; private jobQueue = new SerialQueue(); - constructor(private db: levelup.LevelUp, private log = createDebugLogger('aztec:merkle_trees')) { + #globalVariablesHash: AztecSingleton; + + constructor(private store: AztecKVStore, private log = createDebugLogger('aztec:merkle_trees')) { this.latestGlobalVariablesHash = new Committable(Fr.ZERO); + this.#globalVariablesHash = store.openSingleton(LAST_GLOBAL_VARS_HASH); } /** @@ -100,14 +102,14 @@ export class MerkleTrees implements MerkleTreeDb { const hasher = new Pedersen(); const contractTree: AppendOnlyTree = await initializeTree( StandardTree, - this.db, + this.store, hasher, `${MerkleTreeId[MerkleTreeId.CONTRACT_TREE]}`, CONTRACT_TREE_HEIGHT, ); const nullifierTree = await initializeTree( NullifierTree, - this.db, + this.store, hasher, `${MerkleTreeId[MerkleTreeId.NULLIFIER_TREE]}`, NULLIFIER_TREE_HEIGHT, @@ -115,14 +117,14 @@ export class MerkleTrees implements MerkleTreeDb { ); const noteHashTree: AppendOnlyTree = await initializeTree( StandardTree, - this.db, + this.store, hasher, `${MerkleTreeId[MerkleTreeId.NOTE_HASH_TREE]}`, NOTE_HASH_TREE_HEIGHT, ); const publicDataTree = await initializeTree( PublicDataTree, - this.db, + this.store, hasher, `${MerkleTreeId[MerkleTreeId.PUBLIC_DATA_TREE]}`, PUBLIC_DATA_TREE_HEIGHT, @@ -130,14 +132,14 @@ export class MerkleTrees implements MerkleTreeDb { ); const l1Tol2MessageTree: AppendOnlyTree = await initializeTree( StandardTree, - this.db, + this.store, hasher, `${MerkleTreeId[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]}`, L1_TO_L2_MSG_TREE_HEIGHT, ); const archive: AppendOnlyTree = await initializeTree( StandardTree, - this.db, + this.store, hasher, `${MerkleTreeId[MerkleTreeId.ARCHIVE]}`, ARCHIVE_HEIGHT, @@ -161,15 +163,14 @@ export class MerkleTrees implements MerkleTreeDb { /** * Method to asynchronously create and initialize a MerkleTrees instance. - * @param db - The db instance to use for data persistance. + * @param store - The db instance to use for data persistance. * @returns - A fully initialized MerkleTrees instance. */ - public static async new(db: levelup.LevelUp) { - const merkleTrees = new MerkleTrees(db); - const globalVariablesHash: Buffer | undefined = await db.get(LAST_GLOBAL_VARS_HASH).catch(() => undefined); - await merkleTrees.init( - globalVariablesHash ? { globalVariablesHash: Fr.fromBuffer(globalVariablesHash) } : undefined, - ); + public static async new(store: AztecKVStore) { + const merkleTrees = new MerkleTrees(store); + const globalVariablesHash = store.openSingleton(LAST_GLOBAL_VARS_HASH); + const val = globalVariablesHash.get(); + await merkleTrees.init(val ? { globalVariablesHash: Fr.fromBuffer(val) } : undefined); return merkleTrees; } @@ -280,7 +281,7 @@ export class MerkleTrees implements MerkleTreeDb { index: bigint, includeUncommitted: boolean, ): Promise { - return await this.synchronize(() => this.trees[treeId].getLeafValue(index, includeUncommitted)); + return await this.synchronize(() => Promise.resolve(this.trees[treeId].getLeafValue(index, includeUncommitted))); } /** @@ -348,7 +349,9 @@ export class MerkleTrees implements MerkleTreeDb { } | undefined > { - return await this.synchronize(() => this._getIndexedTree(treeId).findIndexOfPreviousKey(value, includeUncommitted)); + return await this.synchronize(() => + Promise.resolve(this._getIndexedTree(treeId).findIndexOfPreviousKey(value, includeUncommitted)), + ); } /** @@ -364,7 +367,7 @@ export class MerkleTrees implements MerkleTreeDb { includeUncommitted: boolean, ): Promise { return await this.synchronize(() => - this._getIndexedTree(treeId).getLatestLeafPreimageCopy(index, includeUncommitted), + Promise.resolve(this._getIndexedTree(treeId).getLatestLeafPreimageCopy(index, includeUncommitted)), ); } @@ -380,9 +383,9 @@ export class MerkleTrees implements MerkleTreeDb { value: Buffer, includeUncommitted: boolean, ): Promise { - return await this.synchronize(async () => { + return await this.synchronize(() => { const tree = this.trees[treeId]; - return await tree.findLeafIndex(value, includeUncommitted); + return Promise.resolve(tree.findLeafIndex(value, includeUncommitted)); }); } @@ -523,7 +526,7 @@ export class MerkleTrees implements MerkleTreeDb { await tree.commit(); } this.latestGlobalVariablesHash.commit(); - await this.db.put(LAST_GLOBAL_VARS_HASH, this.latestGlobalVariablesHash.get().toBuffer()); + await this.#globalVariablesHash.set(this.latestGlobalVariablesHash.get().toBuffer()); } /** diff --git a/yarn-project/world-state/tsconfig.json b/yarn-project/world-state/tsconfig.json index 5550de6775f..0088e438260 100644 --- a/yarn-project/world-state/tsconfig.json +++ b/yarn-project/world-state/tsconfig.json @@ -15,6 +15,9 @@ { "path": "../foundation" }, + { + "path": "../kv-store" + }, { "path": "../merkle-tree" }, diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index a3ed1d89239..88e50f74f76 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -13,30 +13,37 @@ __metadata: linkType: hard "@achingbrain/nat-port-mapper@npm:^1.0.9": - version: 1.0.9 - resolution: "@achingbrain/nat-port-mapper@npm:1.0.9" + version: 1.0.13 + resolution: "@achingbrain/nat-port-mapper@npm:1.0.13" dependencies: "@achingbrain/ssdp": ^4.0.1 - "@libp2p/logger": ^2.0.0 - default-gateway: ^6.0.2 + "@libp2p/logger": ^4.0.1 + default-gateway: ^7.2.2 err-code: ^3.0.1 it-first: ^3.0.1 p-defer: ^4.0.0 p-timeout: ^6.1.1 xml2js: ^0.6.0 - checksum: 4d8b97ff6eceab530a51682f4f2d5b91101de029b429693bdcff73f19617770fe4e3271b353c3d932c419ed9fd1c0d6ba5bd98b716aab48c64c1d836b2d8020a + checksum: 0ece5a52be65fcb26e75918c39a5dad76a7752103bb32686e564e4c8f10e658e80e0e0d82acca6653cff4bac938faae06d71ceaef7a38916b9928b68a78c2c2b languageName: node linkType: hard "@achingbrain/ssdp@npm:^4.0.1": - version: 4.0.4 - resolution: "@achingbrain/ssdp@npm:4.0.4" + version: 4.0.6 + resolution: "@achingbrain/ssdp@npm:4.0.6" dependencies: event-iterator: ^2.0.0 freeport-promise: ^2.0.0 merge-options: ^3.0.4 - xml2js: ^0.5.0 - checksum: ebd5b25f64a2cd8fd14e760f92824cc308784d833eba887bfabc68a678de692eab83ac6c6859e56a187b7ea78e4fbdc9403899ed2be9cb245e0591a925431565 + xml2js: ^0.6.2 + checksum: 18af3ebf0ddd331531730b3c998729cb3db8f915b7f8296e503babf813a42af284e62b271148ac3ac85aa2420bb1c813c2d3b661c90e75f2e6d8700f9302f50b + languageName: node + linkType: hard + +"@adraffy/ens-normalize@npm:1.10.0": + version: 1.10.0 + resolution: "@adraffy/ens-normalize@npm:1.10.0" + checksum: af0540f963a2632da2bbc37e36ea6593dcfc607b937857133791781e246d47f870d5e3d21fa70d5cfe94e772c284588c81ea3f5b7f4ea8fbb824369444e4dbcb languageName: node linkType: hard @@ -87,6 +94,7 @@ __metadata: "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/noir-contracts": "workspace:^" "@jest/globals": ^29.5.0 @@ -128,7 +136,7 @@ __metadata: debug: ^4.3.4 jest: ^29.5.0 jest-mock-extended: ^3.0.4 - lmdb: ^2.9.1 + lmdb: ^2.9.2 lodash.omit: ^4.5.0 ts-jest: ^29.1.0 ts-node: ^10.9.1 @@ -180,16 +188,10 @@ __metadata: "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 - "@types/leveldown": ^4.0.4 - "@types/levelup": ^5.1.2 - "@types/memdown": ^3.0.0 "@types/node": ^18.7.23 jest: ^29.5.0 koa: ^2.14.2 koa-router: ^12.0.0 - levelup: ^5.1.1 - lmdb: ^2.9.1 - memdown: ^6.1.1 ts-jest: ^29.1.0 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -199,40 +201,6 @@ __metadata: languageName: unknown linkType: soft -"@aztec/aztec-sandbox@workspace:aztec-sandbox": - version: 0.0.0-use.local - resolution: "@aztec/aztec-sandbox@workspace:aztec-sandbox" - dependencies: - "@aztec/accounts": "workspace:^" - "@aztec/aztec-node": "workspace:^" - "@aztec/aztec.js": "workspace:^" - "@aztec/circuit-types": "workspace:^" - "@aztec/circuits.js": "workspace:^" - "@aztec/ethereum": "workspace:^" - "@aztec/foundation": "workspace:^" - "@aztec/l1-artifacts": "workspace:^" - "@aztec/noir-compiler": "workspace:^" - "@aztec/noir-contracts": "workspace:^" - "@aztec/p2p": "workspace:^" - "@aztec/pxe": "workspace:^" - "@jest/globals": ^29.5.0 - "@types/jest": ^29.5.0 - "@types/koa": ^2.13.6 - abitype: ^0.8.11 - jest: ^29.5.0 - koa: ^2.14.2 - koa-router: ^12.0.0 - ts-jest: ^29.1.0 - ts-node: ^10.9.1 - typescript: ^5.0.4 - viem: ^1.2.5 - winston: ^3.10.0 - winston-daily-rotate-file: ^4.7.1 - bin: - aztec-sandbox: ./dest/bin/index.js - languageName: unknown - linkType: soft - "@aztec/aztec.js@workspace:^, @aztec/aztec.js@workspace:aztec.js": version: 0.0.0-use.local resolution: "@aztec/aztec.js@workspace:aztec.js" @@ -280,6 +248,43 @@ __metadata: languageName: unknown linkType: soft +"@aztec/aztec@workspace:aztec": + version: 0.0.0-use.local + resolution: "@aztec/aztec@workspace:aztec" + dependencies: + "@aztec/accounts": "workspace:^" + "@aztec/archiver": "workspace:^" + "@aztec/aztec-node": "workspace:^" + "@aztec/aztec.js": "workspace:^" + "@aztec/circuit-types": "workspace:^" + "@aztec/circuits.js": "workspace:^" + "@aztec/ethereum": "workspace:^" + "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" + "@aztec/l1-artifacts": "workspace:^" + "@aztec/noir-compiler": "workspace:^" + "@aztec/noir-contracts": "workspace:^" + "@aztec/p2p": "workspace:^" + "@aztec/pxe": "workspace:^" + "@jest/globals": ^29.5.0 + "@types/jest": ^29.5.0 + "@types/koa": ^2.13.6 + abitype: ^0.8.11 + commander: ^11.1.0 + jest: ^29.5.0 + koa: ^2.14.2 + koa-router: ^12.0.0 + ts-jest: ^29.1.0 + ts-node: ^10.9.1 + typescript: ^5.0.4 + viem: ^1.2.5 + winston: ^3.10.0 + winston-daily-rotate-file: ^4.7.1 + bin: + aztec: ./dest/bin/index.js + languageName: unknown + linkType: soft + "@aztec/bb.js@portal:../barretenberg/ts::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@aztec/bb.js@portal:../barretenberg/ts::locator=%40aztec%2Faztec3-packages%40workspace%3A." @@ -557,7 +562,7 @@ __metadata: "@types/node": ^18.7.23 jest: ^29.5.0 jest-mock-extended: ^3.0.3 - lmdb: ^2.9.1 + lmdb: ^2.9.2 ts-jest: ^29.1.0 ts-node: ^10.9.1 typescript: ^5.0.4 @@ -582,16 +587,13 @@ __metadata: "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 - "@types/levelup": ^5.1.2 - "@types/memdown": ^3.0.1 "@types/node": ^18.15.3 "@types/sha256": ^0.2.0 jest: ^29.5.0 - levelup: ^5.1.1 - memdown: ^6.1.1 sha256: ^0.2.0 ts-jest: ^29.1.0 ts-node: ^10.9.1 @@ -657,6 +659,7 @@ __metadata: "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/noir-compiler": "workspace:^" "@aztec/types": "workspace:^" @@ -813,6 +816,7 @@ __metadata: "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" "@aztec/l1-artifacts": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/noir-protocol-circuits": "workspace:^" @@ -878,6 +882,7 @@ __metadata: "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 @@ -887,7 +892,6 @@ __metadata: "@types/node": ^18.7.23 jest: ^29.5.0 jest-mock-extended: ^3.0.5 - levelup: ^5.1.1 memdown: ^6.1.1 ts-jest: ^29.1.0 ts-node: ^10.9.1 @@ -902,42 +906,43 @@ __metadata: languageName: unknown linkType: soft -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/code-frame@npm:7.22.5" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" dependencies: - "@babel/highlight": ^7.22.5 - checksum: cfe804f518f53faaf9a1d3e0f9f74127ab9a004912c3a16fda07fb6a633393ecb9918a053cb71804204c1b7ec3d49e1699604715e2cfb0c9f7bc4933d324ebb6 + "@babel/highlight": ^7.23.4 + chalk: ^2.4.2 + checksum: d90981fdf56a2824a9b14d19a4c0e8db93633fd488c772624b4e83e0ceac6039a27cd298a247c3214faa952bf803ba23696172ae7e7235f3b97f43ba278c569a languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/compat-data@npm:7.22.9" - checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 +"@babel/compat-data@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/compat-data@npm:7.23.5" + checksum: 06ce244cda5763295a0ea924728c09bae57d35713b675175227278896946f922a63edf803c322f855a3878323d48d0255a2a3023409d2a123483c8a69ebb4744 languageName: node linkType: hard "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": - version: 7.22.9 - resolution: "@babel/core@npm:7.22.9" + version: 7.23.9 + resolution: "@babel/core@npm:7.23.9" dependencies: "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.9 - "@babel/helper-compilation-targets": ^7.22.9 - "@babel/helper-module-transforms": ^7.22.9 - "@babel/helpers": ^7.22.6 - "@babel/parser": ^7.22.7 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.8 - "@babel/types": ^7.22.5 - convert-source-map: ^1.7.0 + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.6 + "@babel/helper-compilation-targets": ^7.23.6 + "@babel/helper-module-transforms": ^7.23.3 + "@babel/helpers": ^7.23.9 + "@babel/parser": ^7.23.9 + "@babel/template": ^7.23.9 + "@babel/traverse": ^7.23.9 + "@babel/types": ^7.23.9 + convert-source-map: ^2.0.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 - json5: ^2.2.2 + json5: ^2.2.3 semver: ^6.3.1 - checksum: 7bf069aeceb417902c4efdaefab1f7b94adb7dea694a9aed1bda2edf4135348a080820529b1a300c6f8605740a00ca00c19b2d5e74b5dd489d99d8c11d5e56d1 + checksum: 634a511f74db52a5f5a283c1121f25e2227b006c095b84a02a40a9213842489cd82dc7d61cdc74e10b5bcd9bb0a4e28bab47635b54c7e2256d47ab57356e2a76 languageName: node linkType: hard @@ -952,51 +957,49 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.17.3, @babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9, @babel/generator@npm:^7.7.2": - version: 7.22.9 - resolution: "@babel/generator@npm:7.22.9" +"@babel/generator@npm:^7.23.0, @babel/generator@npm:^7.23.6, @babel/generator@npm:^7.7.2": + version: 7.23.6 + resolution: "@babel/generator@npm:7.23.6" dependencies: - "@babel/types": ^7.22.5 + "@babel/types": ^7.23.6 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 7c9d2c58b8d5ac5e047421a6ab03ec2ff5d9a5ff2c2212130a0055e063ac349e0b19d435537d6886c999771aef394832e4f54cd9fc810100a7f23d982f6af06b + checksum: 1a1a1c4eac210f174cd108d479464d053930a812798e09fee069377de39a893422df5b5b146199ead7239ae6d3a04697b45fc9ac6e38e0f6b76374390f91fc6c languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-compilation-targets@npm:7.22.9" +"@babel/helper-compilation-targets@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-compilation-targets@npm:7.23.6" dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-validator-option": ^7.22.5 - browserslist: ^4.21.9 + "@babel/compat-data": ^7.23.5 + "@babel/helper-validator-option": ^7.23.5 + browserslist: ^4.22.2 lru-cache: ^5.1.1 semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: ea0006c6a93759025f4a35a25228ae260538c9f15023e8aac2a6d45ca68aef4cf86cfc429b19af9a402cbdd54d5de74ad3fbcf6baa7e48184dc079f1a791e178 + checksum: c630b98d4527ac8fe2c58d9a06e785dfb2b73ec71b7c4f2ddf90f814b5f75b547f3c015f110a010fd31f76e3864daaf09f3adcd2f6acdbfb18a8de3a48717590 languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.16.7, @babel/helper-environment-visitor@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-environment-visitor@npm:7.22.5" - checksum: 248532077d732a34cd0844eb7b078ff917c3a8ec81a7f133593f71a860a582f05b60f818dc5049c2212e5baa12289c27889a4b81d56ef409b4863db49646c4b1 +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.16.7, @babel/helper-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-function-name@npm:7.22.5" +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" dependencies: - "@babel/template": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 languageName: node linkType: hard -"@babel/helper-hoist-variables@npm:^7.16.7, @babel/helper-hoist-variables@npm:^7.22.5": +"@babel/helper-hoist-variables@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-hoist-variables@npm:7.22.5" dependencies: @@ -1005,27 +1008,27 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-module-imports@npm:7.22.5" +"@babel/helper-module-imports@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" dependencies: - "@babel/types": ^7.22.5 - checksum: 9ac2b0404fa38b80bdf2653fbeaf8e8a43ccb41bd505f9741d820ed95d3c4e037c62a1bcdcb6c9527d7798d2e595924c4d025daed73283badc180ada2c9c49ad + "@babel/types": ^7.22.15 + checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-module-transforms@npm:7.22.9" +"@babel/helper-module-transforms@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/helper-module-transforms@npm:7.23.3" dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-module-imports": ^7.22.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-module-imports": ^7.22.15 "@babel/helper-simple-access": ^7.22.5 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 peerDependencies: "@babel/core": ^7.0.0 - checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 + checksum: 5d0895cfba0e16ae16f3aa92fee108517023ad89a855289c4eb1d46f7aef4519adf8e6f971e1d55ac20c5461610e17213f1144097a8f932e768a9132e2278d71 languageName: node linkType: hard @@ -1045,7 +1048,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.16.7, @babel/helper-split-export-declaration@npm:^7.22.6": +"@babel/helper-split-export-declaration@npm:^7.22.6": version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: @@ -1054,64 +1057,55 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: c0641144cf1a7e7dc93f3d5f16d5327465b6cf5d036b48be61ecba41e1eece161b48f46b7f960951b67f8c3533ce506b16dece576baef4d8b3b49f8c65410f90 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.16.7, @babel/helper-validator-identifier@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-identifier@npm:7.22.5" - checksum: 7f0f30113474a28298c12161763b49de5018732290ca4de13cdaefd4fd0d635a6fe3f6686c37a02905fb1e64f21a5ee2b55140cf7b070e729f1bd66866506aea +"@babel/helper-validator-identifier@npm:^7.16.7, @babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-option@npm:7.22.5" - checksum: bbeca8a85ee86990215c0424997438b388b8d642d69b9f86c375a174d3cdeb270efafd1ff128bc7a1d370923d13b6e45829ba8581c027620e83e3a80c5c414b3 +"@babel/helper-validator-option@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: 537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e languageName: node linkType: hard -"@babel/helpers@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/helpers@npm:7.22.6" +"@babel/helpers@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/helpers@npm:7.23.9" dependencies: - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.6 - "@babel/types": ^7.22.5 - checksum: 5c1f33241fe7bf7709868c2105134a0a86dca26a0fbd508af10a89312b1f77ca38ebae43e50be3b208613c5eacca1559618af4ca236f0abc55d294800faeff30 + "@babel/template": ^7.23.9 + "@babel/traverse": ^7.23.9 + "@babel/types": ^7.23.9 + checksum: 2678231192c0471dbc2fc403fb19456cc46b1afefcfebf6bc0f48b2e938fdb0fef2e0fe90c8c8ae1f021dae5012b700372e4b5d15867f1d7764616532e4a6324 languageName: node linkType: hard -"@babel/highlight@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/highlight@npm:7.22.5" +"@babel/highlight@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/highlight@npm:7.23.4" dependencies: - "@babel/helper-validator-identifier": ^7.22.5 - chalk: ^2.0.0 + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 js-tokens: ^4.0.0 - checksum: f61ae6de6ee0ea8d9b5bcf2a532faec5ab0a1dc0f7c640e5047fc61630a0edb88b18d8c92eb06566d30da7a27db841aca11820ecd3ebe9ce514c9350fbed39c4 + checksum: 643acecdc235f87d925979a979b539a5d7d1f31ae7db8d89047269082694122d11aa85351304c9c978ceeb6d250591ccadb06c366f358ccee08bb9c122476b89 languageName: node linkType: hard -"@babel/parser@npm:^7.0.0, @babel/parser@npm:^7.21.4": - version: 7.23.0 - resolution: "@babel/parser@npm:7.23.0" +"@babel/parser@npm:^7.0.0, @babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.5, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.4, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/parser@npm:7.23.9" bin: parser: ./bin/babel-parser.js - checksum: 453fdf8b9e2c2b7d7b02139e0ce003d1af21947bbc03eb350fb248ee335c9b85e4ab41697ddbdd97079698de825a265e45a0846bb2ed47a2c7c1df833f42a354 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.17.3, @babel/parser@npm:^7.20.5, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7": - version: 7.22.7 - resolution: "@babel/parser@npm:7.22.7" - bin: - parser: ./bin/babel-parser.js - checksum: 02209ddbd445831ee8bf966fdf7c29d189ed4b14343a68eb2479d940e7e3846340d7cc6bd654a5f3d87d19dc84f49f50a58cf9363bee249dc5409ff3ba3dab54 + checksum: e7cd4960ac8671774e13803349da88d512f9292d7baa952173260d3e8f15620a28a3701f14f709d769209022f9e7b79965256b8be204fc550cfe783cdcabe7c7 languageName: node linkType: hard @@ -1171,13 +1165,13 @@ __metadata: linkType: hard "@babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-jsx@npm:7.22.5" + version: 7.23.3 + resolution: "@babel/plugin-syntax-jsx@npm:7.23.3" dependencies: "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8829d30c2617ab31393d99cec2978e41f014f4ac6f01a1cecf4c4dd8320c3ec12fdc3ce121126b2d8d32f6887e99ca1a0bad53dedb1e6ad165640b92b24980ce + checksum: 89037694314a74e7f0e7a9c8d3793af5bf6b23d80950c29b360db1c66859d67f60711ea437e70ad6b5b4b29affe17eababda841b6c01107c2b638e0493bafb4e languageName: node linkType: hard @@ -1259,69 +1253,69 @@ __metadata: linkType: hard "@babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-typescript@npm:7.22.5" + version: 7.23.3 + resolution: "@babel/plugin-syntax-typescript@npm:7.23.3" dependencies: "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8ab7718fbb026d64da93681a57797d60326097fd7cb930380c8bffd9eb101689e90142c760a14b51e8e69c88a73ba3da956cb4520a3b0c65743aee5c71ef360a + checksum: abfad3a19290d258b028e285a1f34c9b8a0cbe46ef79eafed4ed7ffce11b5d0720b5e536c82f91cbd8442cde35a3dd8e861fa70366d87ff06fdc0d4756e30876 languageName: node linkType: hard "@babel/runtime@npm:^7.21.0": - version: 7.22.6 - resolution: "@babel/runtime@npm:7.22.6" + version: 7.23.9 + resolution: "@babel/runtime@npm:7.23.9" dependencies: - regenerator-runtime: ^0.13.11 - checksum: e585338287c4514a713babf4fdb8fc2a67adcebab3e7723a739fc62c79cfda875b314c90fd25f827afb150d781af97bc16c85bfdbfa2889f06053879a1ddb597 + regenerator-runtime: ^0.14.0 + checksum: 6bbebe8d27c0c2dd275d1ac197fc1a6c00e18dab68cc7aaff0adc3195b45862bae9c4cc58975629004b0213955b2ed91e99eccb3d9b39cabea246c657323d667 languageName: node linkType: hard -"@babel/template@npm:^7.22.5, @babel/template@npm:^7.3.3": - version: 7.22.5 - resolution: "@babel/template@npm:7.22.5" +"@babel/template@npm:^7.22.15, @babel/template@npm:^7.23.9, @babel/template@npm:^7.3.3": + version: 7.23.9 + resolution: "@babel/template@npm:7.23.9" dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/parser": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: c5746410164039aca61829cdb42e9a55410f43cace6f51ca443313f3d0bdfa9a5a330d0b0df73dc17ef885c72104234ae05efede37c1cc8a72dc9f93425977a3 + "@babel/code-frame": ^7.23.5 + "@babel/parser": ^7.23.9 + "@babel/types": ^7.23.9 + checksum: 6e67414c0f7125d7ecaf20c11fab88085fa98a96c3ef10da0a61e962e04fdf3a18a496a66047005ddd1bb682a7cc7842d556d1db2f3f3f6ccfca97d5e445d342 languageName: node linkType: hard -"@babel/traverse@npm:7.17.3": - version: 7.17.3 - resolution: "@babel/traverse@npm:7.17.3" +"@babel/traverse@npm:7.23.2": + version: 7.23.2 + resolution: "@babel/traverse@npm:7.23.2" dependencies: - "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.17.3 - "@babel/helper-environment-visitor": ^7.16.7 - "@babel/helper-function-name": ^7.16.7 - "@babel/helper-hoist-variables": ^7.16.7 - "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/parser": ^7.17.3 - "@babel/types": ^7.17.0 + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.23.0 + "@babel/types": ^7.23.0 debug: ^4.1.0 globals: ^11.1.0 - checksum: 780d7ecf711758174989794891af08d378f81febdb8932056c0d9979524bf0298e28f8e7708a872d7781151506c28f56c85c63ea3f1f654662c2fcb8a3eb9fdc + checksum: 26a1eea0dde41ab99dde8b9773a013a0dc50324e5110a049f5d634e721ff08afffd54940b3974a20308d7952085ac769689369e9127dea655f868c0f6e1ab35d languageName: node linkType: hard -"@babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8": - version: 7.22.8 - resolution: "@babel/traverse@npm:7.22.8" +"@babel/traverse@npm:^7.23.9": + version: 7.23.9 + resolution: "@babel/traverse@npm:7.23.9" dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.7 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.6 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 "@babel/helper-hoist-variables": ^7.22.5 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.22.7 - "@babel/types": ^7.22.5 - debug: ^4.1.0 + "@babel/parser": ^7.23.9 + "@babel/types": ^7.23.9 + debug: ^4.3.1 globals: ^11.1.0 - checksum: a381369bc3eedfd13ed5fef7b884657f1c29024ea7388198149f0edc34bd69ce3966e9f40188d15f56490a5e12ba250ccc485f2882b53d41b054fccefb233e33 + checksum: a932f7aa850e158c00c97aad22f639d48c72805c687290f6a73e30c5c4957c07f5d28310c9bf59648e2980fe6c9d16adeb2ff92a9ca0f97fa75739c1328fc6c3 languageName: node linkType: hard @@ -1335,14 +1329,14 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.17.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/types@npm:7.22.5" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.17.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.23.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": + version: 7.23.9 + resolution: "@babel/types@npm:7.23.9" dependencies: - "@babel/helper-string-parser": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.5 + "@babel/helper-string-parser": ^7.23.4 + "@babel/helper-validator-identifier": ^7.22.20 to-fast-properties: ^2.0.0 - checksum: c13a9c1dc7d2d1a241a2f8363540cb9af1d66e978e8984b400a20c4f38ba38ca29f06e26a0f2d49a70bad9e57615dac09c35accfddf1bb90d23cd3e0a0bab892 + checksum: 0a9b008e9bfc89beb8c185e620fa0f8ed6c771f1e1b2e01e1596870969096fec7793898a1d64a035176abf1dd13e2668ee30bf699f2d92c210a8128f4b151e65 languageName: node linkType: hard @@ -1353,14 +1347,21 @@ __metadata: languageName: node linkType: hard -"@chainsafe/is-ip@npm:^2.0.1": - version: 2.0.1 - resolution: "@chainsafe/is-ip@npm:2.0.1" - checksum: c5bbebe58eadc700d12112713fd75e41ae26020eedcac0e8b593fdda16a180239ede1d68d55b500fd8b30189c9a82b5e10769ed86a816e879c83248069152b79 +"@chainsafe/as-chacha20poly1305@npm:^0.1.0": + version: 0.1.0 + resolution: "@chainsafe/as-chacha20poly1305@npm:0.1.0" + checksum: 2bf38f0595bb379489388174e2049e57ae1512815a80fddfe5b9055865739a970651847892233e53cde6a3e34554ede97d1abd8a0f02b4a0005a1a6cf0146a6c languageName: node linkType: hard -"@chainsafe/is-ip@npm:^2.0.2": +"@chainsafe/as-sha256@npm:^0.4.1": + version: 0.4.1 + resolution: "@chainsafe/as-sha256@npm:0.4.1" + checksum: 6d86975e648ecdafd366802278ac15b392b252e967f3681412ec48b5a3518b936cc5e977517499882b084991446d25787d98f8f585891943688cc81549a44e9a + languageName: node + linkType: hard + +"@chainsafe/is-ip@npm:^2.0.1, @chainsafe/is-ip@npm:^2.0.2": version: 2.0.2 resolution: "@chainsafe/is-ip@npm:2.0.2" checksum: 2600350ba1c8fbad5d1ebee71317beeb29fbaebf43780d89e30f8c6c2d27b95ebdab0284dfbab7336b5eb6d8ffcc7081e3e4c5b221889dc366463f83bbe38adb @@ -1368,14 +1369,16 @@ __metadata: linkType: hard "@chainsafe/libp2p-noise@npm:^13.0.0": - version: 13.0.0 - resolution: "@chainsafe/libp2p-noise@npm:13.0.0" + version: 13.0.5 + resolution: "@chainsafe/libp2p-noise@npm:13.0.5" dependencies: + "@chainsafe/as-chacha20poly1305": ^0.1.0 + "@chainsafe/as-sha256": ^0.4.1 "@libp2p/crypto": ^2.0.0 "@libp2p/interface": ^0.1.0 "@libp2p/logger": ^3.0.0 "@libp2p/peer-id": ^3.0.0 - "@noble/ciphers": ^0.1.4 + "@noble/ciphers": ^0.4.0 "@noble/curves": ^1.1.0 "@noble/hashes": ^1.3.1 it-byte-stream: ^1.0.0 @@ -1387,22 +1390,23 @@ __metadata: protons-runtime: ^5.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.4 - checksum: 177c44003cb550b3ce1f867db2f5a3bb8f97bf368095a1a5bd4ccddd64bc2fc4167119a61fa6ed045abe8ef2dbbea9ddac9b8e1d6381d9056749b900029b8de5 + wherearewe: ^2.0.1 + checksum: 98dd78bfd547501280c7a318acfa81624016351f18e0a28debe451340418fd263f90ce8d7358d5b83f61429522de6631321606b98eda35609114041853057af1 languageName: node linkType: hard "@chainsafe/libp2p-yamux@npm:^5.0.0": - version: 5.0.0 - resolution: "@chainsafe/libp2p-yamux@npm:5.0.0" + version: 5.0.4 + resolution: "@chainsafe/libp2p-yamux@npm:5.0.4" dependencies: "@libp2p/interface": ^0.1.0 "@libp2p/logger": ^3.0.0 - abortable-iterator: ^5.0.1 + get-iterator: ^2.0.1 it-foreach: ^2.0.3 it-pipe: ^3.0.1 it-pushable: ^3.2.0 uint8arraylist: ^2.4.3 - checksum: 8de6f9e16097ed983ab3d0da2dffe752f09c2c09473783d39dcb2d54b788fe4353bbed417a3870fb4de151de906a734a73cd53e2b2b4ccec4392d2195828137c + checksum: 58c33b28d8da2b8c6813127de2cc4005f2f09d845cf535c56a3db0495774a2feb935d2813d2141bb6a747f3c1181dfde415945821d489ac7f987e36df744721f languageName: node linkType: hard @@ -1415,10 +1419,10 @@ __metadata: languageName: node linkType: hard -"@colors/colors@npm:1.5.0": - version: 1.5.0 - resolution: "@colors/colors@npm:1.5.0" - checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 +"@colors/colors@npm:1.6.0, @colors/colors@npm:^1.6.0": + version: 1.6.0 + resolution: "@colors/colors@npm:1.6.0" + checksum: aa209963e0c3218e80a4a20553ba8c0fbb6fa13140540b4e5f97923790be06801fc90172c1114fc8b7e888b3d012b67298cde6b9e81521361becfaee400c662f languageName: node linkType: hard @@ -1470,156 +1474,156 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/android-arm64@npm:0.18.17" +"@esbuild/android-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm64@npm:0.18.20" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/android-arm@npm:0.18.17" +"@esbuild/android-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm@npm:0.18.20" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/android-x64@npm:0.18.17" +"@esbuild/android-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-x64@npm:0.18.20" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/darwin-arm64@npm:0.18.17" +"@esbuild/darwin-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-arm64@npm:0.18.20" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/darwin-x64@npm:0.18.17" +"@esbuild/darwin-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-x64@npm:0.18.20" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/freebsd-arm64@npm:0.18.17" +"@esbuild/freebsd-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-arm64@npm:0.18.20" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/freebsd-x64@npm:0.18.17" +"@esbuild/freebsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-x64@npm:0.18.20" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-arm64@npm:0.18.17" +"@esbuild/linux-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm64@npm:0.18.20" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-arm@npm:0.18.17" +"@esbuild/linux-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm@npm:0.18.20" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-ia32@npm:0.18.17" +"@esbuild/linux-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ia32@npm:0.18.20" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-loong64@npm:0.18.17" +"@esbuild/linux-loong64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-loong64@npm:0.18.20" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-mips64el@npm:0.18.17" +"@esbuild/linux-mips64el@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-mips64el@npm:0.18.20" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-ppc64@npm:0.18.17" +"@esbuild/linux-ppc64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ppc64@npm:0.18.20" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-riscv64@npm:0.18.17" +"@esbuild/linux-riscv64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-riscv64@npm:0.18.20" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-s390x@npm:0.18.17" +"@esbuild/linux-s390x@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-s390x@npm:0.18.20" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/linux-x64@npm:0.18.17" +"@esbuild/linux-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-x64@npm:0.18.20" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/netbsd-x64@npm:0.18.17" +"@esbuild/netbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/netbsd-x64@npm:0.18.20" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/openbsd-x64@npm:0.18.17" +"@esbuild/openbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/openbsd-x64@npm:0.18.20" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/sunos-x64@npm:0.18.17" +"@esbuild/sunos-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/sunos-x64@npm:0.18.20" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/win32-arm64@npm:0.18.17" +"@esbuild/win32-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-arm64@npm:0.18.20" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/win32-ia32@npm:0.18.17" +"@esbuild/win32-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-ia32@npm:0.18.20" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.18.17": - version: 0.18.17 - resolution: "@esbuild/win32-x64@npm:0.18.17" +"@esbuild/win32-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-x64@npm:0.18.20" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1636,15 +1640,15 @@ __metadata: linkType: hard "@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": - version: 4.6.2 - resolution: "@eslint-community/regexpp@npm:4.6.2" - checksum: a3c341377b46b54fa228f455771b901d1a2717f95d47dcdf40199df30abc000ba020f747f114f08560d119e979d882a94cf46cfc51744544d54b00319c0f2724 + version: 4.10.0 + resolution: "@eslint-community/regexpp@npm:4.10.0" + checksum: 2a6e345429ea8382aaaf3a61f865cae16ed44d31ca917910033c02dc00d505d939f10b81e079fa14d43b51499c640138e153b7e40743c4c094d9df97d4e56f7b languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.1": - version: 2.1.1 - resolution: "@eslint/eslintrc@npm:2.1.1" +"@eslint/eslintrc@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/eslintrc@npm:2.1.4" dependencies: ajv: ^6.12.4 debug: ^4.3.2 @@ -1655,25 +1659,25 @@ __metadata: js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: bf909ea183d27238c257a82d4ffdec38ca94b906b4b8dfae02ecbe7ecc9e5a8182ef5e469c808bb8cb4fea4750f43ac4ca7c4b4a167b6cd7e3aaacd386b2bd25 + checksum: 10957c7592b20ca0089262d8c2a8accbad14b4f6507e35416c32ee6b4dbf9cad67dfb77096bbd405405e9ada2b107f3797fe94362e1c55e0b09d6e90dd149127 languageName: node linkType: hard -"@eslint/js@npm:^8.46.0": - version: 8.46.0 - resolution: "@eslint/js@npm:8.46.0" - checksum: 7aed479832302882faf5bec37e9d068f270f84c19b3fb529646a7c1b031e73a312f730569c78806492bc09cfce3d7651dfab4ce09a56cbb06bc6469449e56377 +"@eslint/js@npm:8.56.0": + version: 8.56.0 + resolution: "@eslint/js@npm:8.56.0" + checksum: 5804130574ef810207bdf321c265437814e7a26f4e6fac9b496de3206afd52f533e09ec002a3be06cd9adcc9da63e727f1883938e663c4e4751c007d5b58e539 languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.10": - version: 0.11.10 - resolution: "@humanwhocodes/config-array@npm:0.11.10" +"@humanwhocodes/config-array@npm:^0.11.13": + version: 0.11.14 + resolution: "@humanwhocodes/config-array@npm:0.11.14" dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 + "@humanwhocodes/object-schema": ^2.0.2 + debug: ^4.3.1 minimatch: ^3.0.5 - checksum: 1b1302e2403d0e35bc43e66d67a2b36b0ad1119efc704b5faff68c41f791a052355b010fb2d27ef022670f550de24cd6d08d5ecf0821c16326b7dcd0ee5d5d8a + checksum: 861ccce9eaea5de19546653bccf75bf09fe878bc39c3aab00aeee2d2a0e654516adad38dd1098aab5e3af0145bbcbf3f309bdf4d964f8dab9dcd5834ae4c02f2 languageName: node linkType: hard @@ -1684,10 +1688,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 +"@humanwhocodes/object-schema@npm:^2.0.2": + version: 2.0.2 + resolution: "@humanwhocodes/object-schema@npm:2.0.2" + checksum: 2fc11503361b5fb4f14714c700c02a3f4c7c93e9acd6b87a29f62c522d90470f364d6161b03d1cc618b979f2ae02aed1106fd29d302695d8927e2fc8165ba8ee languageName: node linkType: hard @@ -1732,50 +1736,50 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/console@npm:29.6.2" +"@jest/console@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/console@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@types/node": "*" chalk: ^4.0.0 - jest-message-util: ^29.6.2 - jest-util: ^29.6.2 + jest-message-util: ^29.7.0 + jest-util: ^29.7.0 slash: ^3.0.0 - checksum: 1198667bda0430770c3e9b92681c0ee9f8346394574071c633f306192ac5f08e12972d6a5fdf03eb0d441051c8439bce0f6f9f355dc60d98777a35328331ba2e + checksum: 0e3624e32c5a8e7361e889db70b170876401b7d70f509a2538c31d5cd50deb0c1ae4b92dc63fe18a0902e0a48c590c21d53787a0df41a52b34fa7cab96c384d6 languageName: node linkType: hard -"@jest/core@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/core@npm:29.6.2" +"@jest/core@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/core@npm:29.7.0" dependencies: - "@jest/console": ^29.6.2 - "@jest/reporters": ^29.6.2 - "@jest/test-result": ^29.6.2 - "@jest/transform": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/console": ^29.7.0 + "@jest/reporters": ^29.7.0 + "@jest/test-result": ^29.7.0 + "@jest/transform": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" ansi-escapes: ^4.2.1 chalk: ^4.0.0 ci-info: ^3.2.0 exit: ^0.1.2 graceful-fs: ^4.2.9 - jest-changed-files: ^29.5.0 - jest-config: ^29.6.2 - jest-haste-map: ^29.6.2 - jest-message-util: ^29.6.2 - jest-regex-util: ^29.4.3 - jest-resolve: ^29.6.2 - jest-resolve-dependencies: ^29.6.2 - jest-runner: ^29.6.2 - jest-runtime: ^29.6.2 - jest-snapshot: ^29.6.2 - jest-util: ^29.6.2 - jest-validate: ^29.6.2 - jest-watcher: ^29.6.2 + jest-changed-files: ^29.7.0 + jest-config: ^29.7.0 + jest-haste-map: ^29.7.0 + jest-message-util: ^29.7.0 + jest-regex-util: ^29.6.3 + jest-resolve: ^29.7.0 + jest-resolve-dependencies: ^29.7.0 + jest-runner: ^29.7.0 + jest-runtime: ^29.7.0 + jest-snapshot: ^29.7.0 + jest-util: ^29.7.0 + jest-validate: ^29.7.0 + jest-watcher: ^29.7.0 micromatch: ^4.0.4 - pretty-format: ^29.6.2 + pretty-format: ^29.7.0 slash: ^3.0.0 strip-ansi: ^6.0.0 peerDependencies: @@ -1783,76 +1787,76 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: 6bbb3886430248c0092f275b1b946a701406732f7442c04e63e4ee2297c2ec02d8ceeec508a202e08128197699b2bcddbae2c2f74adb2cf30f2f0d7d94a7c2dc + checksum: af759c9781cfc914553320446ce4e47775ae42779e73621c438feb1e4231a5d4862f84b1d8565926f2d1aab29b3ec3dcfdc84db28608bdf5f29867124ebcfc0d languageName: node linkType: hard -"@jest/environment@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/environment@npm:29.6.2" +"@jest/environment@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/environment@npm:29.7.0" dependencies: - "@jest/fake-timers": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/fake-timers": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" - jest-mock: ^29.6.2 - checksum: c7de0e4c0d9166e02d0eb166574e05ec460e1db3b69d6476e63244edd52d7c917e6876af55fe723ff3086f52c0b1869dec60654054735a7a48c9d4ac43af2a25 + jest-mock: ^29.7.0 + checksum: 6fb398143b2543d4b9b8d1c6dbce83fa5247f84f550330604be744e24c2bd2178bb893657d62d1b97cf2f24baf85c450223f8237cccb71192c36a38ea2272934 languageName: node linkType: hard -"@jest/expect-utils@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/expect-utils@npm:29.6.2" +"@jest/expect-utils@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/expect-utils@npm:29.7.0" dependencies: - jest-get-type: ^29.4.3 - checksum: 0decf2009aa3735f9df469e78ce1721c2815e4278439887e0cf0321ca8979541a22515d114a59b2445a6cd70a074b09dc9c00b5e7b3b3feac5174b9c4a78b2e1 + jest-get-type: ^29.6.3 + checksum: 75eb177f3d00b6331bcaa057e07c0ccb0733a1d0a1943e1d8db346779039cb7f103789f16e502f888a3096fb58c2300c38d1f3748b36a7fa762eb6f6d1b160ed languageName: node linkType: hard -"@jest/expect@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/expect@npm:29.6.2" +"@jest/expect@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/expect@npm:29.7.0" dependencies: - expect: ^29.6.2 - jest-snapshot: ^29.6.2 - checksum: bd2d88a4e7c5420079c239afef341ec53dc7e353816cd13acbb42631a31fd321fe58677bb43a4dba851028f4c7e31da7980314e9094cd5b348896cb6cd3d42b2 + expect: ^29.7.0 + jest-snapshot: ^29.7.0 + checksum: a01cb85fd9401bab3370618f4b9013b90c93536562222d920e702a0b575d239d74cecfe98010aaec7ad464f67cf534a353d92d181646a4b792acaa7e912ae55e languageName: node linkType: hard -"@jest/fake-timers@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/fake-timers@npm:29.6.2" +"@jest/fake-timers@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/fake-timers@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@sinonjs/fake-timers": ^10.0.2 "@types/node": "*" - jest-message-util: ^29.6.2 - jest-mock: ^29.6.2 - jest-util: ^29.6.2 - checksum: 1abcda02f22d2ba32e178b7ab80a9180235a6c75ec9faef33324627b19a70dad64889a9ea49b8f07230e14a6e683b9120542c6d1d6b2ecaf937f4efde32dad88 + jest-message-util: ^29.7.0 + jest-mock: ^29.7.0 + jest-util: ^29.7.0 + checksum: caf2bbd11f71c9241b458d1b5a66cbe95debc5a15d96442444b5d5c7ba774f523c76627c6931cca5e10e76f0d08761f6f1f01a608898f4751a0eee54fc3d8d00 languageName: node linkType: hard -"@jest/globals@npm:^29.5.0, @jest/globals@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/globals@npm:29.6.2" +"@jest/globals@npm:^29.5.0, @jest/globals@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/globals@npm:29.7.0" dependencies: - "@jest/environment": ^29.6.2 - "@jest/expect": ^29.6.2 - "@jest/types": ^29.6.1 - jest-mock: ^29.6.2 - checksum: aa4a54f19cc025205bc696546940e1fe9c752c2d4d825852088aa76d44677ebba1ec66fabb78e615480cff23a06a70b5a3f893ab5163d901cdfa0d2267870b10 + "@jest/environment": ^29.7.0 + "@jest/expect": ^29.7.0 + "@jest/types": ^29.6.3 + jest-mock: ^29.7.0 + checksum: 97dbb9459135693ad3a422e65ca1c250f03d82b2a77f6207e7fa0edd2c9d2015fbe4346f3dc9ebff1678b9d8da74754d4d440b7837497f8927059c0642a22123 languageName: node linkType: hard -"@jest/reporters@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/reporters@npm:29.6.2" +"@jest/reporters@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/reporters@npm:29.7.0" dependencies: "@bcoe/v8-coverage": ^0.2.3 - "@jest/console": ^29.6.2 - "@jest/test-result": ^29.6.2 - "@jest/transform": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/console": ^29.7.0 + "@jest/test-result": ^29.7.0 + "@jest/transform": ^29.7.0 + "@jest/types": ^29.6.3 "@jridgewell/trace-mapping": ^0.3.18 "@types/node": "*" chalk: ^4.0.0 @@ -1861,13 +1865,13 @@ __metadata: glob: ^7.1.3 graceful-fs: ^4.2.9 istanbul-lib-coverage: ^3.0.0 - istanbul-lib-instrument: ^5.1.0 + istanbul-lib-instrument: ^6.0.0 istanbul-lib-report: ^3.0.0 istanbul-lib-source-maps: ^4.0.0 istanbul-reports: ^3.1.3 - jest-message-util: ^29.6.2 - jest-util: ^29.6.2 - jest-worker: ^29.6.2 + jest-message-util: ^29.7.0 + jest-util: ^29.7.0 + jest-worker: ^29.7.0 slash: ^3.0.0 string-length: ^4.0.1 strip-ansi: ^6.0.0 @@ -1877,88 +1881,88 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: 7cf880d0730cee7d24ee96928003ef6946bf93423b0ae9a2edb53cae2c231b8ac50ec264f48a73744e3f11ca319cd414edacf99b2e7bf37cd72fe0b362090dd1 + checksum: 7eadabd62cc344f629024b8a268ecc8367dba756152b761bdcb7b7e570a3864fc51b2a9810cd310d85e0a0173ef002ba4528d5ea0329fbf66ee2a3ada9c40455 languageName: node linkType: hard -"@jest/schemas@npm:^29.6.0": - version: 29.6.0 - resolution: "@jest/schemas@npm:29.6.0" +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" dependencies: "@sinclair/typebox": ^0.27.8 - checksum: c00511c69cf89138a7d974404d3a5060af375b5a52b9c87215d91873129b382ca11c1ff25bd6d605951404bb381ddce5f8091004a61e76457da35db1f5c51365 + checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 languageName: node linkType: hard -"@jest/source-map@npm:^29.6.0": - version: 29.6.0 - resolution: "@jest/source-map@npm:29.6.0" +"@jest/source-map@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/source-map@npm:29.6.3" dependencies: "@jridgewell/trace-mapping": ^0.3.18 callsites: ^3.0.0 graceful-fs: ^4.2.9 - checksum: 9c6c40387410bb70b2fae8124287fc28f6bdd1b2d7f24348e8611e1bb638b404518228a4ce64a582365b589c536ae8e7ebab0126cef59a87874b71061d19783b + checksum: bcc5a8697d471396c0003b0bfa09722c3cd879ad697eb9c431e6164e2ea7008238a01a07193dfe3cbb48b1d258eb7251f6efcea36f64e1ebc464ea3c03ae2deb languageName: node linkType: hard -"@jest/test-result@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/test-result@npm:29.6.2" +"@jest/test-result@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/test-result@npm:29.7.0" dependencies: - "@jest/console": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/console": ^29.7.0 + "@jest/types": ^29.6.3 "@types/istanbul-lib-coverage": ^2.0.0 collect-v8-coverage: ^1.0.0 - checksum: 8aff37f18c8d2df4d9f453d57ec018a6479eb697fabcf74b1ca06e34553da1d7a2b85580a290408ba0b02e58543263244a2cb065c7c7180c8d8180cc78444fbd + checksum: 67b6317d526e335212e5da0e768e3b8ab8a53df110361b80761353ad23b6aea4432b7c5665bdeb87658ea373b90fb1afe02ed3611ef6c858c7fba377505057fa languageName: node linkType: hard -"@jest/test-sequencer@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/test-sequencer@npm:29.6.2" +"@jest/test-sequencer@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/test-sequencer@npm:29.7.0" dependencies: - "@jest/test-result": ^29.6.2 + "@jest/test-result": ^29.7.0 graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.2 + jest-haste-map: ^29.7.0 slash: ^3.0.0 - checksum: 12dc2577e45eeb98b85d1769846b7d6effa536907986ad3c4cbd014df9e24431a564cc8cd94603332e4b1f9bfb421371883efc6a5085b361a52425ffc2a52dc6 + checksum: 73f43599017946be85c0b6357993b038f875b796e2f0950487a82f4ebcb115fa12131932dd9904026b4ad8be131fe6e28bd8d0aa93b1563705185f9804bff8bd languageName: node linkType: hard -"@jest/transform@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/transform@npm:29.6.2" +"@jest/transform@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/transform@npm:29.7.0" dependencies: "@babel/core": ^7.11.6 - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@jridgewell/trace-mapping": ^0.3.18 babel-plugin-istanbul: ^6.1.1 chalk: ^4.0.0 convert-source-map: ^2.0.0 fast-json-stable-stringify: ^2.1.0 graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.2 - jest-regex-util: ^29.4.3 - jest-util: ^29.6.2 + jest-haste-map: ^29.7.0 + jest-regex-util: ^29.6.3 + jest-util: ^29.7.0 micromatch: ^4.0.4 pirates: ^4.0.4 slash: ^3.0.0 write-file-atomic: ^4.0.2 - checksum: ffb8c3c344cd48bedadec295d9c436737eccc39c1f0868aa9753b76397b33b2e5b121058af6f287ba6f2036181137e37df1212334bfa9d9a712986a4518cdc18 + checksum: 0f8ac9f413903b3cb6d240102db848f2a354f63971ab885833799a9964999dd51c388162106a807f810071f864302cdd8e3f0c241c29ce02d85a36f18f3f40ab languageName: node linkType: hard -"@jest/types@npm:^29.6.1": - version: 29.6.1 - resolution: "@jest/types@npm:29.6.1" +"@jest/types@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/types@npm:29.6.3" dependencies: - "@jest/schemas": ^29.6.0 + "@jest/schemas": ^29.6.3 "@types/istanbul-lib-coverage": ^2.0.0 "@types/istanbul-reports": ^3.0.0 "@types/node": "*" "@types/yargs": ^17.0.8 chalk: ^4.0.0 - checksum: 89fc1ccf71a84fe0da643e0675b1cfe6a6f19ea72e935b2ab1dbdb56ec547e94433fb59b3536d3832a6e156c077865b7176fe9dae707dab9c3d2f9405ba6233c + checksum: a0bcf15dbb0eca6bdd8ce61a3fb055349d40268622a7670a3b2eb3c3dbafe9eb26af59938366d520b86907b9505b0f9b29b85cec11579a9e580694b87cd90fcc languageName: node linkType: hard @@ -1973,14 +1977,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:3.1.0": - version: 3.1.0 - resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.0.3": +"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.1 resolution: "@jridgewell/resolve-uri@npm:3.1.1" checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 @@ -2004,14 +2001,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14": - version: 1.4.14 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 @@ -2028,13 +2018,13 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.18 - resolution: "@jridgewell/trace-mapping@npm:0.3.18" +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.22 + resolution: "@jridgewell/trace-mapping@npm:0.3.22" dependencies: - "@jridgewell/resolve-uri": 3.1.0 - "@jridgewell/sourcemap-codec": 1.4.14 - checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: ac7dd2cfe0b479aa1b81776d40d789243131cc792dc8b6b6a028c70fcd6171958ae1a71bf67b618ffe3c0c3feead9870c095ee46a5e30319410d92976b28f498 languageName: node linkType: hard @@ -2048,39 +2038,23 @@ __metadata: linkType: hard "@libp2p/bootstrap@npm:^9.0.4": - version: 9.0.4 - resolution: "@libp2p/bootstrap@npm:9.0.4" + version: 9.0.12 + resolution: "@libp2p/bootstrap@npm:9.0.12" dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 - "@libp2p/peer-id": ^3.0.2 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 + "@libp2p/peer-id": ^3.0.6 "@multiformats/mafmt": ^12.1.2 "@multiformats/multiaddr": ^12.1.5 - checksum: 10e66b4b20645606319ed9192c9672e424aa89cd3e16b3202ac23b36bdf188873882bf71535b6b9adcef4720c69af7cf3f29a39a8139334b11dcdefbed8dcd4a - languageName: node - linkType: hard - -"@libp2p/crypto@npm:^2.0.0, @libp2p/crypto@npm:^2.0.3": - version: 2.0.3 - resolution: "@libp2p/crypto@npm:2.0.3" - dependencies: - "@libp2p/interface": ^0.1.2 - "@noble/curves": ^1.1.0 - "@noble/hashes": ^1.3.1 - multiformats: ^12.0.1 - node-forge: ^1.1.0 - protons-runtime: ^5.0.0 - uint8arraylist: ^2.4.3 - uint8arrays: ^4.0.6 - checksum: b1806cea33fe5f16ff6d7d920f8cf77a33d06f418d9488f0b40c0251568e01a12014ee84481048764bc1d2a4372ba536842f2fb4f9879c529c6a2a0755b77e95 + checksum: 249198129b806bf5525d527074e9151c96a411c61474543f8e2679664733af0873c5267b4c579fa29ac4f64f7fe3dae32e70dba66acafd321a3368adc579bccf languageName: node linkType: hard -"@libp2p/crypto@npm:^2.0.4": - version: 2.0.4 - resolution: "@libp2p/crypto@npm:2.0.4" +"@libp2p/crypto@npm:^2.0.0, @libp2p/crypto@npm:^2.0.8": + version: 2.0.8 + resolution: "@libp2p/crypto@npm:2.0.8" dependencies: - "@libp2p/interface": ^0.1.2 + "@libp2p/interface": ^0.1.6 "@noble/curves": ^1.1.0 "@noble/hashes": ^1.3.1 multiformats: ^12.0.1 @@ -2088,7 +2062,7 @@ __metadata: protons-runtime: ^5.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: 1e0a0e8006e9ca7caaec16ce94d193063749fc7f62a7b3d0b4469915e2837c380987baa400a9f35ee13c23783f8317f8bc58b8ed647a5b4bf55635a2a909ae97 + checksum: 4047dc54e33670c7aa4717b9f5e7980717e00ef6a2cefaae336cdcd88f9ca38d7f29a1c642d8cbc7cd85bd2957eb79b869791b4f48fb2e91652b2d87224a136d languageName: node linkType: hard @@ -2116,15 +2090,15 @@ __metadata: languageName: node linkType: hard -"@libp2p/interface-internal@npm:^0.1.4": - version: 0.1.4 - resolution: "@libp2p/interface-internal@npm:0.1.4" +"@libp2p/interface-internal@npm:^0.1.9": + version: 0.1.12 + resolution: "@libp2p/interface-internal@npm:0.1.12" dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/peer-collections": ^4.0.3 + "@libp2p/interface": ^0.1.6 + "@libp2p/peer-collections": ^4.0.8 "@multiformats/multiaddr": ^12.1.5 uint8arraylist: ^2.4.3 - checksum: 26bbd1a2811baa089eb3ec9031f64d8b7c5e183e4f4a1f4b6c37b1de22985e61e63f9ba06fa7cbc91d60217d66773407361c8ea7abba93cf900e633547d5da97 + checksum: 3ffa5843fd7fd046f5ab4cb70a96da6c392ba2f24f832a3b99a0b20653fa6478c924caacd8c1a6aa4de2cb2a39669778ed804bfcb5c0c232a775cc1e29f3dd17 languageName: node linkType: hard @@ -2246,9 +2220,9 @@ __metadata: languageName: node linkType: hard -"@libp2p/interface@npm:^0.1.0, @libp2p/interface@npm:^0.1.1, @libp2p/interface@npm:^0.1.2": - version: 0.1.2 - resolution: "@libp2p/interface@npm:0.1.2" +"@libp2p/interface@npm:^0.1.0, @libp2p/interface@npm:^0.1.2, @libp2p/interface@npm:^0.1.6": + version: 0.1.6 + resolution: "@libp2p/interface@npm:0.1.6" dependencies: "@multiformats/multiaddr": ^12.1.5 abortable-iterator: ^5.0.1 @@ -2256,12 +2230,27 @@ __metadata: it-stream-types: ^2.0.1 multiformats: ^12.0.1 p-defer: ^4.0.0 + race-signal: ^1.0.0 uint8arraylist: ^2.4.3 - checksum: d33748ba16473c622802ee95e57445f2ac79b1ddffbaba7499157a769c57f9c1374ac10de72517e7899f88808e6fee09d77aef928d8eeaaf2bb8951fa93653a7 + checksum: dbf0c4544bbb2a299d54615e8ef553324657e7cb06a2fdc3f1a99d785276c69882841b0e9cf73b934923318d04fe6c6f7ef59194d438a126d0d8d3a4b05cc22b languageName: node linkType: hard -"@libp2p/interfaces@npm:^3.0.0, @libp2p/interfaces@npm:^3.3.1": +"@libp2p/interface@npm:^1.0.0, @libp2p/interface@npm:^1.1.2": + version: 1.1.2 + resolution: "@libp2p/interface@npm:1.1.2" + dependencies: + "@multiformats/multiaddr": ^12.1.10 + it-pushable: ^3.2.3 + it-stream-types: ^2.0.1 + multiformats: ^13.0.0 + progress-events: ^1.0.0 + uint8arraylist: ^2.4.7 + checksum: 99e257281fde4a226124344f24eb246b2a1f0639be3a73aae4478e97267f4fa5d9f86754291b16d5da01179d0fa11066477a7e1b6bb4ddfa025442b0fdc90809 + languageName: node + linkType: hard + +"@libp2p/interfaces@npm:^3.0.0": version: 3.3.2 resolution: "@libp2p/interfaces@npm:3.3.2" checksum: 3071fa49dcbb81a4b218248a1f648fba1061fb9c51e4b5edab9b8a7b9425c25afec96fdf3351ea7a469e7039269e59d95265682a934aa9c21630226dfcb67313 @@ -2269,21 +2258,20 @@ __metadata: linkType: hard "@libp2p/kad-dht@npm:^10.0.4": - version: 10.0.4 - resolution: "@libp2p/kad-dht@npm:10.0.4" - dependencies: - "@libp2p/crypto": ^2.0.3 - "@libp2p/interface": ^0.1.2 - "@libp2p/interface-internal": ^0.1.4 - "@libp2p/logger": ^3.0.2 - "@libp2p/peer-collections": ^4.0.3 - "@libp2p/peer-id": ^3.0.2 + version: 10.0.15 + resolution: "@libp2p/kad-dht@npm:10.0.15" + dependencies: + "@libp2p/crypto": ^2.0.8 + "@libp2p/interface": ^0.1.6 + "@libp2p/interface-internal": ^0.1.9 + "@libp2p/logger": ^3.1.0 + "@libp2p/peer-collections": ^4.0.8 + "@libp2p/peer-id": ^3.0.6 "@multiformats/multiaddr": ^12.1.5 - "@types/sinon": ^10.0.15 + "@types/sinon": ^17.0.0 abortable-iterator: ^5.0.1 any-signal: ^4.1.1 datastore-core: ^9.0.1 - events: ^3.3.0 hashlru: ^2.3.0 interface-datastore: ^8.2.0 it-all: ^3.0.2 @@ -2295,6 +2283,7 @@ __metadata: it-merge: ^3.0.0 it-parallel: ^3.0.0 it-pipe: ^3.0.1 + it-pushable: ^3.2.1 it-stream-types: ^2.0.1 it-take: ^3.0.1 multiformats: ^12.0.1 @@ -2307,27 +2296,27 @@ __metadata: uint8-varint: ^2.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: 8fbc6b2e12eeb98825b7dfa9e09a1c26f22a679167bde6305e8c524ee5514f509639db70915c432e1749272348f3eb8bb37ea7978a1a6f4133053e6b37ae3e3f + checksum: 566c62d45ff8ba92ea15332c8b62395a8e4f794ee46c038b04e4c144f032ddceae080e2a6de0e0948370620d3b708f61052783b788ba40d53d11044910f9becf languageName: node linkType: hard -"@libp2p/keychain@npm:^3.0.3": - version: 3.0.3 - resolution: "@libp2p/keychain@npm:3.0.3" +"@libp2p/keychain@npm:^3.0.8": + version: 3.0.8 + resolution: "@libp2p/keychain@npm:3.0.8" dependencies: - "@libp2p/crypto": ^2.0.3 - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 - "@libp2p/peer-id": ^3.0.2 + "@libp2p/crypto": ^2.0.8 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 + "@libp2p/peer-id": ^3.0.6 interface-datastore: ^8.2.0 merge-options: ^3.0.4 sanitize-filename: ^1.6.3 uint8arrays: ^4.0.6 - checksum: cf02dea0290d891c903fb9be2ad4955ae1a5dcb5a8f842873667231d8a3ce9225cadee57ca88d23d887be0be932fe5aece16412965da267f01b1a2e4c478f38f + checksum: 765971d2ef29cdc781ff2447f28501b9f58c8a9d0e4339c17b01de5a57d50344f58b40928c3b0ad85534a416ac1055a0c1ca59852ca26329118d423d7e305e66 languageName: node linkType: hard -"@libp2p/logger@npm:^2.0.0, @libp2p/logger@npm:^2.0.7": +"@libp2p/logger@npm:^2.0.7": version: 2.1.1 resolution: "@libp2p/logger@npm:2.1.1" dependencies: @@ -2340,44 +2329,57 @@ __metadata: languageName: node linkType: hard -"@libp2p/logger@npm:^3.0.0, @libp2p/logger@npm:^3.0.2": - version: 3.0.2 - resolution: "@libp2p/logger@npm:3.0.2" +"@libp2p/logger@npm:^3.0.0, @libp2p/logger@npm:^3.1.0": + version: 3.1.0 + resolution: "@libp2p/logger@npm:3.1.0" dependencies: - "@libp2p/interface": ^0.1.2 + "@libp2p/interface": ^0.1.6 "@multiformats/multiaddr": ^12.1.5 debug: ^4.3.4 interface-datastore: ^8.2.0 multiformats: ^12.0.1 - checksum: 55734af96bdcf1572796e26d859c4a8f6ee9b4f0ca98bf0112e46cc90ce690a807e533095db79887919d7d33d5a90d2365e1354cdd3787b08ec396388a32f7a6 + checksum: ff80803afe40a1078dbaf3119fd312bce283660e6e3d0705c91395c5e1f09520217ef29d8426880db23837bcfa444579cae6b4fc6e9ae4c869ecf4e5b9a0a59c + languageName: node + linkType: hard + +"@libp2p/logger@npm:^4.0.1": + version: 4.0.5 + resolution: "@libp2p/logger@npm:4.0.5" + dependencies: + "@libp2p/interface": ^1.1.2 + "@multiformats/multiaddr": ^12.1.10 + debug: ^4.3.4 + interface-datastore: ^8.2.0 + multiformats: ^13.0.0 + checksum: e0bc60e3ac6f3ab017eb16b26eb3badc3c728291fdbea28cf9ef2f9fbfc1161d562acfa4c4fbd148d6ad0de8a4417f02d1ffada611af5255fff8495df2d65707 languageName: node linkType: hard "@libp2p/mplex@npm:^9.0.4": - version: 9.0.4 - resolution: "@libp2p/mplex@npm:9.0.4" + version: 9.0.12 + resolution: "@libp2p/mplex@npm:9.0.12" dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 abortable-iterator: ^5.0.1 benchmark: ^2.1.4 it-batched-bytes: ^2.0.2 it-pushable: ^3.2.0 it-stream-types: ^2.0.1 - rate-limiter-flexible: ^2.3.11 + rate-limiter-flexible: ^3.0.0 uint8-varint: ^2.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: ab3bbda7a8fd4c4fd5c0a3d6865cfcd2c2659eff8dbb81c20b8dceeaa7a804039bada63faa7e9d04cdf48c215cc772cef0d38be0f61046b55f0c888b879ce9c3 + checksum: 13c9c8a1826d81fc0497f84bfff97d75563602ea7bf07ac64f29bb3f6c13129610e825bca1bda8d63de62945009a0dc91b607c4979d2e91ad6c2e10f8008ec10 languageName: node linkType: hard -"@libp2p/multistream-select@npm:^4.0.2": - version: 4.0.2 - resolution: "@libp2p/multistream-select@npm:4.0.2" +"@libp2p/multistream-select@npm:^4.0.6": + version: 4.0.10 + resolution: "@libp2p/multistream-select@npm:4.0.10" dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 abortable-iterator: ^5.0.1 it-first: ^3.0.1 it-handshake: ^4.1.3 @@ -2387,90 +2389,76 @@ __metadata: it-pushable: ^3.2.0 it-reader: ^6.0.1 it-stream-types: ^2.0.1 + uint8-varint: ^2.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: 2909e297eabcb7b3da0391f6a323bb414d509e4fbe2feaa3a6a287f95bb0d46c27ec3d952755353142fe910b1fc613114e3efa17bc0f2f50109897d1a7dc85e5 - languageName: node - linkType: hard - -"@libp2p/peer-collections@npm:^4.0.3": - version: 4.0.3 - resolution: "@libp2p/peer-collections@npm:4.0.3" - dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/peer-id": ^3.0.2 - checksum: 3a8784a17d1cbd3098b43d71b888ff15e4d9b2638090c44cb02b5d02c0590ef589788cc0f61708050b74f8d52b38ed4101796016e64478a2e3c1ae0f321e8451 + checksum: 3a3d32cc3605f73cef4039712b394c1bf18d5ca624f9b8b43c880b4d65b8bbc0491273a970183febd52c3f30dfbdbd2f6ac4aa102a117661e057749e67910bb6 languageName: node linkType: hard -"@libp2p/peer-id-factory@npm:^3.0.3": - version: 3.0.3 - resolution: "@libp2p/peer-id-factory@npm:3.0.3" +"@libp2p/peer-collections@npm:^4.0.8": + version: 4.0.11 + resolution: "@libp2p/peer-collections@npm:4.0.11" dependencies: - "@libp2p/crypto": ^2.0.3 - "@libp2p/interface": ^0.1.2 - "@libp2p/peer-id": ^3.0.2 - multiformats: ^12.0.1 - protons-runtime: ^5.0.0 - uint8arraylist: ^2.4.3 - uint8arrays: ^4.0.6 - checksum: 093530837f0d73fc6cb40c168c10c4bc2f196783b089c1006b9958b5ad86b93963de9fccf18159ce60afad01896c549bee5e368283fba288d9abf2598c7a6ea5 + "@libp2p/interface": ^0.1.6 + "@libp2p/peer-id": ^3.0.6 + checksum: b15651d905007f51cb9867f08aa3af21b8a36fef67a2f3a6309483df13d99d7611e6a9aed7dbaf1cf2adbe4ccbca0d366be92dc4e66afc705bbd9ffe43dc8b80 languageName: node linkType: hard -"@libp2p/peer-id-factory@npm:^3.0.4": - version: 3.0.4 - resolution: "@libp2p/peer-id-factory@npm:3.0.4" +"@libp2p/peer-id-factory@npm:^3.0.3, @libp2p/peer-id-factory@npm:^3.0.4, @libp2p/peer-id-factory@npm:^3.0.8": + version: 3.0.11 + resolution: "@libp2p/peer-id-factory@npm:3.0.11" dependencies: - "@libp2p/crypto": ^2.0.4 - "@libp2p/interface": ^0.1.2 - "@libp2p/peer-id": ^3.0.2 + "@libp2p/crypto": ^2.0.8 + "@libp2p/interface": ^0.1.6 + "@libp2p/peer-id": ^3.0.6 multiformats: ^12.0.1 protons-runtime: ^5.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: 40c534029bfa8d9b98119ee2c0ce3c0c91bcf7280028e7ba8bfe4da2a90de53014791d75c8d1400877919f748918704276b6e3337c5128975842c0593464fda9 + checksum: bdcee4fef7f8aace6a8316e523e8c82753986a42c58b51f59d04534a1095c9c1eec8193e859614aa2589a7f5e43e64e529bb0b475e7bad7150b2034b2ebc0aa2 languageName: node linkType: hard -"@libp2p/peer-id@npm:^3.0.0, @libp2p/peer-id@npm:^3.0.2": - version: 3.0.2 - resolution: "@libp2p/peer-id@npm:3.0.2" +"@libp2p/peer-id@npm:^3.0.0, @libp2p/peer-id@npm:^3.0.2, @libp2p/peer-id@npm:^3.0.6": + version: 3.0.6 + resolution: "@libp2p/peer-id@npm:3.0.6" dependencies: - "@libp2p/interface": ^0.1.2 + "@libp2p/interface": ^0.1.6 multiformats: ^12.0.1 uint8arrays: ^4.0.6 - checksum: 021a5854dd2b8afc0d83e1541531d9710be237d5a6883aa0965d85cba629fbaaa27f68f774f5fa9c331df6a8e6b1187031d270905a7c33f103177cf0e190e2bb + checksum: d573948b9b9fc64d80a2175ff27c9878d15a43aec5c71d9486c9b6d5e4a0510c9d935c71e35420cd09d55f32c3a87307112627becc5d9f709b4b19a7100f7d30 languageName: node linkType: hard -"@libp2p/peer-record@npm:^6.0.3": - version: 6.0.3 - resolution: "@libp2p/peer-record@npm:6.0.3" +"@libp2p/peer-record@npm:^6.0.9": + version: 6.0.12 + resolution: "@libp2p/peer-record@npm:6.0.12" dependencies: - "@libp2p/crypto": ^2.0.3 - "@libp2p/interface": ^0.1.2 - "@libp2p/peer-id": ^3.0.2 - "@libp2p/utils": ^4.0.2 + "@libp2p/crypto": ^2.0.8 + "@libp2p/interface": ^0.1.6 + "@libp2p/peer-id": ^3.0.6 + "@libp2p/utils": ^4.0.7 "@multiformats/multiaddr": ^12.1.5 protons-runtime: ^5.0.0 - uint8-varint: ^1.0.2 + uint8-varint: ^2.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: 63e7a6190a608d649761303b8e2783fcdb8f2024d3cafc137afeb67eab553469fb1f052cbe88fdb489385cd621aaa4cf52d9d93effb99111704158d98408e1cb + checksum: d252cafa7c63fc05c8715cb4de8e340bbd76e5438b3eaf309f6e2de5a41d550f399f4ddba110ef2edcb4e667659baa20d4da2cc4d9f19611ae4402f72eb87006 languageName: node linkType: hard -"@libp2p/peer-store@npm:^9.0.3": - version: 9.0.3 - resolution: "@libp2p/peer-store@npm:9.0.3" +"@libp2p/peer-store@npm:^9.0.9": + version: 9.0.12 + resolution: "@libp2p/peer-store@npm:9.0.12" dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 - "@libp2p/peer-collections": ^4.0.3 - "@libp2p/peer-id": ^3.0.2 - "@libp2p/peer-id-factory": ^3.0.3 - "@libp2p/peer-record": ^6.0.3 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 + "@libp2p/peer-collections": ^4.0.8 + "@libp2p/peer-id": ^3.0.6 + "@libp2p/peer-id-factory": ^3.0.8 + "@libp2p/peer-record": ^6.0.9 "@multiformats/multiaddr": ^12.1.5 interface-datastore: ^8.2.0 it-all: ^3.0.2 @@ -2479,79 +2467,80 @@ __metadata: protons-runtime: ^5.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 - checksum: 25b489c067ad910dcb8290afcbd5669ca87ddba9e1bed19c3b0279ab328d147b0f7fd0bc736707da61f897e1864c525733b2f9daae7791d7a67b76e0e7e1826b + checksum: b4d3ee98781742a7f46d50afc43f6b530058c9d8f2db04fd66c391d59427eaa4b49eb9d4df26e6bd4e6ae8d9a60e90686ae522f13e9ad517da4860c3f868a778 languageName: node linkType: hard "@libp2p/tcp@npm:^8.0.4": - version: 8.0.4 - resolution: "@libp2p/tcp@npm:8.0.4" + version: 8.0.13 + resolution: "@libp2p/tcp@npm:8.0.13" dependencies: - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 - "@libp2p/utils": ^4.0.2 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 + "@libp2p/utils": ^4.0.7 "@multiformats/mafmt": ^12.1.2 "@multiformats/multiaddr": ^12.1.5 - "@types/sinon": ^10.0.15 + "@types/sinon": ^17.0.0 stream-to-it: ^0.2.2 - checksum: ba7fc1da50181c6e118d362f85baf6a16cdab609be9eb2b7c182326cabef87676df03f9b5f816bac8cb2d597b1462075ebe7ca4d84243b60ba45359322aa4185 + checksum: cceff8633265c3bee7b0a246808fe26a61cb5876ca3363ae3278ebd9d2bd4775e3d3057c5ef8f18b8dd78368a0fd6359c94e7f8cd3f747ad4ebc89fce80db274 languageName: node linkType: hard -"@libp2p/utils@npm:^4.0.2": - version: 4.0.2 - resolution: "@libp2p/utils@npm:4.0.2" +"@libp2p/utils@npm:^4.0.7": + version: 4.0.7 + resolution: "@libp2p/utils@npm:4.0.7" dependencies: "@chainsafe/is-ip": ^2.0.2 - "@libp2p/interface": ^0.1.2 - "@libp2p/logger": ^3.0.2 + "@libp2p/interface": ^0.1.6 + "@libp2p/logger": ^3.1.0 "@multiformats/multiaddr": ^12.1.5 + "@multiformats/multiaddr-matcher": ^1.0.1 is-loopback-addr: ^2.0.1 it-stream-types: ^2.0.1 private-ip: ^3.0.0 uint8arraylist: ^2.4.3 - checksum: 1fd40278c58fe75d587f2d209bec039787b9997ba3ad9e2f8a47b716247efb73be98093d08fa5872395cd74b6f5d1b575fd5319d545c31155313a865c9135aee + checksum: df883f04b9efda532009ae0b2f03d918567277479e6f115a02673394e4239605bbaa0718e7cea7bd4c70307b44cd782492b6fa4ad9f03c7c4621f12cbb1f7d4c languageName: node linkType: hard -"@lmdb/lmdb-darwin-arm64@npm:2.9.1": - version: 2.9.1 - resolution: "@lmdb/lmdb-darwin-arm64@npm:2.9.1" +"@lmdb/lmdb-darwin-arm64@npm:2.9.2": + version: 2.9.2 + resolution: "@lmdb/lmdb-darwin-arm64@npm:2.9.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@lmdb/lmdb-darwin-x64@npm:2.9.1": - version: 2.9.1 - resolution: "@lmdb/lmdb-darwin-x64@npm:2.9.1" +"@lmdb/lmdb-darwin-x64@npm:2.9.2": + version: 2.9.2 + resolution: "@lmdb/lmdb-darwin-x64@npm:2.9.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@lmdb/lmdb-linux-arm64@npm:2.9.1": - version: 2.9.1 - resolution: "@lmdb/lmdb-linux-arm64@npm:2.9.1" +"@lmdb/lmdb-linux-arm64@npm:2.9.2": + version: 2.9.2 + resolution: "@lmdb/lmdb-linux-arm64@npm:2.9.2" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@lmdb/lmdb-linux-arm@npm:2.9.1": - version: 2.9.1 - resolution: "@lmdb/lmdb-linux-arm@npm:2.9.1" +"@lmdb/lmdb-linux-arm@npm:2.9.2": + version: 2.9.2 + resolution: "@lmdb/lmdb-linux-arm@npm:2.9.2" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@lmdb/lmdb-linux-x64@npm:2.9.1": - version: 2.9.1 - resolution: "@lmdb/lmdb-linux-x64@npm:2.9.1" +"@lmdb/lmdb-linux-x64@npm:2.9.2": + version: 2.9.2 + resolution: "@lmdb/lmdb-linux-x64@npm:2.9.2" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@lmdb/lmdb-win32-x64@npm:2.9.1": - version: 2.9.1 - resolution: "@lmdb/lmdb-win32-x64@npm:2.9.1" +"@lmdb/lmdb-win32-x64@npm:2.9.2": + version: 2.9.2 + resolution: "@lmdb/lmdb-win32-x64@npm:2.9.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -2575,30 +2564,30 @@ __metadata: languageName: node linkType: hard -"@monorepo-utils/package-utils@npm:^2.10.2": - version: 2.10.2 - resolution: "@monorepo-utils/package-utils@npm:2.10.2" +"@monorepo-utils/package-utils@npm:^2.10.4": + version: 2.10.4 + resolution: "@monorepo-utils/package-utils@npm:2.10.4" dependencies: globby: ^11.0.1 load-json-file: ^6.2.0 upath: ^2.0.1 yaml: ^2.1.3 - checksum: fa8ff74b63a5760bb5088c1897f2e82c77d8c5e60858141d354b434fcefdf19a8d590721ddec328821fecfe8797018bdb79ad20be02a19d168859d19f03823ad + checksum: aa55887ff790693e2db7158aa28fbf178c7041607e65f857f516306e6ff6a77d596151ee6d61519fce8369db8cffffd07ee6fb66b99f12619f3845985dc7543f languageName: node linkType: hard "@monorepo-utils/workspaces-to-typescript-project-references@npm:^2.9.0": - version: 2.10.2 - resolution: "@monorepo-utils/workspaces-to-typescript-project-references@npm:2.10.2" + version: 2.10.4 + resolution: "@monorepo-utils/workspaces-to-typescript-project-references@npm:2.10.4" dependencies: - "@monorepo-utils/package-utils": ^2.10.2 + "@monorepo-utils/package-utils": ^2.10.4 comment-json: ^3.0.3 meow: ^7.1.1 semver-match: 0.1.1 upath: ^2.0.1 bin: workspaces-to-typescript-project-references: bin/cmd.js - checksum: 076575a837a6a928e029eeac284278e2953638a60632264d60e2efcdb216fba1d8de4fc2a74ab598ad71663a87cc595cbe3b8732da7d4845b44f1fb321a4da74 + checksum: 34d539247bdcaff9f0182ec8654a5f63d81bd8b06e0947fb6ab3f8c72127684e45906510576fa1a15dd31d8b7d7ad99f29918e5a4ff9b21a74f45227f8b6ccef languageName: node linkType: hard @@ -2653,51 +2642,36 @@ __metadata: languageName: node linkType: hard -"@multiformats/multiaddr-matcher@npm:^1.0.0": - version: 1.0.1 - resolution: "@multiformats/multiaddr-matcher@npm:1.0.1" +"@multiformats/multiaddr-matcher@npm:^1.0.0, @multiformats/multiaddr-matcher@npm:^1.0.1": + version: 1.1.2 + resolution: "@multiformats/multiaddr-matcher@npm:1.1.2" dependencies: "@chainsafe/is-ip": ^2.0.1 "@multiformats/multiaddr": ^12.0.0 - multiformats: ^12.0.1 - checksum: 71579db42aa0e22297e542946d7ad2ab5a3427d619de6838cce46cce3bb168615577b6e94b58fca1b4af94520dae366810ecc309081810e15ff61781591908d5 + multiformats: ^13.0.0 + checksum: ae0619211ad1a4f1021993c1372f6498cbaec07897559b0b8644e0c8e53a3fc209136d3faf4f6cef5b1533f952b55b232fd6eb089d578a3594fa92d01802d4c3 languageName: node linkType: hard -"@multiformats/multiaddr@npm:^12.0.0, @multiformats/multiaddr@npm:^12.1.3": - version: 12.1.5 - resolution: "@multiformats/multiaddr@npm:12.1.5" +"@multiformats/multiaddr@npm:^12.0.0, @multiformats/multiaddr@npm:^12.1.10, @multiformats/multiaddr@npm:^12.1.3, @multiformats/multiaddr@npm:^12.1.5": + version: 12.1.14 + resolution: "@multiformats/multiaddr@npm:12.1.14" dependencies: "@chainsafe/is-ip": ^2.0.1 "@chainsafe/netmask": ^2.0.0 - "@libp2p/interfaces": ^3.3.1 - dns-over-http-resolver: ^2.1.0 - multiformats: ^12.0.1 - uint8arrays: ^4.0.2 - varint: ^6.0.0 - checksum: 01181807070382fb96019aec68df6276c90801185eedeb82c69dfef0ff6898eacc87a13e639c364dc0da976c5be623b56198e7107f2da40e4ef3a2d3523e8c49 - languageName: node - linkType: hard - -"@multiformats/multiaddr@npm:^12.1.5": - version: 12.1.7 - resolution: "@multiformats/multiaddr@npm:12.1.7" - dependencies: - "@chainsafe/is-ip": ^2.0.1 - "@chainsafe/netmask": ^2.0.0 - "@libp2p/interface": ^0.1.1 - dns-over-http-resolver: ^2.1.0 - multiformats: ^12.0.1 + "@libp2p/interface": ^1.0.0 + dns-over-http-resolver: ^3.0.2 + multiformats: ^13.0.0 uint8-varint: ^2.0.1 - uint8arrays: ^4.0.2 - checksum: 96b83208b7bd3e9387f2fdac20fc554d962395c02661e9c1da819646d2f3129e1a76e5abc6a0c8d386c7126a7678e58d05b08dc812260b7cad2488533cbe44b0 + uint8arrays: ^5.0.0 + checksum: 6c48bb1c467b36c030b2c746574b81f7e3a8fba46987471b5f6714dac1ceea120759383be37c1cacc8d1fbb9c8666eb28ad0041c5737eaf457bd8d58f0d520fa languageName: node linkType: hard -"@noble/ciphers@npm:^0.1.4": - version: 0.1.4 - resolution: "@noble/ciphers@npm:0.1.4" - checksum: a846f91dc876ea8cf01c20f04df2816926ad4e4d90169e6334de39b477ce13bf5e720f4df9f9898dd2a87643660ccc8a04aa466baf885c43860c270bcc7deced +"@noble/ciphers@npm:^0.4.0": + version: 0.4.1 + resolution: "@noble/ciphers@npm:0.4.1" + checksum: 8301334d6281c1cd6200716be6d01e30b8fd07b6ff7a537587187a649e625a347f24d52eba4812fc3535a077cd53e33a7abb77aeee19ff6662b7f048148f9e21 languageName: node linkType: hard @@ -2710,16 +2684,7 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:^1.0.0, @noble/curves@npm:^1.1.0": - version: 1.1.0 - resolution: "@noble/curves@npm:1.1.0" - dependencies: - "@noble/hashes": 1.3.1 - checksum: 2658cdd3f84f71079b4e3516c47559d22cf4b55c23ac8ee9d2b1f8e5b72916d9689e59820e0f9d9cb4a46a8423af5b56dc6bb7782405c88be06a015180508db5 - languageName: node - linkType: hard - -"@noble/curves@npm:^1.2.0": +"@noble/curves@npm:1.2.0, @noble/curves@npm:~1.2.0": version: 1.2.0 resolution: "@noble/curves@npm:1.2.0" dependencies: @@ -2728,17 +2693,19 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.3.0": +"@noble/curves@npm:^1.0.0, @noble/curves@npm:^1.1.0, @noble/curves@npm:^1.2.0": version: 1.3.0 - resolution: "@noble/hashes@npm:1.3.0" - checksum: d7ddb6d7c60f1ce1f87facbbef5b724cdea536fc9e7f59ae96e0fc9de96c8f1a2ae2bdedbce10f7dcc621338dfef8533daa73c873f2b5c87fa1a4e05a95c2e2e + resolution: "@noble/curves@npm:1.3.0" + dependencies: + "@noble/hashes": 1.3.3 + checksum: b65342ee66c4a440eee2978524412eabba9a9efdd16d6370e15218c6a7d80bddf35e66bb57ed52c0dfd32cb9a717b439ab3a72db618f1a0066dfebe3fd12a421 languageName: node linkType: hard -"@noble/hashes@npm:1.3.1, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0": - version: 1.3.1 - resolution: "@noble/hashes@npm:1.3.1" - checksum: 7fdefc0f7a0c1ec27acc6ff88841793e3f93ec4ce6b8a6a12bfc0dd70ae6b7c4c82fe305fdfeda1735d5ad4a9eebe761e6693b3d355689c559e91242f4bc95b1 +"@noble/hashes@npm:1.3.0": + version: 1.3.0 + resolution: "@noble/hashes@npm:1.3.0" + checksum: d7ddb6d7c60f1ce1f87facbbef5b724cdea536fc9e7f59ae96e0fc9de96c8f1a2ae2bdedbce10f7dcc621338dfef8533daa73c873f2b5c87fa1a4e05a95c2e2e languageName: node linkType: hard @@ -2749,6 +2716,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.3.3, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.2": + version: 1.3.3 + resolution: "@noble/hashes@npm:1.3.3" + checksum: 8a6496d1c0c64797339bc694ad06cdfaa0f9e56cd0c3f68ae3666cfb153a791a55deb0af9c653c7ed2db64d537aa3e3054629740d2f2338bb1dcb7ab60cd205b + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -2816,6 +2790,19 @@ __metadata: languageName: node linkType: soft +"@npmcli/agent@npm:^2.0.0": + version: 2.2.0 + resolution: "@npmcli/agent@npm:2.2.0" + dependencies: + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.1 + checksum: 3b25312edbdfaa4089af28e2d423b6f19838b945e47765b0c8174c1395c79d43c3ad6d23cb364b43f59fd3acb02c93e3b493f72ddbe3dfea04c86843a7311fc4 + languageName: node + linkType: hard + "@npmcli/fs@npm:^3.1.0": version: 3.1.0 resolution: "@npmcli/fs@npm:3.1.0" @@ -2832,96 +2819,9 @@ __metadata: languageName: node linkType: hard -"@pkgr/utils@npm:^2.3.1": - version: 2.4.2 - resolution: "@pkgr/utils@npm:2.4.2" - dependencies: - cross-spawn: ^7.0.3 - fast-glob: ^3.3.0 - is-glob: ^4.0.3 - open: ^9.1.0 - picocolors: ^1.0.0 - tslib: ^2.6.0 - checksum: 24e04c121269317d259614cd32beea3af38277151c4002df5883c4be920b8e3490bb897748e844f9d46bf68230f86dabd4e8f093773130e7e60529a769a132fc - languageName: node - linkType: hard - -"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": - version: 1.1.2 - resolution: "@protobufjs/aspromise@npm:1.1.2" - checksum: 011fe7ef0826b0fd1a95935a033a3c0fd08483903e1aa8f8b4e0704e3233406abb9ee25350ec0c20bbecb2aad8da0dcea58b392bbd77d6690736f02c143865d2 - languageName: node - linkType: hard - -"@protobufjs/base64@npm:^1.1.2": - version: 1.1.2 - resolution: "@protobufjs/base64@npm:1.1.2" - checksum: 67173ac34de1e242c55da52c2f5bdc65505d82453893f9b51dc74af9fe4c065cf4a657a4538e91b0d4a1a1e0a0642215e31894c31650ff6e3831471061e1ee9e - languageName: node - linkType: hard - -"@protobufjs/codegen@npm:^2.0.4": - version: 2.0.4 - resolution: "@protobufjs/codegen@npm:2.0.4" - checksum: 59240c850b1d3d0b56d8f8098dd04787dcaec5c5bd8de186fa548de86b86076e1c50e80144b90335e705a044edf5bc8b0998548474c2a10a98c7e004a1547e4b - languageName: node - linkType: hard - -"@protobufjs/eventemitter@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/eventemitter@npm:1.1.0" - checksum: 0369163a3d226851682f855f81413cbf166cd98f131edb94a0f67f79e75342d86e89df9d7a1df08ac28be2bc77e0a7f0200526bb6c2a407abbfee1f0262d5fd7 - languageName: node - linkType: hard - -"@protobufjs/fetch@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/fetch@npm:1.1.0" - dependencies: - "@protobufjs/aspromise": ^1.1.1 - "@protobufjs/inquire": ^1.1.0 - checksum: 3fce7e09eb3f1171dd55a192066450f65324fd5f7cc01a431df01bb00d0a895e6bfb5b0c5561ce157ee1d886349c90703d10a4e11a1a256418ff591b969b3477 - languageName: node - linkType: hard - -"@protobufjs/float@npm:^1.0.2": - version: 1.0.2 - resolution: "@protobufjs/float@npm:1.0.2" - checksum: 5781e1241270b8bd1591d324ca9e3a3128d2f768077a446187a049e36505e91bc4156ed5ac3159c3ce3d2ba3743dbc757b051b2d723eea9cd367bfd54ab29b2f - languageName: node - linkType: hard - -"@protobufjs/inquire@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/inquire@npm:1.1.0" - checksum: ca06f02eaf65ca36fb7498fc3492b7fc087bfcc85c702bac5b86fad34b692bdce4990e0ef444c1e2aea8c034227bd1f0484be02810d5d7e931c55445555646f4 - languageName: node - linkType: hard - -"@protobufjs/path@npm:^1.1.2": - version: 1.1.2 - resolution: "@protobufjs/path@npm:1.1.2" - checksum: 856eeb532b16a7aac071cacde5c5620df800db4c80cee6dbc56380524736205aae21e5ae47739114bf669ab5e8ba0e767a282ad894f3b5e124197cb9224445ee - languageName: node - linkType: hard - -"@protobufjs/pool@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/pool@npm:1.1.0" - checksum: d6a34fbbd24f729e2a10ee915b74e1d77d52214de626b921b2d77288bd8f2386808da2315080f2905761527cceffe7ec34c7647bd21a5ae41a25e8212ff79451 - languageName: node - linkType: hard - -"@protobufjs/utf8@npm:^1.1.0": - version: 1.1.0 - resolution: "@protobufjs/utf8@npm:1.1.0" - checksum: f9bf3163d13aaa3b6f5e6fbf37a116e094ea021c0e1f2a7ccd0e12a29e2ce08dafba4e8b36e13f8ed7397e1591610ce880ed1289af4d66cf4ace8a36a9557278 - languageName: node - linkType: hard - -"@puppeteer/browsers@npm:1.7.1": - version: 1.7.1 - resolution: "@puppeteer/browsers@npm:1.7.1" +"@puppeteer/browsers@npm:1.9.1": + version: 1.9.1 + resolution: "@puppeteer/browsers@npm:1.9.1" dependencies: debug: 4.3.4 extract-zip: 2.0.1 @@ -2929,17 +2829,17 @@ __metadata: proxy-agent: 6.3.1 tar-fs: 3.0.4 unbzip2-stream: 1.4.3 - yargs: 17.7.1 + yargs: 17.7.2 bin: browsers: lib/cjs/main-cli.js - checksum: fb7cf7773a1aed4e34ce0952dbf9609a164e624d4f8e1f342b816fe3e983888d7a7b2fbafc963559e96cb5bca0d75fb9c81f2097f9b1f5478a0f1cc7cbc12dff + checksum: 1ea82e34af882dc6d7e8392a88ec4196e206a7f65743be39c196c7068d66b9bdfa370e28c6ab09946bd2baa2182adbcbf445e79cc9bcc5242f05878ae7045b27 languageName: node linkType: hard -"@scure/base@npm:~1.1.0": - version: 1.1.1 - resolution: "@scure/base@npm:1.1.1" - checksum: b4fc810b492693e7e8d0107313ac74c3646970c198bbe26d7332820886fa4f09441991023ec9aa3a2a51246b74409ab5ebae2e8ef148bbc253da79ac49130309 +"@scure/base@npm:~1.1.0, @scure/base@npm:~1.1.2": + version: 1.1.5 + resolution: "@scure/base@npm:1.1.5" + checksum: 9e9ee6088cb3aa0fb91f5a48497d26682c7829df3019b1251d088d166d7a8c0f941c68aaa8e7b96bbad20c71eb210397cb1099062cde3e29d4bad6b975c18519 languageName: node linkType: hard @@ -2954,6 +2854,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.3.2": + version: 1.3.2 + resolution: "@scure/bip32@npm:1.3.2" + dependencies: + "@noble/curves": ~1.2.0 + "@noble/hashes": ~1.3.2 + "@scure/base": ~1.1.2 + checksum: c5ae84fae43490853693b481531132b89e056d45c945fc8b92b9d032577f753dfd79c5a7bbcbf0a7f035951006ff0311b6cf7a389e26c9ec6335e42b20c53157 + languageName: node + linkType: hard + "@scure/bip39@npm:1.2.0": version: 1.2.0 resolution: "@scure/bip39@npm:1.2.0" @@ -2964,6 +2875,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.2.1": + version: 1.2.1 + resolution: "@scure/bip39@npm:1.2.1" + dependencies: + "@noble/hashes": ~1.3.0 + "@scure/base": ~1.1.0 + checksum: c5bd6f1328fdbeae2dcdd891825b1610225310e5e62a4942714db51066866e4f7bef242c7b06a1b9dcc8043a4a13412cf5c5df76d3b10aa9e36b82e9b6e3eeaa + languageName: node + linkType: hard + "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -2972,11 +2893,11 @@ __metadata: linkType: hard "@sinonjs/commons@npm:^3.0.0": - version: 3.0.0 - resolution: "@sinonjs/commons@npm:3.0.0" + version: 3.0.1 + resolution: "@sinonjs/commons@npm:3.0.1" dependencies: type-detect: 4.0.8 - checksum: b4b5b73d4df4560fb8c0c7b38c7ad4aeabedd362f3373859d804c988c725889cde33550e4bcc7cd316a30f5152a2d1d43db71b6d0c38f5feef71fd8d016763f8 + checksum: a7c3e7cc612352f4004873747d9d8b2d4d90b13a6d483f685598c945a70e734e255f1ca5dc49702515533c403b32725defff148177453b3f3915bcb60e9d4601 languageName: node linkType: hard @@ -2989,13 +2910,6 @@ __metadata: languageName: node linkType: hard -"@tootallnate/once@npm:2": - version: 2.0.0 - resolution: "@tootallnate/once@npm:2.0.0" - checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 - languageName: node - linkType: hard - "@tootallnate/quickjs-emscripten@npm:^0.23.0": version: 0.23.0 resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0" @@ -3004,12 +2918,12 @@ __metadata: linkType: hard "@trivago/prettier-plugin-sort-imports@npm:^4.1.1": - version: 4.2.0 - resolution: "@trivago/prettier-plugin-sort-imports@npm:4.2.0" + version: 4.3.0 + resolution: "@trivago/prettier-plugin-sort-imports@npm:4.3.0" dependencies: "@babel/generator": 7.17.7 "@babel/parser": ^7.20.5 - "@babel/traverse": 7.17.3 + "@babel/traverse": 7.23.2 "@babel/types": 7.17.0 javascript-natural-sort: 0.7.1 lodash: ^4.17.21 @@ -3019,7 +2933,7 @@ __metadata: peerDependenciesMeta: "@vue/compiler-sfc": optional: true - checksum: 2081ba9f1a2d33b9a3eeadeb3e713d404ee3d1a5cff3b20a23d94d6d915f0a8ff549616c1e77cd728f1b33733e0d7ab8e4c2512f344a612d81ece40025351160 + checksum: 22bb311ca24f09eef25915a66727e7be113b703f196f6ea0589dc9730b11a6f1e5e4bcc468213101d138b570d310792c83abb8d9487c53f9e597942fea052b6e languageName: node linkType: hard @@ -3052,274 +2966,264 @@ __metadata: linkType: hard "@types/abstract-leveldown@npm:*": - version: 7.2.1 - resolution: "@types/abstract-leveldown@npm:7.2.1" - checksum: 20689e7d144ce26d2384e2e151eed59046c95d573a6988da5e77e3076808eb4f435f474a0387af9ac786bfbfc7089e277dcfd9572ae902553d5c018e9b527a30 + version: 7.2.5 + resolution: "@types/abstract-leveldown@npm:7.2.5" + checksum: 3a99b13c81a53a62b42bea9cff326880de3146b4eeff528b039be69a268515b3120a6c12142e96646fcb0a03c463f298998581e86d9ddb29fbea3612f40edb2b languageName: node linkType: hard "@types/accepts@npm:*": - version: 1.3.5 - resolution: "@types/accepts@npm:1.3.5" + version: 1.3.7 + resolution: "@types/accepts@npm:1.3.7" dependencies: "@types/node": "*" - checksum: 590b7580570534a640510c071e09074cf63b5958b237a728f94322567350aea4d239f8a9d897a12b15c856b992ee4d7907e9812bb079886af2c00714e7fb3f60 + checksum: 7678cf74976e16093aff6e6f9755826faf069ac1e30179276158ce46ea246348ff22ca6bdd46cef08428881337d9ceefbf00bab08a7731646eb9fc9449d6a1e7 languageName: node linkType: hard "@types/babel__core@npm:^7.1.14": - version: 7.20.1 - resolution: "@types/babel__core@npm:7.20.1" + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" dependencies: "@babel/parser": ^7.20.7 "@babel/types": ^7.20.7 "@types/babel__generator": "*" "@types/babel__template": "*" "@types/babel__traverse": "*" - checksum: 9fcd9691a33074802d9057ff70b0e3ff3778f52470475b68698a0f6714fbe2ccb36c16b43dc924eb978cd8a81c1f845e5ff4699e7a47606043b539eb8c6331a8 + checksum: a3226f7930b635ee7a5e72c8d51a357e799d19cbf9d445710fa39ab13804f79ab1a54b72ea7d8e504659c7dfc50675db974b526142c754398d7413aa4bc30845 languageName: node linkType: hard "@types/babel__generator@npm:*": - version: 7.6.4 - resolution: "@types/babel__generator@npm:7.6.4" + version: 7.6.8 + resolution: "@types/babel__generator@npm:7.6.8" dependencies: "@babel/types": ^7.0.0 - checksum: 20effbbb5f8a3a0211e95959d06ae70c097fb6191011b73b38fe86deebefad8e09ee014605e0fd3cdaedc73d158be555866810e9166e1f09e4cfd880b874dcb0 + checksum: 5b332ea336a2efffbdeedb92b6781949b73498606ddd4205462f7d96dafd45ff3618770b41de04c4881e333dd84388bfb8afbdf6f2764cbd98be550d85c6bb48 languageName: node linkType: hard "@types/babel__template@npm:*": - version: 7.4.1 - resolution: "@types/babel__template@npm:7.4.1" + version: 7.4.4 + resolution: "@types/babel__template@npm:7.4.4" dependencies: "@babel/parser": ^7.1.0 "@babel/types": ^7.0.0 - checksum: 649fe8b42c2876be1fd28c6ed9b276f78152d5904ec290b6c861d9ef324206e0a5c242e8305c421ac52ecf6358fa7e32ab7a692f55370484825c1df29b1596ee + checksum: d7a02d2a9b67e822694d8e6a7ddb8f2b71a1d6962dfd266554d2513eefbb205b33ca71a0d163b1caea3981ccf849211f9964d8bd0727124d18ace45aa6c9ae29 languageName: node linkType: hard "@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.20.1 - resolution: "@types/babel__traverse@npm:7.20.1" + version: 7.20.5 + resolution: "@types/babel__traverse@npm:7.20.5" dependencies: "@babel/types": ^7.20.7 - checksum: 58341e23c649c0eba134a1682d4f20d027fad290d92e5740faa1279978f6ed476fc467ae51ce17a877e2566d805aeac64eae541168994367761ec883a4150221 + checksum: 608e0ab4fc31cd47011d98942e6241b34d461608c0c0e153377c5fd822c436c475f1ded76a56bfa76a1adf8d9266b727bbf9bfac90c4cb152c97f30dadc5b7e8 languageName: node linkType: hard "@types/bn.js@npm:*, @types/bn.js@npm:^5.1.3": - version: 5.1.3 - resolution: "@types/bn.js@npm:5.1.3" + version: 5.1.5 + resolution: "@types/bn.js@npm:5.1.5" dependencies: "@types/node": "*" - checksum: 6cd144b8192b6655a009021a4f838a725ea3eb4c5e6425ffc5b144788f7612fb09018c2359954edef32ab7db15f7070b77d05499318b6d9824a55cb7e6776620 + checksum: c87b28c4af74545624f8a3dae5294b16aa190c222626e8d4b2e327b33b1a3f1eeb43e7a24d914a9774bca43d8cd6e1cb0325c1f4b3a244af6693a024e1d918e6 languageName: node linkType: hard "@types/body-parser@npm:*": - version: 1.19.2 - resolution: "@types/body-parser@npm:1.19.2" + version: 1.19.5 + resolution: "@types/body-parser@npm:1.19.5" dependencies: "@types/connect": "*" "@types/node": "*" - checksum: e17840c7d747a549f00aebe72c89313d09fbc4b632b949b2470c5cb3b1cb73863901ae84d9335b567a79ec5efcfb8a28ff8e3f36bc8748a9686756b6d5681f40 + checksum: 1e251118c4b2f61029cc43b0dc028495f2d1957fe8ee49a707fb940f86a9bd2f9754230805598278fe99958b49e9b7e66eec8ef6a50ab5c1f6b93e1ba2aaba82 languageName: node linkType: hard "@types/connect@npm:*": - version: 3.4.35 - resolution: "@types/connect@npm:3.4.35" + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" dependencies: "@types/node": "*" - checksum: fe81351470f2d3165e8b12ce33542eef89ea893e36dd62e8f7d72566dfb7e448376ae962f9f3ea888547ce8b55a40020ca0e01d637fab5d99567673084542641 + checksum: 7eb1bc5342a9604facd57598a6c62621e244822442976c443efb84ff745246b10d06e8b309b6e80130026a396f19bf6793b7cecd7380169f369dac3bfc46fb99 languageName: node linkType: hard "@types/content-disposition@npm:*": - version: 0.5.5 - resolution: "@types/content-disposition@npm:0.5.5" - checksum: fdf7379db1d509990bcf9a21d85f05aad878596f28b1418f9179f6436cb22513262c670ce88c6055054a7f5804a9303eeacb70aa59a5e11ffdc1434559db9692 + version: 0.5.8 + resolution: "@types/content-disposition@npm:0.5.8" + checksum: eeea868fb510ae7a32aa2d7de680fba79d59001f3e758a334621e10bc0a6496d3a42bb79243a5e53b9c63cb524522853ccc144fe1ab160c4247d37cdb81146c4 languageName: node linkType: hard -"@types/cookiejar@npm:*": - version: 2.1.2 - resolution: "@types/cookiejar@npm:2.1.2" - checksum: f6e1903454007f86edd6c3520cbb4d553e1d4e17eaf1f77f6f75e3270f48cc828d74397a113a36942f5fe52f9fa71067bcfa738f53ad468fcca0bc52cb1cbd28 +"@types/cookiejar@npm:^2.1.5": + version: 2.1.5 + resolution: "@types/cookiejar@npm:2.1.5" + checksum: 04d5990e87b6387532d15a87d9ec9b2eb783039291193863751dcfd7fc723a3b3aa30ce4c06b03975cba58632e933772f1ff031af23eaa3ac7f94e71afa6e073 languageName: node linkType: hard "@types/cookies@npm:*": - version: 0.7.7 - resolution: "@types/cookies@npm:0.7.7" + version: 0.7.10 + resolution: "@types/cookies@npm:0.7.10" dependencies: "@types/connect": "*" "@types/express": "*" "@types/keygrip": "*" "@types/node": "*" - checksum: d3759efc1182cb0651808570ae13638677b67b0ea724eef7b174e58ffe6ea044b62c7c2715e532f76f88fce4dd8101ed32ac6fbb73226db654017924e8a2a1e6 + checksum: 99cd44a193398932ff7926cfaac1eb4441d3dc47c3f64fdfb28861acbeb290b6db6a20376f993defc9d302db92bb1d36189b89ba447a633f960535f3f0d34e2d languageName: node linkType: hard "@types/debug@npm:^4.1.7": - version: 4.1.8 - resolution: "@types/debug@npm:4.1.8" + version: 4.1.12 + resolution: "@types/debug@npm:4.1.12" dependencies: "@types/ms": "*" - checksum: a9a9bb40a199e9724aa944e139a7659173a9b274798ea7efbc277cb084bc37d32fc4c00877c3496fac4fed70a23243d284adb75c00b5fdabb38a22154d18e5df + checksum: 47876a852de8240bfdaf7481357af2b88cb660d30c72e73789abf00c499d6bc7cd5e52f41c915d1b9cd8ec9fef5b05688d7b7aef17f7f272c2d04679508d1053 languageName: node linkType: hard "@types/detect-node@npm:^2.0.0": - version: 2.0.0 - resolution: "@types/detect-node@npm:2.0.0" - checksum: f0f5c8ec948f5d4a40944773c8f81460ca7fa08fddf53330166feff1f8e28719bba9a01984872c5823c5de00c8223984381640a41b3c541bc57f3b2d529a0024 + version: 2.0.2 + resolution: "@types/detect-node@npm:2.0.2" + checksum: 064af29e09c5e336174d69b7709510457b1c6704d195a0d1dde9d26091c6cc8aaed39f8e7d329eedbc765655296b5a46db12b50841265a721f5bd4d0b48cbe6f languageName: node linkType: hard "@types/elliptic@npm:^6.4.16": - version: 6.4.16 - resolution: "@types/elliptic@npm:6.4.16" + version: 6.4.18 + resolution: "@types/elliptic@npm:6.4.18" dependencies: "@types/bn.js": "*" - checksum: fedecadbab1a469a22bc9f8e44ce730bd945faed82230174c9df4748f29948d34d9d6f7c79122049cd37f048522e28019a470df7a55c86765a82fb0d05f3f415 + checksum: c27613c530fb95441e5e6b456c8c9bc26568ca14c546aae6d7c1d8d46869f79a2272feaef266ac00bdb68b2671e6351ed01b91b82266eac30ca9092720825d16 languageName: node linkType: hard "@types/eslint-scope@npm:^3.7.3": - version: 3.7.4 - resolution: "@types/eslint-scope@npm:3.7.4" + version: 3.7.7 + resolution: "@types/eslint-scope@npm:3.7.7" dependencies: "@types/eslint": "*" "@types/estree": "*" - checksum: ea6a9363e92f301cd3888194469f9ec9d0021fe0a397a97a6dd689e7545c75de0bd2153dfb13d3ab532853a278b6572c6f678ce846980669e41029d205653460 + checksum: e2889a124aaab0b89af1bab5959847c5bec09809209255de0e63b9f54c629a94781daa04adb66bffcdd742f5e25a17614fb933965093c0eea64aacda4309380e languageName: node linkType: hard "@types/eslint@npm:*": - version: 8.44.1 - resolution: "@types/eslint@npm:8.44.1" + version: 8.56.2 + resolution: "@types/eslint@npm:8.56.2" dependencies: "@types/estree": "*" "@types/json-schema": "*" - checksum: 8b45be72d3c22a1ee0b1cc7e7fb0e34e32bbf959e6b7e0e46d160c17894aedf159c1db5c85750f10068884c741eebc37a1cc7ea659de23a8df0c9a3203e2ff9d + checksum: 38e054971596f5c0413f66a62dc26b10e0a21ac46ceacb06fbf8cfb838d20820787209b17218b3916e4c23d990ff77cfdb482d655cac0e0d2b837d430fcc5db8 languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/estree@npm:1.0.1" - checksum: e9aa175eacb797216fafce4d41e8202c7a75555bc55232dee0f9903d7171f8f19f0ae7d5191bb1a88cb90e65468be508c0df850a9fb81b4433b293a5a749899d +"@types/estree@npm:*, @types/estree@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a languageName: node linkType: hard "@types/express-serve-static-core@npm:^4.17.33": - version: 4.17.35 - resolution: "@types/express-serve-static-core@npm:4.17.35" + version: 4.17.42 + resolution: "@types/express-serve-static-core@npm:4.17.42" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: cc8995d10c6feda475ec1b3a0e69eb0f35f21ab6b49129ad5c6f279e0bc5de8175bc04ec51304cb79a43eec3ed2f5a1e01472eb6d5f827b8c35c6ca8ad24eb6e + checksum: 58273f80fcc94de42691f48e22542e69f0b17863378e3216ce8b782ace012f32241bfeb02a2be837f0e2b4ef96e916979adc30bbfea13f6545bd3ab81b7d2773 languageName: node linkType: hard "@types/express@npm:*": - version: 4.17.17 - resolution: "@types/express@npm:4.17.17" + version: 4.17.21 + resolution: "@types/express@npm:4.17.21" dependencies: "@types/body-parser": "*" "@types/express-serve-static-core": ^4.17.33 "@types/qs": "*" "@types/serve-static": "*" - checksum: 0196dacc275ac3ce89d7364885cb08e7fb61f53ca101f65886dbf1daf9b7eb05c0943e2e4bbd01b0cc5e50f37e0eea7e4cbe97d0304094411ac73e1b7998f4da - languageName: node - linkType: hard - -"@types/fs-extra@npm:^11.0.1": - version: 11.0.1 - resolution: "@types/fs-extra@npm:11.0.1" - dependencies: - "@types/jsonfile": "*" - "@types/node": "*" - checksum: 3e930346e5d84f419deb8ced1c582beef8cb20d0bd8a0eb145a37d75bab0572a1895f0e48a0d681d386b3a58b9a992b2d2acecc464bcaec2548f53ea00718651 + checksum: fb238298630370a7392c7abdc80f495ae6c716723e114705d7e3fb67e3850b3859bbfd29391463a3fb8c0b32051847935933d99e719c0478710f8098ee7091c5 languageName: node linkType: hard -"@types/fs-extra@npm:^11.0.2": - version: 11.0.2 - resolution: "@types/fs-extra@npm:11.0.2" +"@types/fs-extra@npm:^11.0.1, @types/fs-extra@npm:^11.0.2": + version: 11.0.4 + resolution: "@types/fs-extra@npm:11.0.4" dependencies: "@types/jsonfile": "*" "@types/node": "*" - checksum: 5b3e30343ee62d2e393e1029355f13f64bab6f3416226e22492483f99da840e2e53ca22cbfa4ac3749f2f83f7086d19c009005c8fa175da01df0fae59c2d73e1 + checksum: 242cb84157631f057f76495c8220707541882c00a00195b603d937fb55e471afecebcb089bab50233ed3a59c69fd68bf65c1f69dd7fafe2347e139cc15b9b0e5 languageName: node linkType: hard "@types/graceful-fs@npm:^4.1.3": - version: 4.1.6 - resolution: "@types/graceful-fs@npm:4.1.6" + version: 4.1.9 + resolution: "@types/graceful-fs@npm:4.1.9" dependencies: "@types/node": "*" - checksum: c3070ccdc9ca0f40df747bced1c96c71a61992d6f7c767e8fd24bb6a3c2de26e8b84135ede000b7e79db530a23e7e88dcd9db60eee6395d0f4ce1dae91369dd4 + checksum: 79d746a8f053954bba36bd3d94a90c78de995d126289d656fb3271dd9f1229d33f678da04d10bce6be440494a5a73438e2e363e92802d16b8315b051036c5256 languageName: node linkType: hard "@types/http-assert@npm:*": - version: 1.5.3 - resolution: "@types/http-assert@npm:1.5.3" - checksum: 9553e5a0b8bcfdac4b51d3fa3b89a91b5450171861a667a5b4c47204e0f4a1ca865d97396e6ceaf220e87b64d06b7a8bad7bfba15ef97acb41a87507c9940dbc + version: 1.5.5 + resolution: "@types/http-assert@npm:1.5.5" + checksum: cd6bb7fd42cc6e2a702cb55370b8b25231954ad74c04bcd185b943a74ded3d4c28099c30f77b26951df2426441baff41718816c60b5af80efe2b8888d900bf93 languageName: node linkType: hard "@types/http-errors@npm:*": - version: 2.0.1 - resolution: "@types/http-errors@npm:2.0.1" - checksum: 3bb0c50b0a652e679a84c30cd0340d696c32ef6558518268c238840346c077f899315daaf1c26c09c57ddd5dc80510f2a7f46acd52bf949e339e35ed3ee9654f + version: 2.0.4 + resolution: "@types/http-errors@npm:2.0.4" + checksum: 1f3d7c3b32c7524811a45690881736b3ef741bf9849ae03d32ad1ab7062608454b150a4e7f1351f83d26a418b2d65af9bdc06198f1c079d75578282884c4e8e3 languageName: node linkType: hard "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.4 - resolution: "@types/istanbul-lib-coverage@npm:2.0.4" - checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 + version: 2.0.6 + resolution: "@types/istanbul-lib-coverage@npm:2.0.6" + checksum: 3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 languageName: node linkType: hard "@types/istanbul-lib-report@npm:*": - version: 3.0.0 - resolution: "@types/istanbul-lib-report@npm:3.0.0" + version: 3.0.3 + resolution: "@types/istanbul-lib-report@npm:3.0.3" dependencies: "@types/istanbul-lib-coverage": "*" - checksum: 656398b62dc288e1b5226f8880af98087233cdb90100655c989a09f3052b5775bf98ba58a16c5ae642fb66c61aba402e07a9f2bff1d1569e3b306026c59f3f36 + checksum: b91e9b60f865ff08cb35667a427b70f6c2c63e88105eadd29a112582942af47ed99c60610180aa8dcc22382fa405033f141c119c69b95db78c4c709fbadfeeb4 languageName: node linkType: hard "@types/istanbul-reports@npm:^3.0.0": - version: 3.0.1 - resolution: "@types/istanbul-reports@npm:3.0.1" + version: 3.0.4 + resolution: "@types/istanbul-reports@npm:3.0.4" dependencies: "@types/istanbul-lib-report": "*" - checksum: f1ad54bc68f37f60b30c7915886b92f86b847033e597f9b34f2415acdbe5ed742fa559a0a40050d74cdba3b6a63c342cac1f3a64dba5b68b66a6941f4abd7903 + checksum: 93eb18835770b3431f68ae9ac1ca91741ab85f7606f310a34b3586b5a34450ec038c3eed7ab19266635499594de52ff73723a54a72a75b9f7d6a956f01edee95 languageName: node linkType: hard "@types/jest@npm:^29.5.0": - version: 29.5.3 - resolution: "@types/jest@npm:29.5.3" + version: 29.5.11 + resolution: "@types/jest@npm:29.5.11" dependencies: expect: ^29.0.0 pretty-format: ^29.0.0 - checksum: e36bb92e0b9e5ea7d6f8832baa42f087fc1697f6cd30ec309a07ea4c268e06ec460f1f0cfd2581daf5eff5763475190ec1ad8ac6520c49ccfe4f5c0a48bfa676 + checksum: f892a06ec9f0afa9a61cd7fa316ec614e21d4df1ad301b5a837787e046fcb40dfdf7f264a55e813ac6b9b633cb9d366bd5b8d1cea725e84102477b366df23fdd languageName: node linkType: hard "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.8": - version: 7.0.12 - resolution: "@types/json-schema@npm:7.0.12" - checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 languageName: node linkType: hard @@ -3331,46 +3235,46 @@ __metadata: linkType: hard "@types/jsonfile@npm:*": - version: 6.1.1 - resolution: "@types/jsonfile@npm:6.1.1" + version: 6.1.4 + resolution: "@types/jsonfile@npm:6.1.4" dependencies: "@types/node": "*" - checksum: 0f8fe0a9221a00e8413cffba723dfe16553868724b830237256fb0052ecd5cac96498189d1235a001cfa815f352008261c9ceb373f0aa58227f891e0c7a12c4d + checksum: 309fda20eb5f1cf68f2df28931afdf189c5e7e6bec64ac783ce737bb98908d57f6f58757ad5da9be37b815645a6f914e2d4f3ac66c574b8fe1ba6616284d0e97 languageName: node linkType: hard "@types/keygrip@npm:*": - version: 1.0.2 - resolution: "@types/keygrip@npm:1.0.2" - checksum: 60bc2738a4f107070ee3d96f44709cb38f3a96c7ccabab09f56c1b2b4d85f869fd8fb9f1f2937e863d0e9e781f005c2223b823bf32b859185b4f52370c352669 + version: 1.0.6 + resolution: "@types/keygrip@npm:1.0.6" + checksum: d157f60bf920492347791d2b26d530d5069ce05796549fbacd4c24d66ffbebbcb0ab67b21e7a1b80a593b9fd4b67dc4843dec04c12bbc2e0fddfb8577a826c41 languageName: node linkType: hard "@types/koa-bodyparser@npm:^4.3.10": - version: 4.3.10 - resolution: "@types/koa-bodyparser@npm:4.3.10" + version: 4.3.12 + resolution: "@types/koa-bodyparser@npm:4.3.12" dependencies: "@types/koa": "*" - checksum: 4b4cd176815a6c1fb0d593bfea03de1285e606d3a96e56ad3691144e35061750ed95e4ecf2ff8e25599d360a93646e29dbb167fdfaaa73ccf87ca5b6141ff0db + checksum: 645cc253c6b9b2e98252b1cdc75a4812cd6d3c228e426f9893a755324b7a6936559ec659a0ff288cb2642340b3cc4e2110167f24b84efc8e3b89c04fe67ed883 languageName: node linkType: hard "@types/koa-compose@npm:*": - version: 3.2.5 - resolution: "@types/koa-compose@npm:3.2.5" + version: 3.2.8 + resolution: "@types/koa-compose@npm:3.2.8" dependencies: "@types/koa": "*" - checksum: 5d1147c4b057eb158195f442f0384f06503f3e69dba99fb517b30a05261a9f92928945c12bb1cfc17a5b7d60db003f38b455a3a9b125f12e4fc81fffa396b3cf + checksum: 95c32bdee738ac7c10439bbf6342ca3b9f0aafd7e8118739eac7fb0fa703a23cfe4c88f63e13a69a16fbde702e0bcdc62b272aa734325fc8efa7e5625479752e languageName: node linkType: hard "@types/koa-compress@npm:^4.0.3": - version: 4.0.3 - resolution: "@types/koa-compress@npm:4.0.3" + version: 4.0.6 + resolution: "@types/koa-compress@npm:4.0.6" dependencies: "@types/koa": "*" "@types/node": "*" - checksum: 6f09e4ad8160204fbee9d0a452b83ba62fec503a2eec60cf41fc67a032971027b6858e0b90c6e05bf1ad3b006f7c7a2d02922db4d159d223ab8d33eeeb108757 + checksum: 0ec8ffac1bf3c7dc36a9ee4588f83ade0a485b615aff7e9e08082319b1b3f7e2f5954ed5ce4303a7f9ba1b4144081e0700cbf3165d1aef54e5e12130c810b2e4 languageName: node linkType: hard @@ -3384,36 +3288,36 @@ __metadata: linkType: hard "@types/koa-router@npm:^7.4.4": - version: 7.4.4 - resolution: "@types/koa-router@npm:7.4.4" + version: 7.4.8 + resolution: "@types/koa-router@npm:7.4.8" dependencies: "@types/koa": "*" - checksum: 23ff5b725daa1427dc822602f5d4fdcecca5f990595af48879e41338a9c71819ae312326028eef4645beb6ea32ea852416e2f0761a2abd5bf80c2575a3301837 + checksum: 30b9735748f25ac338ec4197430a10f1cf58eeea0445f0b64733ed95df82b9245a31c01bbfdd3c9b71e90aa7a1ccf9546f4dd91bac87f6186152e67146ad9b6c languageName: node linkType: hard "@types/koa-send@npm:*": - version: 4.1.4 - resolution: "@types/koa-send@npm:4.1.4" + version: 4.1.6 + resolution: "@types/koa-send@npm:4.1.6" dependencies: "@types/koa": "*" - checksum: 27732c85e97465810bc7631153368daa8e8715bd356eab344d0b3deaec162de09b6cd9d61a524f4d3631493234da7104167e788d593ce27405b70bdfb12fc81b + checksum: d46d207f1d826ccd74bf3a02180d0475be8456eb3a2244244d19cb3f1737251e163d73958fdcd12111e03c7c0545cc89e7888a6ef2ba370ebf2b2e804efaaaf1 languageName: node linkType: hard "@types/koa-static@npm:^4.0.2": - version: 4.0.2 - resolution: "@types/koa-static@npm:4.0.2" + version: 4.0.4 + resolution: "@types/koa-static@npm:4.0.4" dependencies: "@types/koa": "*" "@types/koa-send": "*" - checksum: a9c557a37b25a677f3aae084b2afd267fa78a728cd69aec20821d8acca3ef4bda172d1fd16a23711266d97e77962d037ffd25ee76b24608413032226321f461f + checksum: 99087a9b6f4214679932008fbed2d4332fca06cd01f2d333439bd1cf0844c313584c8eb6b805360d1c3d6c6c8a475468a5f4f73ecad551c8cc369e290ad41331 languageName: node linkType: hard -"@types/koa@npm:*, @types/koa@npm:^2.13.5, @types/koa@npm:^2.13.6": - version: 2.13.8 - resolution: "@types/koa@npm:2.13.8" +"@types/koa@npm:*, @types/koa@npm:^2.13.5, @types/koa@npm:^2.13.6, @types/koa@npm:^2.13.9": + version: 2.14.0 + resolution: "@types/koa@npm:2.14.0" dependencies: "@types/accepts": "*" "@types/content-disposition": "*" @@ -3423,171 +3327,134 @@ __metadata: "@types/keygrip": "*" "@types/koa-compose": "*" "@types/node": "*" - checksum: 76a2a6d219c65f242a43efca42970d864701c58319c346a91dd8c3b4df2021786fd0d600a88dfb098358c9085f9f4a2dfe62563641441cf21e11e2bfe04f4fdf - languageName: node - linkType: hard - -"@types/koa@npm:^2.13.9": - version: 2.13.9 - resolution: "@types/koa@npm:2.13.9" - dependencies: - "@types/accepts": "*" - "@types/content-disposition": "*" - "@types/cookies": "*" - "@types/http-assert": "*" - "@types/http-errors": "*" - "@types/keygrip": "*" - "@types/koa-compose": "*" - "@types/node": "*" - checksum: af9cd599c8e17e2ae0f4168a61d964e343f713d002b65fd995658d7addc6551ccadecfd32b3405cf44e4d360178ee4f972d6881533548261ae1f636a655d24b1 + checksum: 57d809e42350c9ddefa2150306355e40757877468bb027e0bd99f5aeb43cfaf8ba8b14761ea65e419d6fb4c2403a1f3ed0762872a9cf040dbd14357caca56548 languageName: node linkType: hard "@types/koa__cors@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/koa__cors@npm:4.0.0" - dependencies: - "@types/koa": "*" - checksum: 0a7f8c2ab9b957befbbe31b9293af05a95282fb984b8468b0c0a0a0101beefe2663ce716ca56fbf4e5ec5ca2d89193ee7d635ee84bb8b5d718df01149286f4d2 - languageName: node - linkType: hard - -"@types/level-errors@npm:*": - version: 3.0.0 - resolution: "@types/level-errors@npm:3.0.0" - checksum: ad9392663439306677ac9cb704f8fa0b64c300dfea4f3494369eb78a2e09c194156cbab2b52c71a361a09b735d54a2de65195dcadba0ec7db1d14a320198133e - languageName: node - linkType: hard - -"@types/leveldown@npm:^4.0.3": version: 4.0.3 - resolution: "@types/leveldown@npm:4.0.3" + resolution: "@types/koa__cors@npm:4.0.3" dependencies: - "@types/abstract-leveldown": "*" - "@types/node": "*" - checksum: 0a476bd8d3c71266fdb323875d3312bf7828d6ab9f1bf9882a0ff93d04044660e45cd211ca8ec34c5665eaa773f98fe9fee14235792835bd06cb68192fe44669 + "@types/koa": "*" + checksum: ca7bfd1ffacf6c425393e2716a88d66dfe1b5e9a32cd92253cc846fa95bd7fd44c1dc848252f13b7febb5bccf23b8e88716b051cfa04d18fa31e0768432dccb7 languageName: node - linkType: hard - -"@types/leveldown@npm:^4.0.4": - version: 4.0.4 - resolution: "@types/leveldown@npm:4.0.4" - dependencies: - "@types/abstract-leveldown": "*" - "@types/node": "*" - checksum: 630b2d2d1c48f83d14ab0f6c03ad2af1c427675c3692873c4fd3d673bde4140eabc028ce5736ad3d76aeea20769cf53df6f83468a4f0cf28f6d04dbb435edf48 + linkType: hard + +"@types/level-errors@npm:*": + version: 3.0.2 + resolution: "@types/level-errors@npm:3.0.2" + checksum: 3d9b801f6499f795b60ac723c1b3f93ca105f20ed26966eeb606c804b10c65984c3233fb99914644d75a3223f80f220eca74fda316640a85a5b3d7572cd86925 languageName: node linkType: hard -"@types/levelup@npm:^5.1.2": - version: 5.1.2 - resolution: "@types/levelup@npm:5.1.2" +"@types/leveldown@npm:^4.0.3": + version: 4.0.6 + resolution: "@types/leveldown@npm:4.0.6" dependencies: "@types/abstract-leveldown": "*" - "@types/level-errors": "*" "@types/node": "*" - checksum: 6740284488b6806ba398bc38842fa789edd5667a342830c544a6b3611ebeed957a08d03dc8bde1e32fe03ac9c439341647c044c1ff0f73a26bcded9ca302a009 + checksum: 8b06cbc6858f3956fe8e10a8bb58edd75369587e72ce33ab7e35e21e1f1c8e89981a337c977ffd3a635d4441113e434362ba37e343d8a0ec69cd7c8988450977 languageName: node linkType: hard -"@types/levelup@npm:^5.1.3": - version: 5.1.3 - resolution: "@types/levelup@npm:5.1.3" +"@types/levelup@npm:^5.1.2, @types/levelup@npm:^5.1.3": + version: 5.1.5 + resolution: "@types/levelup@npm:5.1.5" dependencies: "@types/abstract-leveldown": "*" "@types/level-errors": "*" "@types/node": "*" - checksum: 948642ea481573eec323e5f8b5475c1ab32b5eac0982e5a2a9904ac74336d32fe579d51219410770c1cb88f69f0135fd9be3cbfa5ee6e9b84f81eeddf7ed8e0d + checksum: 844798bdc805e3c449e478e283eb1196892d3f4fb6b24158faa5f10b283fa785da736917de1ec030ce1b8be9a8c54881cee2354632cb540ef80a325a19d920d1 languageName: node linkType: hard "@types/lodash.camelcase@npm:^4.3.7": - version: 4.3.7 - resolution: "@types/lodash.camelcase@npm:4.3.7" + version: 4.3.9 + resolution: "@types/lodash.camelcase@npm:4.3.9" dependencies: "@types/lodash": "*" - checksum: ef068b921ab439f7b1a2c0ebbd890ba64ba437fc6aeb5e3ac18d34da30f9054fceaac5ccfdfa9e12b2fc403e10910439d3ebf92ba2f93de03c2f02261adfc000 + checksum: f54132d38ffa72b25bce2111e4d28f339599f6d4fcfc1248a89d1d96445512d7a431f0b0e74f6e6c8d6bc09fe53cf94d9426e188d8feacb3ffe04cd9c3a602e7 languageName: node linkType: hard "@types/lodash.capitalize@npm:^4.2.7": - version: 4.2.7 - resolution: "@types/lodash.capitalize@npm:4.2.7" + version: 4.2.9 + resolution: "@types/lodash.capitalize@npm:4.2.9" dependencies: "@types/lodash": "*" - checksum: dab8b781d7dcc56c18ba0c8286a6ccb61cc598d936a449265453a473e62b2b6d7c109c4447dfeb8ccacc4088769bc3bfd0d39bc8797f03e4e685d4f4b1bc7c01 + checksum: 54a9154b2084392986646335d5ed4902a89c24ce675cf8b8cfcd022f6a0eed71c30c2f8cc4b2682cfc5c55a5e1fdad2340609ba58db451dfdd41d82b14c88995 languageName: node linkType: hard "@types/lodash.chunk@npm:^4.2.7": - version: 4.2.7 - resolution: "@types/lodash.chunk@npm:4.2.7" + version: 4.2.9 + resolution: "@types/lodash.chunk@npm:4.2.9" dependencies: "@types/lodash": "*" - checksum: 09df5ca00d8866776038bf94658d30b4ea84bffe5f81c14c01568bcb6be692bf59f6ea093de2bb0afbb3f8e54ae96ebd97595f2838ab59b77865427ca77d391e + checksum: ccffe7273a0941655d5b988baeffa8f7d4d19a8b43ed728ff4e616013506efe85914ba99d4ec299e0106506e1bca3923b065eabb0aa5f1e4b18f68e790ae6b88 languageName: node linkType: hard "@types/lodash.clonedeep@npm:^4.5.7": - version: 4.5.7 - resolution: "@types/lodash.clonedeep@npm:4.5.7" + version: 4.5.9 + resolution: "@types/lodash.clonedeep@npm:4.5.9" dependencies: "@types/lodash": "*" - checksum: 20d6a20970b3b54b3c10cf17ace1cea49c4905d7f7cae2575a98108466e8d4c9bea3b3449d11ccaac4da1fc9bab225f477f4c2dbea8ba877cc47f629455efb69 + checksum: ef85512b7dce7a4f981a818ae44d11982907e1f26b5b26bedf0957c35e8591eb8e1d24fa31ca851d4b40e0a1ee88563853d762412691fe5f357e8335cead2325 languageName: node linkType: hard "@types/lodash.clonedeepwith@npm:^4.5.7": - version: 4.5.7 - resolution: "@types/lodash.clonedeepwith@npm:4.5.7" + version: 4.5.9 + resolution: "@types/lodash.clonedeepwith@npm:4.5.9" dependencies: "@types/lodash": "*" - checksum: 2cfc7c55533abf491a2b6897a233244b187bf55ac51545e4f0b937721fdfb7e82cb3743290aa4dcb41487d653d95fdddc172b39318a893c9a2ca6658b0866430 + checksum: c690fb28126f7248894f08abe13d6c7684dd0a4e9ac545a419a8687438b50d2e6fe32b31176c65a394d3ade4fd16a145ecbf77e7521992414bf657b8b1d936c8 languageName: node linkType: hard "@types/lodash.every@npm:^4.6.7": - version: 4.6.7 - resolution: "@types/lodash.every@npm:4.6.7" + version: 4.6.9 + resolution: "@types/lodash.every@npm:4.6.9" dependencies: "@types/lodash": "*" - checksum: 9bf1475332401948453019a6fc4d9ee1275acfe52dccd2b81746927ef4623f6fb846849a15dfe08ec5b5c50e6302875a19ac469cc820e7f05d7517407ba41dc7 + checksum: 9239e078c1aba47ead8d3232d46869a6b9e886387c92c8d9a0a1549b7f21864cfa8428b5725ebbfcd31e5c54761a6fa3d4bbe049a776fe3e973cb10d967fbd0c languageName: node linkType: hard "@types/lodash.isequal@npm:^4.5.6": - version: 4.5.6 - resolution: "@types/lodash.isequal@npm:4.5.6" + version: 4.5.8 + resolution: "@types/lodash.isequal@npm:4.5.8" dependencies: "@types/lodash": "*" - checksum: 0f065989408a9e0584e6c27495be2cd4602e62650f55266aa195812582444463c0c8570c674ae84f947c11748f49ab43fd5b482fa120e08eeee4c23b162edc38 + checksum: f3180c2d2925514fff1908a1303c11468c9f39b47fd7b053416aad3f1447f8e4a9894dd0460187ac9ac19387e25aec8dd8214d13a50a0967e0dc9cca8e4c5353 languageName: node linkType: hard "@types/lodash.omit@npm:^4.5.7": - version: 4.5.7 - resolution: "@types/lodash.omit@npm:4.5.7" + version: 4.5.9 + resolution: "@types/lodash.omit@npm:4.5.9" dependencies: "@types/lodash": "*" - checksum: e30600de518e648f4e9590d9238506ceab561726ec2fe56b4ff29b17aa1e47cbf9188be259b7d606dfb2040998c778533ccc0c58f065cca44ab5a6dbc8b6e518 + checksum: 5be43f3598d6b1fa481fe7046e9e15e2225f547e0e309746c2b87f4e4fa8705e96c564e2762a9312e73e2a223d701ab893b122c506500de49a4b9fb40fb6d17c languageName: node linkType: hard "@types/lodash.pick@npm:^4.4.7": - version: 4.4.7 - resolution: "@types/lodash.pick@npm:4.4.7" + version: 4.4.9 + resolution: "@types/lodash.pick@npm:4.4.9" dependencies: "@types/lodash": "*" - checksum: 78428a83b5d85e75bd13fb632030f9adb08dfc5bde3a9b6a302434fe7ac98e62919f87a7337e0ba674017d63bc57a8855ef863f5fcecd25e63b1d39eba2e4697 + checksum: 007c298133b5bc2157f13d6641b139d2782b4af7b6a942cc4b1a427c6ebc6020e46b32ee2e782607389b0c63a5211d51152606424fdfe25f3eeac8afea0bdf02 languageName: node linkType: hard "@types/lodash.startcase@npm:^4.4.7": - version: 4.4.7 - resolution: "@types/lodash.startcase@npm:4.4.7" + version: 4.4.9 + resolution: "@types/lodash.startcase@npm:4.4.9" dependencies: "@types/lodash": "*" - checksum: ee5b903e7cb99a4c747325c38167dea70c10f9929823033f7f2e02aad5e227c84f80c6f7d9d6923a7c0f30a429c5ea4a1b6505bd50a96655b6ab7ac43e8ebe27 + checksum: 448203f0b6d31c1af9fe8292d5417af670bee560bb0af0cac3a6047b90c2d60ba03197367c2defae21e3982c665763197343863ce7d97131efa8e13e6431fe9f languageName: node linkType: hard @@ -3601,180 +3468,159 @@ __metadata: linkType: hard "@types/lodash@npm:*": - version: 4.14.196 - resolution: "@types/lodash@npm:4.14.196" - checksum: 201d17c3e62ae02a93c99ec78e024b2be9bd75564dd8fd8c26f6ac51a985ab280d28ce2688c3bcdfe785b0991cd9814edff19ee000234c7b45d9a697f09feb6a - languageName: node - linkType: hard - -"@types/memdown@npm:^3.0.0, @types/memdown@npm:^3.0.1": - version: 3.0.1 - resolution: "@types/memdown@npm:3.0.1" - dependencies: - "@types/abstract-leveldown": "*" - checksum: 08085fff44f1868d352ec3be81890cfd0034ad1086f3dbc8bbfc412d55434bb6f5bbd512a22a92f2f9c416ccb0784815ecaa0a6fada4478c9a39db3f0f7a1a43 + version: 4.14.202 + resolution: "@types/lodash@npm:4.14.202" + checksum: a91acf3564a568c6f199912f3eb2c76c99c5a0d7e219394294213b3f2d54f672619f0fde4da22b29dc5d4c31457cd799acc2e5cb6bd90f9af04a1578483b6ff7 languageName: node linkType: hard -"@types/memdown@npm:^3.0.2": - version: 3.0.2 - resolution: "@types/memdown@npm:3.0.2" +"@types/memdown@npm:^3.0.0, @types/memdown@npm:^3.0.1, @types/memdown@npm:^3.0.2, @types/memdown@npm:^3.0.3": + version: 3.0.5 + resolution: "@types/memdown@npm:3.0.5" dependencies: "@types/abstract-leveldown": "*" - checksum: bfc36240e32ed6f82b2b858be88aa8814e8c1e0a8922aae8bf44ce07a2c9e0e7bf867e01cab8aad10e1cab2d0bcb0b800b4f63b89d9c791328892acc00683469 + checksum: a0c384858354da754933a83295642ac8710af08e1bf499ff3ae87d86ea34a0d9ebf2bdf75ec45d992cd152580c671c82ea4a0aea03f10eeb3aed33eceb21819e languageName: node linkType: hard -"@types/memdown@npm:^3.0.3": - version: 3.0.3 - resolution: "@types/memdown@npm:3.0.3" - dependencies: - "@types/abstract-leveldown": "*" - checksum: 9aa311838574b51e4334878102c80c6abc0e1ec14fe00f98c6ee812f3e6b24db53de632e0f763692730e0147e5c41add0ac4257c3deb3dc7abce176708ed73a4 +"@types/methods@npm:^1.1.4": + version: 1.1.4 + resolution: "@types/methods@npm:1.1.4" + checksum: ad2a7178486f2fd167750f3eb920ab032a947ff2e26f55c86670a6038632d790b46f52e5b6ead5823f1e53fc68028f1e9ddd15cfead7903e04517c88debd72b1 languageName: node linkType: hard "@types/mime@npm:*": - version: 3.0.1 - resolution: "@types/mime@npm:3.0.1" - checksum: 4040fac73fd0cea2460e29b348c1a6173da747f3a87da0dbce80dd7a9355a3d0e51d6d9a401654f3e5550620e3718b5a899b2ec1debf18424e298a2c605346e7 + version: 3.0.4 + resolution: "@types/mime@npm:3.0.4" + checksum: a6139c8e1f705ef2b064d072f6edc01f3c099023ad7c4fce2afc6c2bf0231888202adadbdb48643e8e20da0ce409481a49922e737eca52871b3dc08017455843 languageName: node linkType: hard "@types/mime@npm:^1": - version: 1.3.2 - resolution: "@types/mime@npm:1.3.2" - checksum: 0493368244cced1a69cb791b485a260a422e6fcc857782e1178d1e6f219f1b161793e9f87f5fae1b219af0f50bee24fcbe733a18b4be8fdd07a38a8fb91146fd + version: 1.3.5 + resolution: "@types/mime@npm:1.3.5" + checksum: e29a5f9c4776f5229d84e525b7cd7dd960b51c30a0fb9a028c0821790b82fca9f672dab56561e2acd9e8eed51d431bde52eafdfef30f643586c4162f1aecfc78 languageName: node linkType: hard "@types/minimist@npm:^1.2.0": - version: 1.2.2 - resolution: "@types/minimist@npm:1.2.2" - checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + version: 1.2.5 + resolution: "@types/minimist@npm:1.2.5" + checksum: 477047b606005058ab0263c4f58097136268007f320003c348794f74adedc3166ffc47c80ec3e94687787f2ab7f4e72c468223946e79892cf0fd9e25e9970a90 languageName: node linkType: hard "@types/ms@npm:*": - version: 0.7.31 - resolution: "@types/ms@npm:0.7.31" - checksum: daadd354aedde024cce6f5aa873fefe7b71b22cd0e28632a69e8b677aeb48ae8caa1c60e5919bb781df040d116b01cb4316335167a3fc0ef6a63fa3614c0f6da + version: 0.7.34 + resolution: "@types/ms@npm:0.7.34" + checksum: f38d36e7b6edecd9badc9cf50474159e9da5fa6965a75186cceaf883278611b9df6669dc3a3cc122b7938d317b68a9e3d573d316fcb35d1be47ec9e468c6bd8a languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=13.7.0": - version: 20.4.5 - resolution: "@types/node@npm:20.4.5" - checksum: 36a0304a8dc346a1b2d2edac4c4633eecf70875793d61a5274d0df052d7a7af7a8e34f29884eac4fbd094c4f0201477dcb39c0ecd3307ca141688806538d1138 +"@types/node@npm:*": + version: 20.11.7 + resolution: "@types/node@npm:20.11.7" + dependencies: + undici-types: ~5.26.4 + checksum: 61ea0718bccda31110c643190518407b7c50d26698a20e3522871608db5fa3d2d43d1ae57c609068eae6996d563db43326045a90f22a9aacc825e8d6c7aea2ce languageName: node linkType: hard "@types/node@npm:^18.14.6, @types/node@npm:^18.15.11, @types/node@npm:^18.15.3, @types/node@npm:^18.7.23": - version: 18.17.1 - resolution: "@types/node@npm:18.17.1" - checksum: 56201bda9a2d05d68602df63b4e67b0545ac8c6d0280bd5fb31701350a978a577a027501fbf49db99bf177f2242ebd1244896bfd35e89042d5bd7dfebff28d4e + version: 18.19.10 + resolution: "@types/node@npm:18.19.10" + dependencies: + undici-types: ~5.26.4 + checksum: eea429c1fe8d25702c1e860f5c4ac053db3c52a5884646f458513b622a507660a6c88c717ee4f106e63c82f4ec6cafbf999e3f3f1d3083f7a40b4f715e03332b languageName: node linkType: hard "@types/normalize-package-data@npm:^2.4.0": - version: 2.4.1 - resolution: "@types/normalize-package-data@npm:2.4.1" - checksum: e87bccbf11f95035c89a132b52b79ce69a1e3652fe55962363063c9c0dae0fe2477ebc585e03a9652adc6f381d24ba5589cc5e51849df4ced3d3e004a7d40ed5 + version: 2.4.4 + resolution: "@types/normalize-package-data@npm:2.4.4" + checksum: 65dff72b543997b7be8b0265eca7ace0e34b75c3e5fee31de11179d08fa7124a7a5587265d53d0409532ecb7f7fba662c2012807963e1f9b059653ec2c83ee05 languageName: node linkType: hard "@types/pako@npm:^2.0.0": - version: 2.0.0 - resolution: "@types/pako@npm:2.0.0" - checksum: 50240a036b5e6acabbf36ac4dca93ec9e619241f0404da8d401cdb427bec3029833324b8a04c4b1ae2ecbc33422fdec31dbf9f43653d9d07cafb82ace78dfccd + version: 2.0.3 + resolution: "@types/pako@npm:2.0.3" + checksum: 0746dd5d29eccf5b2e6cceb3ccb093851219e78bd2e2e20d25757e247987139e061e5d4ba37cb5295493f06e3c683c74f8876011cd8a3f3748a09244fbc841d9 languageName: node linkType: hard "@types/qs@npm:*": - version: 6.9.7 - resolution: "@types/qs@npm:6.9.7" - checksum: 7fd6f9c25053e9b5bb6bc9f9f76c1d89e6c04f7707a7ba0e44cc01f17ef5284adb82f230f542c2d5557d69407c9a40f0f3515e8319afd14e1e16b5543ac6cdba + version: 6.9.11 + resolution: "@types/qs@npm:6.9.11" + checksum: 620ca1628bf3da65662c54ed6ebb120b18a3da477d0bfcc872b696685a9bb1893c3c92b53a1190a8f54d52eaddb6af8b2157755699ac83164604329935e8a7f2 languageName: node linkType: hard "@types/range-parser@npm:*": - version: 1.2.4 - resolution: "@types/range-parser@npm:1.2.4" - checksum: b7c0dfd5080a989d6c8bb0b6750fc0933d9acabeb476da6fe71d8bdf1ab65e37c136169d84148034802f48378ab94e3c37bb4ef7656b2bec2cb9c0f8d4146a95 - languageName: node - linkType: hard - -"@types/retry@npm:0.12.1": - version: 0.12.1 - resolution: "@types/retry@npm:0.12.1" - checksum: 5f46b2556053655f78262bb33040dc58417c900457cc63ff37d6c35349814471453ef511af0cec76a540c601296cd2b22f64bab1ab649c0dacc0223765ba876c - languageName: node - linkType: hard - -"@types/semver@npm:^7.5.0": - version: 7.5.0 - resolution: "@types/semver@npm:7.5.0" - checksum: 0a64b9b9c7424d9a467658b18dd70d1d781c2d6f033096a6e05762d20ebbad23c1b69b0083b0484722aabf35640b78ccc3de26368bcae1129c87e9df028a22e2 + version: 1.2.7 + resolution: "@types/range-parser@npm:1.2.7" + checksum: 95640233b689dfbd85b8c6ee268812a732cf36d5affead89e806fe30da9a430767af8ef2cd661024fd97e19d61f3dec75af2df5e80ec3bea000019ab7028629a languageName: node linkType: hard -"@types/semver@npm:^7.5.2": - version: 7.5.2 - resolution: "@types/semver@npm:7.5.2" - checksum: 743aa8a2b58e20b329c19bd2459152cb049d12fafab7279b90ac11e0f268c97efbcb606ea0c681cca03f79015381b40d9b1244349b354270bec3f939ed49f6e9 +"@types/retry@npm:0.12.2": + version: 0.12.2 + resolution: "@types/retry@npm:0.12.2" + checksum: e5675035717b39ce4f42f339657cae9637cf0c0051cf54314a6a2c44d38d91f6544be9ddc0280587789b6afd056be5d99dbe3e9f4df68c286c36321579b1bf4a languageName: node linkType: hard -"@types/semver@npm:^7.5.4": - version: 7.5.4 - resolution: "@types/semver@npm:7.5.4" - checksum: 120c0189f6fec5f2d12d0d71ac8a4cfa952dc17fa3d842e8afddb82bba8828a4052f8799c1653e2b47ae1977435f38e8985658fde971905ce5afb8e23ee97ecf +"@types/semver@npm:^7.5.0, @types/semver@npm:^7.5.2, @types/semver@npm:^7.5.4": + version: 7.5.6 + resolution: "@types/semver@npm:7.5.6" + checksum: 563a0120ec0efcc326567db2ed920d5d98346f3638b6324ea6b50222b96f02a8add3c51a916b6897b51523aad8ac227d21d3dcf8913559f1bfc6c15b14d23037 languageName: node linkType: hard "@types/send@npm:*": - version: 0.17.1 - resolution: "@types/send@npm:0.17.1" + version: 0.17.4 + resolution: "@types/send@npm:0.17.4" dependencies: "@types/mime": ^1 "@types/node": "*" - checksum: 10b620a5960058ef009afbc17686f680d6486277c62f640845381ec4baa0ea683fdd77c3afea4803daf5fcddd3fb2972c8aa32e078939f1d4e96f83195c89793 + checksum: cf4db48251bbb03cd6452b4de6e8e09e2d75390a92fd798eca4a803df06444adc94ed050246c94c7ed46fb97be1f63607f0e1f13c3ce83d71788b3e08640e5e0 languageName: node linkType: hard "@types/serve-static@npm:*": - version: 1.15.2 - resolution: "@types/serve-static@npm:1.15.2" + version: 1.15.5 + resolution: "@types/serve-static@npm:1.15.5" dependencies: "@types/http-errors": "*" "@types/mime": "*" "@types/node": "*" - checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e + checksum: 0ff4b3703cf20ba89c9f9e345bc38417860a88e85863c8d6fe274a543220ab7f5f647d307c60a71bb57dc9559f0890a661e8dc771a6ec5ef195d91c8afc4a893 languageName: node linkType: hard "@types/sha256@npm:^0.2.0": - version: 0.2.0 - resolution: "@types/sha256@npm:0.2.0" + version: 0.2.2 + resolution: "@types/sha256@npm:0.2.2" dependencies: "@types/node": "*" - checksum: f3c8e0dcaf11d833292b7dd19db567ef41b23036b2fb9ea7335cba100aac8c56e1346171fae6c63885f6c0e1048550506fd165628bc0001902fea010a16d3842 + checksum: 7701b9dc105e7b877090c9bb9b02e10953831737b599bfc7658635ae35d2b21927f77028f8090d50ea0281058ee975f190d664e5351c5aaf5535a1c26ba01f1f languageName: node linkType: hard -"@types/sinon@npm:^10.0.15": - version: 10.0.16 - resolution: "@types/sinon@npm:10.0.16" +"@types/sinon@npm:^17.0.0": + version: 17.0.3 + resolution: "@types/sinon@npm:17.0.3" dependencies: "@types/sinonjs__fake-timers": "*" - checksum: 1216aac584500d6bf845ca76f57e82f8459cf9de4ed80a55e50aa4438360fc418789a42181e211c5d279e97f86a3a994e3c81e43971d540737caca0193242bbf + checksum: c8e9956d9c90fe1ec1cc43085ae48897f93f9ea86e909ab47f255ea71f5229651faa070393950fb6923aef426c84e92b375503f9f8886ef44668b82a8ee49e9a languageName: node linkType: hard "@types/sinonjs__fake-timers@npm:*": - version: 8.1.2 - resolution: "@types/sinonjs__fake-timers@npm:8.1.2" - checksum: bbc73a5ab6c0ec974929392f3d6e1e8db4ebad97ec506d785301e1c3d8a4f98a35b1aa95b97035daef02886fd8efd7788a2fa3ced2ec7105988bfd8dce61eedd + version: 8.1.5 + resolution: "@types/sinonjs__fake-timers@npm:8.1.5" + checksum: 7e3c08f6c13df44f3ea7d9a5155ddf77e3f7314c156fa1c5a829a4f3763bafe2f75b1283b887f06e6b4296996a2f299b70f64ff82625f9af5885436e2524d10c languageName: node linkType: hard @@ -3788,86 +3634,86 @@ __metadata: linkType: hard "@types/stack-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "@types/stack-utils@npm:2.0.1" - checksum: 205fdbe3326b7046d7eaf5e494d8084f2659086a266f3f9cf00bccc549c8e36e407f88168ad4383c8b07099957ad669f75f2532ed4bc70be2b037330f7bae019 + version: 2.0.3 + resolution: "@types/stack-utils@npm:2.0.3" + checksum: 72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 languageName: node linkType: hard "@types/superagent@npm:*": - version: 4.1.18 - resolution: "@types/superagent@npm:4.1.18" + version: 8.1.3 + resolution: "@types/superagent@npm:8.1.3" dependencies: - "@types/cookiejar": "*" + "@types/cookiejar": ^2.1.5 + "@types/methods": ^1.1.4 "@types/node": "*" - checksum: 4e50cb41e6f0ac55917dddae4665e5251ce0ec086f89172c8b53432c0c3ee026b9243ba4c994aa2702720d7c288fd7ae77f241f9fb9fb15d2d7c4b6bc2ee7079 + checksum: 284307f88986b733fc22ede29d0660f26e7e2d4f8ee7bf772544633404e5d21026bfb202b7c3aedab1bedf6e9276e96fbebc6e07cc2163e6729d5a36dc842215 languageName: node linkType: hard "@types/supertest@npm:^2.0.12": - version: 2.0.12 - resolution: "@types/supertest@npm:2.0.12" + version: 2.0.16 + resolution: "@types/supertest@npm:2.0.16" dependencies: "@types/superagent": "*" - checksum: f0e2b44f86bec2f708d6a3d0cb209055b487922040773049b0f8c6b557af52d4b5fa904e17dfaa4ce6e610172206bbec7b62420d158fa57b6ffc2de37b1730d3 + checksum: 2fc998ea698e0467cdbe3bea0ebce2027ea3a45a13e51a6cecb0435f44b486faecf99c34d8702d2d7fe033e6e09fdd2b374af52ecc8d0c69a1deec66b8c0dd52 languageName: node linkType: hard "@types/triple-beam@npm:^1.3.2": - version: 1.3.2 - resolution: "@types/triple-beam@npm:1.3.2" - checksum: dd7b4a563fb710abc992e5d59eac481bed9e303fada2e276e37b00be31c392e03300ee468e57761e616512872e77935f92472877d0704a19688d15a726cee17b + version: 1.3.5 + resolution: "@types/triple-beam@npm:1.3.5" + checksum: 519b6a1b30d4571965c9706ad5400a200b94e4050feca3e7856e3ea7ac00ec9903e32e9a10e2762d0f7e472d5d03e5f4b29c16c0bd8c1f77c8876c683b2231f1 languageName: node linkType: hard "@types/ws@npm:^8.5.4": - version: 8.5.5 - resolution: "@types/ws@npm:8.5.5" + version: 8.5.10 + resolution: "@types/ws@npm:8.5.10" dependencies: "@types/node": "*" - checksum: d00bf8070e6938e3ccf933010921c6ce78ac3606696ce37a393b27a9a603f7bd93ea64f3c5fa295a2f743575ba9c9a9fdb904af0f5fe2229bf2adf0630386e4a + checksum: 3ec416ea2be24042ebd677932a462cf16d2080393d8d7d0b1b3f5d6eaa4a7387aaf0eefb99193c0bfd29444857cf2e0c3ac89899e130550dc6c14ada8a46d25e languageName: node linkType: hard "@types/yargs-parser@npm:*": - version: 21.0.0 - resolution: "@types/yargs-parser@npm:21.0.0" - checksum: b2f4c8d12ac18a567440379909127cf2cec393daffb73f246d0a25df36ea983b93b7e9e824251f959e9f928cbc7c1aab6728d0a0ff15d6145f66cec2be67d9a2 + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: ef236c27f9432983e91432d974243e6c4cdae227cb673740320eff32d04d853eed59c92ca6f1142a335cfdc0e17cccafa62e95886a8154ca8891cc2dec4ee6fc languageName: node linkType: hard "@types/yargs@npm:^17.0.8": - version: 17.0.24 - resolution: "@types/yargs@npm:17.0.24" + version: 17.0.32 + resolution: "@types/yargs@npm:17.0.32" dependencies: "@types/yargs-parser": "*" - checksum: 5f3ac4dc4f6e211c1627340160fbe2fd247ceba002190da6cf9155af1798450501d628c9165a183f30a224fc68fa5e700490d740ff4c73e2cdef95bc4e8ba7bf + checksum: 4505bdebe8716ff383640c6e928f855b5d337cb3c68c81f7249fc6b983d0aa48de3eee26062b84f37e0d75a5797bc745e0c6e76f42f81771252a758c638f36ba languageName: node linkType: hard "@types/yauzl@npm:^2.9.1": - version: 2.10.0 - resolution: "@types/yauzl@npm:2.10.0" + version: 2.10.3 + resolution: "@types/yauzl@npm:2.10.3" dependencies: "@types/node": "*" - checksum: 55d27ae5d346ea260e40121675c24e112ef0247649073848e5d4e03182713ae4ec8142b98f61a1c6cbe7d3b72fa99bbadb65d8b01873e5e605cdc30f1ff70ef2 + checksum: 5ee966ea7bd6b2802f31ad4281c92c4c0b6dfa593c378a2582c58541fa113bec3d70eb0696b34ad95e8e6861a884cba6c3e351285816693ed176222f840a8c08 languageName: node linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/eslint-plugin@npm:6.2.1" + version: 6.19.1 + resolution: "@typescript-eslint/eslint-plugin@npm:6.19.1" dependencies: "@eslint-community/regexpp": ^4.5.1 - "@typescript-eslint/scope-manager": 6.2.1 - "@typescript-eslint/type-utils": 6.2.1 - "@typescript-eslint/utils": 6.2.1 - "@typescript-eslint/visitor-keys": 6.2.1 + "@typescript-eslint/scope-manager": 6.19.1 + "@typescript-eslint/type-utils": 6.19.1 + "@typescript-eslint/utils": 6.19.1 + "@typescript-eslint/visitor-keys": 6.19.1 debug: ^4.3.4 graphemer: ^1.4.0 ignore: ^5.2.4 natural-compare: ^1.4.0 - natural-compare-lite: ^1.4.0 semver: ^7.5.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -3876,44 +3722,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: e73f3fe36519d895037d223f3ddf200b97e17bcde9390984118c38733add1edf996357c809ec2db92cec61bc7c9e5a3d9a583e0d0f92fa9c3919b68716a27b37 + checksum: ad04000cd6c15d864ff92655baa3aec99bb0ccf4714fedd145fedde60a27590a5feafe480beb2f0f3864b416098bde1e9431bada7480eb7ca4efad891e1d2f6f languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/parser@npm:6.2.1" + version: 6.19.1 + resolution: "@typescript-eslint/parser@npm:6.19.1" dependencies: - "@typescript-eslint/scope-manager": 6.2.1 - "@typescript-eslint/types": 6.2.1 - "@typescript-eslint/typescript-estree": 6.2.1 - "@typescript-eslint/visitor-keys": 6.2.1 + "@typescript-eslint/scope-manager": 6.19.1 + "@typescript-eslint/types": 6.19.1 + "@typescript-eslint/typescript-estree": 6.19.1 + "@typescript-eslint/visitor-keys": 6.19.1 debug: ^4.3.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: cf4768cbfc696ce1d4b15ae55b3d2b52761e91a4a80e738cf3a75c501c2257d735cd6e462567965069d0d693a8cf5463ab9e8b97c36c6ed1fccd3c1c09855bdb + checksum: cd29619da08a2d9b7123ba4d8240989c747f8e0d5672179d8b147e413ee1334d1fa48570b0c37cf0ae4e26a275fd2d268cbe702c6fed639d3331abbb3292570a languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/scope-manager@npm:6.2.1" +"@typescript-eslint/scope-manager@npm:6.19.1": + version: 6.19.1 + resolution: "@typescript-eslint/scope-manager@npm:6.19.1" dependencies: - "@typescript-eslint/types": 6.2.1 - "@typescript-eslint/visitor-keys": 6.2.1 - checksum: 3bb461678c7e729895c5ac16781ec7d66efc6ffa944bb49693ce8e9560f9a6cac70929157c0fc0875b2829ae19a5cdabb97973ddcfb7e81c16e22cdd5d39e3fd + "@typescript-eslint/types": 6.19.1 + "@typescript-eslint/visitor-keys": 6.19.1 + checksum: 848cdebc16a3803e8a6d6035a7067605309a652bb2425f475f755b5ace4d80d2c17c8c8901f0f4759556da8d0a5b71024d472b85c3f3c70d0e6dcfe2a972ef35 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/type-utils@npm:6.2.1" +"@typescript-eslint/type-utils@npm:6.19.1": + version: 6.19.1 + resolution: "@typescript-eslint/type-utils@npm:6.19.1" dependencies: - "@typescript-eslint/typescript-estree": 6.2.1 - "@typescript-eslint/utils": 6.2.1 + "@typescript-eslint/typescript-estree": 6.19.1 + "@typescript-eslint/utils": 6.19.1 debug: ^4.3.4 ts-api-utils: ^1.0.1 peerDependencies: @@ -3921,7 +3767,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 7f8d80f03e6ddc1838307a2a4df61dc4bd8400efb9dcc7316063ae293fce54afad238404a0c25cd2cdaceee73ae514f254b850bd7ff11e2def700d5d6b90af05 + checksum: eab1a30f8d85f7c6e2545de5963fbec2f3bb91913d59623069b4b0db372a671ab048c7018376fc853c3af06ea39417f3e7b27dd665027dd812347a5e64cecd77 languageName: node linkType: hard @@ -3939,28 +3785,29 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/types@npm:6.2.1" - checksum: 388d32f15a9db8ad5d80794caf9ab280d6e5a428efdf4f6a6dfc4069afe4d19da32d628acf638e4c5b92ee77a9a18eecf728a778a3b91cc8a24484af579fc9cf +"@typescript-eslint/types@npm:6.19.1": + version: 6.19.1 + resolution: "@typescript-eslint/types@npm:6.19.1" + checksum: 598ce222b59c20432d06f60703d0c2dd16d9b2151569c192852136c57b8188e3ef6ef9fddaa2c136c9a756fcc7d873c0e29ec41cfd340564842287ef7b4571cd languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/typescript-estree@npm:6.2.1" +"@typescript-eslint/typescript-estree@npm:6.19.1": + version: 6.19.1 + resolution: "@typescript-eslint/typescript-estree@npm:6.19.1" dependencies: - "@typescript-eslint/types": 6.2.1 - "@typescript-eslint/visitor-keys": 6.2.1 + "@typescript-eslint/types": 6.19.1 + "@typescript-eslint/visitor-keys": 6.19.1 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 + minimatch: 9.0.3 semver: ^7.5.4 ts-api-utils: ^1.0.1 peerDependenciesMeta: typescript: optional: true - checksum: 3d9beeb5e36b8827de5c160ed8e5c111dd66ca00671b183409b051e242b291480679b900bb74aaf4895dcae49497037567d3fcbbe67fa9930786ddd01c685f04 + checksum: fb71a14aeee0468780219c5b8d39075f85d360b04ccd0ee88f4f0a615d2c232a6d3016e36d8c6eda2d9dfda86b4f4cc2c3d7582940fb29d33c7cf305e124d4e2 languageName: node linkType: hard @@ -4000,20 +3847,20 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/utils@npm:6.2.1" +"@typescript-eslint/utils@npm:6.19.1": + version: 6.19.1 + resolution: "@typescript-eslint/utils@npm:6.19.1" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.12 "@types/semver": ^7.5.0 - "@typescript-eslint/scope-manager": 6.2.1 - "@typescript-eslint/types": 6.2.1 - "@typescript-eslint/typescript-estree": 6.2.1 + "@typescript-eslint/scope-manager": 6.19.1 + "@typescript-eslint/types": 6.19.1 + "@typescript-eslint/typescript-estree": 6.19.1 semver: ^7.5.4 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: d16356a633f39d988a9af159da15e28c6a28fa47abce372061c79cf186d193d148e1c32862c9702ff87e2a06f7a2f82773e4b56320a39f432f4b1a989f8005ad + checksum: fe72e75c3ea17a85772b83f148555ea94ff5d55d13586f3fc038833197a74f8071e14c2bbf1781c40eec20005f052f4be2513a725eea82a15da3cb9af3046c70 languageName: node linkType: hard @@ -4037,13 +3884,20 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.2.1": - version: 6.2.1 - resolution: "@typescript-eslint/visitor-keys@npm:6.2.1" +"@typescript-eslint/visitor-keys@npm:6.19.1": + version: 6.19.1 + resolution: "@typescript-eslint/visitor-keys@npm:6.19.1" dependencies: - "@typescript-eslint/types": 6.2.1 + "@typescript-eslint/types": 6.19.1 eslint-visitor-keys: ^3.4.1 - checksum: c05a1c45129f2cf9a8c49dadc3da10b675232e59b69dfe9fdc0bfb45d3be077ceff78097baf50e502dab3e71ce9fd799d2015e356a4be2787ee10c6c7a44ea8a + checksum: bdf057a42e776970a89cdd568e493e3ea7ec085544d8f318d33084da63c3395ad2c0fb9cef9f61ceeca41f5dab54ab064b7078fe596889005e412ec74d2d1ae4 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.2.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 4f656b7b4672f2ce6e272f2427d8b0824ed11546a601d8d5412b9d7704e83db38a8d9f402ecdf2b9063fc164af842ad0ec4a55819f621ed7e7ea4d1efcc74524 languageName: node linkType: hard @@ -4257,10 +4111,10 @@ __metadata: languageName: node linkType: hard -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 0e994ad2aa6575f94670d8a2149afe94465de9cedaaaac364e7fb43a40c3691c980ff74899f682f4ca58fa96b4cbd7421a015d3a6defe43a442117d7821a2f36 languageName: node linkType: hard @@ -4279,6 +4133,21 @@ __metadata: languageName: node linkType: hard +"abitype@npm:0.9.8": + version: 0.9.8 + resolution: "abitype@npm:0.9.8" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3 >=3.19.1 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: d7d887f29d6821e3f7a400de9620511b80ead3f85c5c87308aaec97965d3493e6687ed816e88722b4f512249bd66dee9e69231b49af0e1db8f69400a62c87cf6 + languageName: node + linkType: hard + "abitype@npm:^0.8.11": version: 0.8.11 resolution: "abitype@npm:0.8.11" @@ -4345,27 +4214,18 @@ __metadata: linkType: hard "acorn-walk@npm:^8.1.1": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 + version: 8.3.2 + resolution: "acorn-walk@npm:8.3.2" + checksum: 3626b9d26a37b1b427796feaa5261faf712307a8920392c8dce9a5739fb31077667f4ad2ec71c7ac6aaf9f61f04a9d3d67ff56f459587206fc04aa31c27ef392 languageName: node linkType: hard "acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" + version: 8.11.3 + resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d - languageName: node - linkType: hard - -"agent-base@npm:6, agent-base@npm:^6.0.2": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: 4 - checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + checksum: 76d8e7d559512566b43ab4aadc374f11f563f0a9e21626dd59cb2888444e9445923ae9f3699972767f18af61df89cd89f5eaaf772d1327b055b45cb829b4a88c languageName: node linkType: hard @@ -4378,17 +4238,6 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.2.1": - version: 4.3.0 - resolution: "agentkeepalive@npm:4.3.0" - dependencies: - debug: ^4.1.0 - depd: ^2.0.0 - humanize-ms: ^1.2.1 - checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 - languageName: node - linkType: hard - "aggregate-error@npm:^3.0.0": version: 3.1.0 resolution: "aggregate-error@npm:3.1.0" @@ -4513,23 +4362,6 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 - languageName: node - linkType: hard - "arg@npm:^4.1.0": version: 4.1.3 resolution: "arg@npm:4.1.3" @@ -4570,16 +4402,16 @@ __metadata: languageName: node linkType: hard -"array-includes@npm:^3.1.6": - version: 3.1.6 - resolution: "array-includes@npm:3.1.6" +"array-includes@npm:^3.1.7": + version: 3.1.7 + resolution: "array-includes@npm:3.1.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - get-intrinsic: ^1.1.3 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + get-intrinsic: ^1.2.1 is-string: ^1.0.7 - checksum: f22f8cd8ba8a6448d91eebdc69f04e4e55085d09232b5216ee2d476dab3ef59984e8d1889e662c6a0ed939dcb1b57fd05b2c0209c3370942fc41b752c82a2ca5 + checksum: 06f9e4598fac12a919f7c59a3f04f010ea07f0b7f0585465ed12ef528a60e45f374e79d1bddbb34cdd4338357d00023ddbd0ac18b0be36964f5e726e8965d7fc languageName: node linkType: hard @@ -4590,54 +4422,55 @@ __metadata: languageName: node linkType: hard -"array.prototype.findlastindex@npm:^1.2.2": - version: 1.2.2 - resolution: "array.prototype.findlastindex@npm:1.2.2" +"array.prototype.findlastindex@npm:^1.2.3": + version: 1.2.3 + resolution: "array.prototype.findlastindex@npm:1.2.3" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 es-shim-unscopables: ^1.0.0 - get-intrinsic: ^1.1.3 - checksum: 8a166359f69a2a751c843f26b9c8cd03d0dc396a92cdcb85f4126b5f1cecdae5b2c0c616a71ea8aff026bde68165b44950b3664404bb73db0673e288495ba264 + get-intrinsic: ^1.2.1 + checksum: 31f35d7b370c84db56484618132041a9af401b338f51899c2e78ef7690fbba5909ee7ca3c59a7192085b328cc0c68c6fd1f6d1553db01a689a589ae510f3966e languageName: node linkType: hard -"array.prototype.flat@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flat@npm:1.3.1" +"array.prototype.flat@npm:^1.3.2": + version: 1.3.2 + resolution: "array.prototype.flat@npm:1.3.2" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 es-shim-unscopables: ^1.0.0 - checksum: 5a8415949df79bf6e01afd7e8839bbde5a3581300e8ad5d8449dea52639e9e59b26a467665622783697917b43bf39940a6e621877c7dd9b3d1c1f97484b9b88b + checksum: 5d6b4bf102065fb3f43764bfff6feb3295d372ce89591e6005df3d0ce388527a9f03c909af6f2a973969a4d178ab232ffc9236654149173e0e187ec3a1a6b87b languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flatmap@npm:1.3.1" +"array.prototype.flatmap@npm:^1.3.2": + version: 1.3.2 + resolution: "array.prototype.flatmap@npm:1.3.2" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 es-shim-unscopables: ^1.0.0 - checksum: 8c1c43a4995f12cf12523436da28515184c753807b3f0bc2ca6c075f71c470b099e2090cc67dba8e5280958fea401c1d0c59e1db0143272aef6cd1103921a987 + checksum: ce09fe21dc0bcd4f30271f8144083aa8c13d4639074d6c8dc82054b847c7fc9a0c97f857491f4da19d4003e507172a78f4bcd12903098adac8b9cd374f734be3 languageName: node linkType: hard -"arraybuffer.prototype.slice@npm:^1.0.1": - version: 1.0.1 - resolution: "arraybuffer.prototype.slice@npm:1.0.1" +"arraybuffer.prototype.slice@npm:^1.0.2": + version: 1.0.2 + resolution: "arraybuffer.prototype.slice@npm:1.0.2" dependencies: array-buffer-byte-length: ^1.0.0 call-bind: ^1.0.2 define-properties: ^1.2.0 + es-abstract: ^1.22.1 get-intrinsic: ^1.2.1 is-array-buffer: ^3.0.2 is-shared-array-buffer: ^1.0.2 - checksum: e3e9b2a3e988ebfeddce4c7e8f69df730c9e48cb04b0d40ff0874ce3d86b3d1339dd520ffde5e39c02610bc172ecfbd4bc93324b1cabd9554c44a56b131ce0ce + checksum: c200faf437786f5b2c80d4564ff5481c886a16dee642ef02abdc7306c7edd523d1f01d1dd12b769c7eb42ac9bc53874510db19a92a2c035c0f6696172aafa5d3 languageName: node linkType: hard @@ -4698,9 +4531,9 @@ __metadata: linkType: hard "async@npm:^3.2.3": - version: 3.2.4 - resolution: "async@npm:3.2.4" - checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 + version: 3.2.5 + resolution: "async@npm:3.2.5" + checksum: 5ec77f1312301dee02d62140a6b1f7ee0edd2a0f983b6fd2b0849b969f245225b990b47b8243e7b9ad16451a53e7f68e753700385b706198ced888beedba3af4 languageName: node linkType: hard @@ -4725,20 +4558,20 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^29.6.2": - version: 29.6.2 - resolution: "babel-jest@npm:29.6.2" +"babel-jest@npm:^29.7.0": + version: 29.7.0 + resolution: "babel-jest@npm:29.7.0" dependencies: - "@jest/transform": ^29.6.2 + "@jest/transform": ^29.7.0 "@types/babel__core": ^7.1.14 babel-plugin-istanbul: ^6.1.1 - babel-preset-jest: ^29.5.0 + babel-preset-jest: ^29.6.3 chalk: ^4.0.0 graceful-fs: ^4.2.9 slash: ^3.0.0 peerDependencies: "@babel/core": ^7.8.0 - checksum: 3936b5d6ed6f08670c830ed919e38a4a593d0643b8e30fdeb16f4588b262ea5255fb96fd1849c02fba0b082ecfa4e788ce9a128ad1b9e654d46aac09c3a55504 + checksum: ee6f8e0495afee07cac5e4ee167be705c711a8cc8a737e05a587a131fdae2b3c8f9aa55dfd4d9c03009ac2d27f2de63d8ba96d3e8460da4d00e8af19ef9a83f7 languageName: node linkType: hard @@ -4755,15 +4588,15 @@ __metadata: languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-plugin-jest-hoist@npm:29.5.0" +"babel-plugin-jest-hoist@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-plugin-jest-hoist@npm:29.6.3" dependencies: "@babel/template": ^7.3.3 "@babel/types": ^7.3.3 "@types/babel__core": ^7.1.14 "@types/babel__traverse": ^7.0.6 - checksum: 099b5254073b6bc985b6d2d045ad26fb8ed30ff8ae6404c4fe8ee7cd0e98a820f69e3dfb871c7c65aae0f4b65af77046244c07bb92d49ef9005c90eedf681539 + checksum: 51250f22815a7318f17214a9d44650ba89551e6d4f47a2dc259128428324b52f5a73979d010cefd921fd5a720d8c1d55ad74ff601cd94c7bd44d5f6292fde2d1 languageName: node linkType: hard @@ -4789,15 +4622,15 @@ __metadata: languageName: node linkType: hard -"babel-preset-jest@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-preset-jest@npm:29.5.0" +"babel-preset-jest@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-preset-jest@npm:29.6.3" dependencies: - babel-plugin-jest-hoist: ^29.5.0 + babel-plugin-jest-hoist: ^29.6.3 babel-preset-current-node-syntax: ^1.0.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: 5566ca2762766c9319b4973d018d2fa08c0fcf6415c72cc54f4c8e7199e851ea8f5e6c6730f03ed7ed44fc8beefa959dd15911f2647dee47c615ff4faeddb1ad + checksum: aa4ff2a8a728d9d698ed521e3461a109a1e66202b13d3494e41eea30729a5e7cc03b3a2d56c594423a135429c37bf63a9fa8b0b9ce275298be3095a88c69f6fb languageName: node linkType: hard @@ -4816,9 +4649,9 @@ __metadata: linkType: hard "basic-ftp@npm:^5.0.2": - version: 5.0.3 - resolution: "basic-ftp@npm:5.0.3" - checksum: 8b04e88eb85a64de9311721bb0707c9cd70453eefdd854cab85438e6f46fb6c597ddad57ed1acf0a9ede3c677b14e657f51051688a5f23d6f3ea7b5d9073b850 + version: 5.0.4 + resolution: "basic-ftp@npm:5.0.4" + checksum: 57725f24debd8c1b36f9bad1bfee39c5d9f5997f32a23e5c957389dcc64373a13b41711e5723b4a3b616a93530b345686119f480c27a115b2fde944c1652ceb1 languageName: node linkType: hard @@ -4832,13 +4665,6 @@ __metadata: languageName: node linkType: hard -"big-integer@npm:^1.6.44": - version: 1.6.51 - resolution: "big-integer@npm:1.6.51" - checksum: 3d444173d1b2e20747e2c175568bedeebd8315b0637ea95d75fd27830d3b8e8ba36c6af40374f36bdaea7b5de376dcada1b07587cb2a79a928fccdb6e6e3c518 - languageName: node - linkType: hard - "bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -4857,22 +4683,13 @@ __metadata: languageName: node linkType: hard -"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1, bn.js@npm:^5.2.1": +"bn.js@npm:^5.0.0, bn.js@npm:^5.2.1": version: 5.2.1 resolution: "bn.js@npm:5.2.1" checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 languageName: node linkType: hard -"bplist-parser@npm:^0.2.0": - version: 0.2.0 - resolution: "bplist-parser@npm:0.2.0" - dependencies: - big-integer: ^1.6.44 - checksum: d5339dd16afc51de6c88f88f58a45b72ed6a06aa31f5557d09877575f220b7c1d3fbe375da0b62e6a10d4b8ed80523567e351f24014f5bc886ad523758142cdd - languageName: node - linkType: hard - "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -4945,7 +4762,7 @@ __metadata: languageName: node linkType: hard -"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.0.1": +"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.1.0": version: 4.1.0 resolution: "browserify-rsa@npm:4.1.0" dependencies: @@ -4956,33 +4773,33 @@ __metadata: linkType: hard "browserify-sign@npm:^4.0.0": - version: 4.2.1 - resolution: "browserify-sign@npm:4.2.1" + version: 4.2.2 + resolution: "browserify-sign@npm:4.2.2" dependencies: - bn.js: ^5.1.1 - browserify-rsa: ^4.0.1 + bn.js: ^5.2.1 + browserify-rsa: ^4.1.0 create-hash: ^1.2.0 create-hmac: ^1.1.7 - elliptic: ^6.5.3 + elliptic: ^6.5.4 inherits: ^2.0.4 - parse-asn1: ^5.1.5 - readable-stream: ^3.6.0 - safe-buffer: ^5.2.0 - checksum: 0221f190e3f5b2d40183fa51621be7e838d9caa329fe1ba773406b7637855f37b30f5d83e52ff8f244ed12ffe6278dd9983638609ed88c841ce547e603855707 + parse-asn1: ^5.1.6 + readable-stream: ^3.6.2 + safe-buffer: ^5.2.1 + checksum: b622730c0fc183328c3a1c9fdaaaa5118821ed6822b266fa6b0375db7e20061ebec87301d61931d79b9da9a96ada1cab317fce3c68f233e5e93ed02dbb35544c languageName: node linkType: hard -"browserslist@npm:^4.14.5, browserslist@npm:^4.21.9": - version: 4.21.10 - resolution: "browserslist@npm:4.21.10" +"browserslist@npm:^4.21.10, browserslist@npm:^4.22.2": + version: 4.22.2 + resolution: "browserslist@npm:4.22.2" dependencies: - caniuse-lite: ^1.0.30001517 - electron-to-chromium: ^1.4.477 - node-releases: ^2.0.13 - update-browserslist-db: ^1.0.11 + caniuse-lite: ^1.0.30001565 + electron-to-chromium: ^1.4.601 + node-releases: ^2.0.14 + update-browserslist-db: ^1.0.13 bin: browserslist: cli.js - checksum: 1e27c0f111a35d1dd0e8fc2c61781b0daefabc2c9471b0b10537ce54843014bceb2a1ce4571af1a82b2bf1e6e6e05d38865916689a158f03bc2c7a4ec2577db8 + checksum: 33ddfcd9145220099a7a1ac533cecfe5b7548ffeb29b313e1b57be6459000a1f8fa67e781cf4abee97268ac594d44134fcc4a6b2b4750ceddc9796e3a22076d9 languageName: node linkType: hard @@ -5045,33 +4862,6 @@ __metadata: languageName: node linkType: hard -"bundle-name@npm:^3.0.0": - version: 3.0.0 - resolution: "bundle-name@npm:3.0.0" - dependencies: - run-applescript: ^5.0.0 - checksum: edf2b1fbe6096ed32e7566947ace2ea937ee427391744d7510a2880c4b9a5b3543d3f6c551236a29e5c87d3195f8e2912516290e638c15bcbede7b37cc375615 - languageName: node - linkType: hard - -"busboy@npm:^1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" - dependencies: - streamsearch: ^1.1.0 - checksum: 32801e2c0164e12106bf236291a00795c3c4e4b709ae02132883fe8478ba2ae23743b11c5735a0aae8afe65ac4b6ca4568b91f0d9fed1fdbc32ede824a73746e - languageName: node - linkType: hard - -"byte-access@npm:^1.0.0, byte-access@npm:^1.0.1": - version: 1.0.1 - resolution: "byte-access@npm:1.0.1" - dependencies: - uint8arraylist: ^2.0.0 - checksum: 12d5350d9fa6108da80844f5b8c6c80f54bc037cc90f914d81e3a27e374d6c5aac1ba875a8dc2da6b00c6d65c1726bde83a7d57914746cd6d52ff9939a5b21fa - languageName: node - linkType: hard - "bytes@npm:3.1.2, bytes@npm:^3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -5079,23 +4869,23 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^17.0.0": - version: 17.1.3 - resolution: "cacache@npm:17.1.3" +"cacache@npm:^18.0.0": + version: 18.0.2 + resolution: "cacache@npm:18.0.2" dependencies: "@npmcli/fs": ^3.1.0 fs-minipass: ^3.0.0 glob: ^10.2.2 - lru-cache: ^7.7.1 - minipass: ^5.0.0 - minipass-collect: ^1.0.2 + lru-cache: ^10.0.1 + minipass: ^7.0.3 + minipass-collect: ^2.0.1 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 p-map: ^4.0.0 ssri: ^10.0.0 tar: ^6.1.11 unique-filename: ^3.0.0 - checksum: 385756781e1e21af089160d89d7462b7ed9883c978e848c7075b90b73cb823680e66092d61513050164588387d2ca87dd6d910e28d64bc13a9ac82cd8580c796 + checksum: 0250df80e1ad0c828c956744850c5f742c24244e9deb5b7dc81bca90f8c10e011e132ecc58b64497cc1cad9a98968676147fb6575f4f94722f7619757b17a11b languageName: node linkType: hard @@ -5109,13 +4899,14 @@ __metadata: languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" +"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.4, call-bind@npm:^1.0.5": + version: 1.0.5 + resolution: "call-bind@npm:1.0.5" dependencies: - function-bind: ^1.1.1 - get-intrinsic: ^1.0.2 - checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 + function-bind: ^1.1.2 + get-intrinsic: ^1.2.1 + set-function-length: ^1.1.1 + checksum: 449e83ecbd4ba48e7eaac5af26fea3b50f8f6072202c2dd7c5a6e7a6308f2421abe5e13a3bbd55221087f76320c5e09f25a8fdad1bab2b77c68ae74d92234ea5 languageName: node linkType: hard @@ -5151,10 +4942,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001517": - version: 1.0.30001518 - resolution: "caniuse-lite@npm:1.0.30001518" - checksum: 1b63272f6e3d628ac52e2547e0b75fc477004d4b19b63e34b2c045de7f2e48909f9ea513978fc5a46c4ab5ac6c9daf9cc5e6a78466e90684fb824c3f2105e8f5 +"caniuse-lite@npm:^1.0.30001565": + version: 1.0.30001580 + resolution: "caniuse-lite@npm:1.0.30001580" + checksum: 8d287d1e2a64348365f55562457b52afc8c5e0e8ddf040e18e53395ca165241a697205611dc209dace5c7f7d1d3ee8d566672cce6f9668d658d7930b7a200875 languageName: node linkType: hard @@ -5165,7 +4956,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0": +"chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -5207,22 +4998,22 @@ __metadata: languageName: node linkType: hard -"chromium-bidi@npm:0.4.28": - version: 0.4.28 - resolution: "chromium-bidi@npm:0.4.28" +"chromium-bidi@npm:0.5.4": + version: 0.5.4 + resolution: "chromium-bidi@npm:0.5.4" dependencies: mitt: 3.0.1 urlpattern-polyfill: 9.0.0 peerDependencies: devtools-protocol: "*" - checksum: d8ac0aefcf11ebd744e0b97ecded9dac5c03ab55f46267570cdf1b780ad1e05e8cf6987b65178bda99a1ef1ea1bc59721bda85008283ca5f145912b9e1bf578d + checksum: ac256ae94a9f792a220303379c81a7cff49f5aedd07dd0fcd0cd28c79b204a468ef26a9ef6fa9132d65a477ee624fff6372bebdd51b88cb4e7c7ad2275fb9b77 languageName: node linkType: hard "ci-info@npm:^3.2.0": - version: 3.8.0 - resolution: "ci-info@npm:3.8.0" - checksum: d0a4d3160497cae54294974a7246202244fff031b0a6ea20dd57b10ec510aa17399c41a1b0982142c105f3255aff2173e5c0dd7302ee1b2f28ba3debda375098 + version: 3.9.0 + resolution: "ci-info@npm:3.9.0" + checksum: 6b19dc9b2966d1f8c2041a838217299718f15d6c4b63ae36e4674edd2bee48f780e94761286a56aa59eb305a85fbea4ddffb7630ec063e7ec7e7e5ad42549a87 languageName: node linkType: hard @@ -5260,9 +5051,9 @@ __metadata: linkType: hard "cli-spinners@npm:^2.5.0": - version: 2.9.1 - resolution: "cli-spinners@npm:2.9.1" - checksum: 1780618be58309c469205bc315db697934bac68bce78cd5dfd46248e507a533172d623c7348ecfd904734f597ce0a4e5538684843d2cfb7af485d4466699940c + version: 2.9.2 + resolution: "cli-spinners@npm:2.9.2" + checksum: 1bd588289b28432e4676cb5d40505cfe3e53f2e4e10fbe05c8a710a154d6fe0ce7836844b00d6858f740f2ffe67cdc36e0fce9c7b6a8430e80e6388d5aa4956c languageName: node linkType: hard @@ -5363,15 +5154,6 @@ __metadata: languageName: node linkType: hard -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b - languageName: node - linkType: hard - "color@npm:^3.1.3": version: 3.2.1 resolution: "color@npm:3.2.1" @@ -5422,6 +5204,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^11.1.0": + version: 11.1.0 + resolution: "commander@npm:11.1.0" + checksum: fd1a8557c6b5b622c89ecdfde703242ab7db3b628ea5d1755784c79b8e7cb0d74d65b4a262289b533359cd58e1bfc0bf50245dfbcd2954682a6f367c828b79ef + languageName: node + linkType: hard + "commander@npm:^2.16.0, commander@npm:^2.20.0, commander@npm:^2.20.3, commander@npm:^2.8.1": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -5470,9 +5259,9 @@ __metadata: linkType: hard "component-emitter@npm:^1.3.0": - version: 1.3.0 - resolution: "component-emitter@npm:1.3.0" - checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b + version: 1.3.1 + resolution: "component-emitter@npm:1.3.1" + checksum: 94550aa462c7bd5a61c1bc480e28554aa306066930152d1b1844a0dd3845d4e5db7e261ddec62ae184913b3e59b55a2ad84093b9d3596a8f17c341514d6c483d languageName: node linkType: hard @@ -5513,8 +5302,8 @@ __metadata: linkType: hard "concurrently@npm:^8.0.1": - version: 8.2.0 - resolution: "concurrently@npm:8.2.0" + version: 8.2.2 + resolution: "concurrently@npm:8.2.2" dependencies: chalk: ^4.1.2 date-fns: ^2.30.0 @@ -5528,14 +5317,7 @@ __metadata: bin: conc: dist/bin/concurrently.js concurrently: dist/bin/concurrently.js - checksum: eafe6a4d9b7fda87f55ea285cfc6acd937a5286ceec8991ab48e6cc27c45fce6a5c6f45e18d7555defa15dc7d7e8941bc5a9d1ceaf182e31441d420e00333434 - languageName: node - linkType: hard - -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed + checksum: 8ac774df06869773438f1bf91025180c52d5b53139bc86cf47659136c0d97461d0579c515d848d1e945d4e3e0cafe646b2ea18af8d74259b46abddcfe39b2c6c languageName: node linkType: hard @@ -5562,13 +5344,6 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": - version: 1.9.0 - resolution: "convert-source-map@npm:1.9.0" - checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 - languageName: node - linkType: hard - "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -5590,13 +5365,13 @@ __metadata: languageName: node linkType: hard -"cookies@npm:~0.8.0": - version: 0.8.0 - resolution: "cookies@npm:0.8.0" +"cookies@npm:~0.9.0": + version: 0.9.1 + resolution: "cookies@npm:0.9.1" dependencies: depd: ~2.0.0 keygrip: ~1.1.0 - checksum: 806055a44f128705265b1bc6a853058da18bf80dea3654ad99be20985b1fa1b14f86c1eef73644aab8071241f8a78acd57202b54c4c5c70769fc694fbb9c4edc + checksum: 213e4d14847b582fbd8a003203d3621a4b9fa792a315c37954e89332d38fac5bcc34ba92ef316ad6d5fe28f0187aaa115927fbbe2080744ad1707a93b4313247 languageName: node linkType: hard @@ -5614,20 +5389,20 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:8.3.6": - version: 8.3.6 - resolution: "cosmiconfig@npm:8.3.6" +"cosmiconfig@npm:9.0.0": + version: 9.0.0 + resolution: "cosmiconfig@npm:9.0.0" dependencies: + env-paths: ^2.2.1 import-fresh: ^3.3.0 js-yaml: ^4.1.0 parse-json: ^5.2.0 - path-type: ^4.0.0 peerDependencies: typescript: ">=4.9.5" peerDependenciesMeta: typescript: optional: true - checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0 + checksum: a30c424b53d442ea0bdd24cb1b3d0d8687c8dda4a17ab6afcdc439f8964438801619cdb66e8e79f63b9caa3e6586b60d8bab9ce203e72df6c5e80179b971fe8f languageName: node linkType: hard @@ -5668,6 +5443,23 @@ __metadata: languageName: node linkType: hard +"create-jest@npm:^29.7.0": + version: 29.7.0 + resolution: "create-jest@npm:29.7.0" + dependencies: + "@jest/types": ^29.6.3 + chalk: ^4.0.0 + exit: ^0.1.2 + graceful-fs: ^4.2.9 + jest-config: ^29.7.0 + jest-util: ^29.7.0 + prompts: ^2.0.1 + bin: + create-jest: bin/create-jest.js + checksum: 1427d49458adcd88547ef6fa39041e1fe9033a661293aa8d2c3aa1b4967cb5bf4f0c00436c7a61816558f28ba2ba81a94d5c962e8022ea9a883978fc8e1f2945 + languageName: node + linkType: hard + "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -5721,31 +5513,31 @@ __metadata: languageName: node linkType: hard -"data-uri-to-buffer@npm:^5.0.1": - version: 5.0.1 - resolution: "data-uri-to-buffer@npm:5.0.1" - checksum: 10958f89c0047b84bd86d572b6b77c9bf238ebe7b55a9a9ab04c90fbf5ab1881783b72e31dc0febdffd30ec914930244f2f728e3629bb8911d922baba129426f +"data-uri-to-buffer@npm:^6.0.0": + version: 6.0.1 + resolution: "data-uri-to-buffer@npm:6.0.1" + checksum: 9140e68c585ae33d950f5943bd476751346c8b789ae80b01a578a33cb8f7f706d1ca7378aff2b1878b2a6d9a8c88c55cc286d88191c8b8ead8255c3c4d934530 languageName: node linkType: hard "datastore-core@npm:^9.0.1": - version: 9.2.0 - resolution: "datastore-core@npm:9.2.0" + version: 9.2.7 + resolution: "datastore-core@npm:9.2.7" dependencies: - "@libp2p/logger": ^2.0.0 + "@libp2p/logger": ^4.0.1 err-code: ^3.0.1 interface-store: ^5.0.0 it-all: ^3.0.1 it-drain: ^3.0.1 it-filter: ^3.0.0 it-map: ^3.0.1 - it-merge: ^3.0.0 + it-merge: ^3.0.1 it-pipe: ^3.0.0 it-pushable: ^3.0.0 it-sort: ^3.0.1 it-take: ^3.0.1 - uint8arrays: ^4.0.2 - checksum: f955cdea823e3e3b9ec0090e7dcfab54b4818156674555e7ca38b0047c98dd42cb14474495cbb3c5e6b721320269354fe0185ea2101f6542fb5149f47d7b2114 + uint8arrays: ^5.0.0 + checksum: 593f40d8e5ccbc80b073b4ec1553e70bc061d4656ca238c10eb47d799ff8a137f19698268b0639cc5a26cf5e036f72946dad0bd20cd37e57f713c9d7a1b32a67 languageName: node linkType: hard @@ -5836,34 +5628,12 @@ __metadata: languageName: node linkType: hard -"default-browser-id@npm:^3.0.0": - version: 3.0.0 - resolution: "default-browser-id@npm:3.0.0" - dependencies: - bplist-parser: ^0.2.0 - untildify: ^4.0.0 - checksum: 279c7ad492542e5556336b6c254a4eaf31b2c63a5433265655ae6e47301197b6cfb15c595a6fdc6463b2ff8e1a1a1ed3cba56038a60e1527ba4ab1628c6b9941 - languageName: node - linkType: hard - -"default-browser@npm:^4.0.0": - version: 4.0.0 - resolution: "default-browser@npm:4.0.0" +"default-gateway@npm:^7.2.2": + version: 7.2.2 + resolution: "default-gateway@npm:7.2.2" dependencies: - bundle-name: ^3.0.0 - default-browser-id: ^3.0.0 execa: ^7.1.1 - titleize: ^3.0.0 - checksum: 40c5af984799042b140300be5639c9742599bda76dc9eba5ac9ad5943c83dd36cebc4471eafcfddf8e0ec817166d5ba89d56f08e66a126c7c7908a179cead1a7 - languageName: node - linkType: hard - -"default-gateway@npm:^6.0.2": - version: 6.0.3 - resolution: "default-gateway@npm:6.0.3" - dependencies: - execa: ^5.0.0 - checksum: 126f8273ecac8ee9ff91ea778e8784f6cd732d77c3157e8c5bdd6ed03651b5291f71446d05bc02d04073b1e67583604db5394ea3cf992ede0088c70ea15b7378 + checksum: eec8a2a338677322bcdbf339bbdede61225f6145eedd0c3d4948deadfc929dc0e04b153b33674873d36efa403f76649aaacbfc728a438ee9f538a28723515478 languageName: node linkType: hard @@ -5886,20 +5656,25 @@ __metadata: languageName: node linkType: hard -"define-lazy-prop@npm:^3.0.0": - version: 3.0.0 - resolution: "define-lazy-prop@npm:3.0.0" - checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.1": + version: 1.1.1 + resolution: "define-data-property@npm:1.1.1" + dependencies: + get-intrinsic: ^1.2.1 + gopd: ^1.0.1 + has-property-descriptors: ^1.0.0 + checksum: a29855ad3f0630ea82e3c5012c812efa6ca3078d5c2aa8df06b5f597c1cde6f7254692df41945851d903e05a1668607b6d34e778f402b9ff9ffb38111f1a3f0d languageName: node linkType: hard -"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0": - version: 1.2.0 - resolution: "define-properties@npm:1.2.0" +"define-properties@npm:^1.1.3, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" dependencies: + define-data-property: ^1.0.1 has-property-descriptors: ^1.0.0 object-keys: ^1.1.1 - checksum: e60aee6a19b102df4e2b1f301816804e81ab48bb91f00d0d935f269bf4b3f79c88b39e4f89eaa132890d23267335fd1140dfcd8d5ccd61031a0a2c41a54e33a6 + checksum: b4ccd00597dd46cb2d4a379398f5b19fca84a16f3374e2249201992f36b30f6835949a9429669ee6b41b6e837205a163eadd745e472069e70dfc10f03e5fcc12 languageName: node linkType: hard @@ -6187,10 +5962,10 @@ __metadata: languageName: node linkType: hard -"devtools-protocol@npm:0.0.1179426": - version: 0.0.1179426 - resolution: "devtools-protocol@npm:0.0.1179426" - checksum: 38a091bde42d7d0f8e5e6c7a445db6a56d7b80f21f51de47ed1316123f70b2256aa6fe0d87fbe37bcc4928c0b9245e28a17fb7fbf8d8622156ae36870b26c1ed +"devtools-protocol@npm:0.0.1232444": + version: 0.0.1232444 + resolution: "devtools-protocol@npm:0.0.1232444" + checksum: b421a3c20506d597211d101c3ed4e550db2ca195d59c3371b2e04a8d057f33be60e732bafc80dc53b34546593a7751857321971e235e9ce9f1c5a9523fd8fa20 languageName: node linkType: hard @@ -6204,10 +5979,10 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^29.4.3": - version: 29.4.3 - resolution: "diff-sequences@npm:29.4.3" - checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 +"diff-sequences@npm:^29.6.3": + version: 29.6.3 + resolution: "diff-sequences@npm:29.6.3" + checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa languageName: node linkType: hard @@ -6238,15 +6013,13 @@ __metadata: languageName: node linkType: hard -"dns-over-http-resolver@npm:^2.1.0": - version: 2.1.1 - resolution: "dns-over-http-resolver@npm:2.1.1" +"dns-over-http-resolver@npm:^3.0.2": + version: 3.0.2 + resolution: "dns-over-http-resolver@npm:3.0.2" dependencies: - debug: ^4.3.1 - native-fetch: ^4.0.2 + debug: ^4.3.4 receptacle: ^1.3.2 - undici: ^5.12.0 - checksum: 153a0f4ef705cd08c9b0c163d654988dbb087eabe44c8ab243481c108af97b52ec6343b7127ed1a6a5705a497e8dc06cd1e6c33fbe5aae3a08e357c1e93fc93e + checksum: 782739450bae3329fdbafcb3c53b497eeb0b3af3bdd8de91977a513d4fe797446597a09d6e042a2c5da99cfc0039c4acac8a7efb93aca5b3424b58f4174d4a4f languageName: node linkType: hard @@ -6269,9 +6042,9 @@ __metadata: linkType: hard "dotenv@npm:^16.0.3": - version: 16.3.1 - resolution: "dotenv@npm:16.3.1" - checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd + version: 16.4.1 + resolution: "dotenv@npm:16.4.1" + checksum: a343f0a1d156deef8c60034f797969867af4dbccfacedd4ac15fad04547e7ffe0553b58fc3b27a5837950f0d977e38e9234943fbcec4aeced4e3d044309a76ab languageName: node linkType: hard @@ -6296,10 +6069,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.477": - version: 1.4.480 - resolution: "electron-to-chromium@npm:1.4.480" - checksum: 074b9d81dffa6ca182f604326c62a12d22139ae141d6ffabdb3b267f42fac88ba3e69d3614f9e939f65a0f03a343f0c81f702e24064bc54c4f138e02378b1e54 +"electron-to-chromium@npm:^1.4.601": + version: 1.4.647 + resolution: "electron-to-chromium@npm:1.4.647" + checksum: fd79098e08a03025fb64a0608dd20942a7004bb38a8c7fd6d18d8b1767712866a3dae2df7e69ddbc7c627352278cbd07ce1a7368b6c037129e68a042802e108c languageName: node linkType: hard @@ -6381,7 +6154,7 @@ __metadata: languageName: node linkType: hard -"env-paths@npm:^2.2.0": +"env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e @@ -6389,11 +6162,11 @@ __metadata: linkType: hard "envinfo@npm:^7.7.3": - version: 7.10.0 - resolution: "envinfo@npm:7.10.0" + version: 7.11.0 + resolution: "envinfo@npm:7.11.0" bin: envinfo: dist/cli.js - checksum: 05e81a5768c42cbd5c580dc3f274db3401facadd53e9bd52e2aa49dfbb5d8b26f6181c25a6652d79618a6994185bd2b1c137673101690b147f758e4e71d42f7d + checksum: c45a7d20409d5f4cda72483b150d3816b15b434f2944d72c1495d8838bd7c4e7b2f32c12128ffb9b92b5f66f436237b8a525eb3a9a5da2d20013bc4effa28aef languageName: node linkType: hard @@ -6420,25 +6193,25 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2": - version: 1.22.1 - resolution: "es-abstract@npm:1.22.1" +"es-abstract@npm:^1.22.1": + version: 1.22.3 + resolution: "es-abstract@npm:1.22.3" dependencies: array-buffer-byte-length: ^1.0.0 - arraybuffer.prototype.slice: ^1.0.1 + arraybuffer.prototype.slice: ^1.0.2 available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 + call-bind: ^1.0.5 es-set-tostringtag: ^2.0.1 es-to-primitive: ^1.2.1 - function.prototype.name: ^1.1.5 - get-intrinsic: ^1.2.1 + function.prototype.name: ^1.1.6 + get-intrinsic: ^1.2.2 get-symbol-description: ^1.0.0 globalthis: ^1.0.3 gopd: ^1.0.1 - has: ^1.0.3 has-property-descriptors: ^1.0.0 has-proto: ^1.0.1 has-symbols: ^1.0.3 + hasown: ^2.0.0 internal-slot: ^1.0.5 is-array-buffer: ^3.0.2 is-callable: ^1.2.7 @@ -6446,51 +6219,51 @@ __metadata: is-regex: ^1.1.4 is-shared-array-buffer: ^1.0.2 is-string: ^1.0.7 - is-typed-array: ^1.1.10 + is-typed-array: ^1.1.12 is-weakref: ^1.0.2 - object-inspect: ^1.12.3 + object-inspect: ^1.13.1 object-keys: ^1.1.1 object.assign: ^4.1.4 - regexp.prototype.flags: ^1.5.0 - safe-array-concat: ^1.0.0 + regexp.prototype.flags: ^1.5.1 + safe-array-concat: ^1.0.1 safe-regex-test: ^1.0.0 - string.prototype.trim: ^1.2.7 - string.prototype.trimend: ^1.0.6 - string.prototype.trimstart: ^1.0.6 + string.prototype.trim: ^1.2.8 + string.prototype.trimend: ^1.0.7 + string.prototype.trimstart: ^1.0.7 typed-array-buffer: ^1.0.0 typed-array-byte-length: ^1.0.0 typed-array-byte-offset: ^1.0.0 typed-array-length: ^1.0.4 unbox-primitive: ^1.0.2 - which-typed-array: ^1.1.10 - checksum: 614e2c1c3717cb8d30b6128ef12ea110e06fd7d75ad77091ca1c5dbfb00da130e62e4bbbbbdda190eada098a22b27fe0f99ae5a1171dac2c8663b1e8be8a3a9b + which-typed-array: ^1.1.13 + checksum: b1bdc962856836f6e72be10b58dc128282bdf33771c7a38ae90419d920fc3b36cc5d2b70a222ad8016e3fc322c367bf4e9e89fc2bc79b7e933c05b218e83d79a languageName: node linkType: hard "es-module-lexer@npm:^1.2.1": - version: 1.3.0 - resolution: "es-module-lexer@npm:1.3.0" - checksum: 48fd9f504a9d2a894126f75c8b7ccc6273a289983e9b67255f165bfd9ae765d50100218251e94e702ca567826905ea2f7b3b4a0c4d74d3ce99cce3a2a606a238 + version: 1.4.1 + resolution: "es-module-lexer@npm:1.4.1" + checksum: a11b5a256d4e8e9c7d94c2fd87415ccd1591617b6edd847e064503f8eaece2d25e2e9078a02c5ce3ed5e83bb748f5b4820efbe78072c8beb07ac619c2edec35d languageName: node linkType: hard "es-set-tostringtag@npm:^2.0.1": - version: 2.0.1 - resolution: "es-set-tostringtag@npm:2.0.1" + version: 2.0.2 + resolution: "es-set-tostringtag@npm:2.0.2" dependencies: - get-intrinsic: ^1.1.3 - has: ^1.0.3 + get-intrinsic: ^1.2.2 has-tostringtag: ^1.0.0 - checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 + hasown: ^2.0.0 + checksum: afcec3a4c9890ae14d7ec606204858441c801ff84f312538e1d1ccf1e5493c8b17bd672235df785f803756472cb4f2d49b87bde5237aef33411e74c22f194e07 languageName: node linkType: hard "es-shim-unscopables@npm:^1.0.0": - version: 1.0.0 - resolution: "es-shim-unscopables@npm:1.0.0" + version: 1.0.2 + resolution: "es-shim-unscopables@npm:1.0.2" dependencies: - has: ^1.0.3 - checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 + hasown: ^2.0.0 + checksum: 432bd527c62065da09ed1d37a3f8e623c423683285e6188108286f4a1e8e164a5bcbfbc0051557c7d14633cd2a41ce24c7048e6bbb66a985413fd32f1be72626 languageName: node linkType: hard @@ -6506,31 +6279,31 @@ __metadata: linkType: hard "esbuild@npm:^0.18.10": - version: 0.18.17 - resolution: "esbuild@npm:0.18.17" - dependencies: - "@esbuild/android-arm": 0.18.17 - "@esbuild/android-arm64": 0.18.17 - "@esbuild/android-x64": 0.18.17 - "@esbuild/darwin-arm64": 0.18.17 - "@esbuild/darwin-x64": 0.18.17 - "@esbuild/freebsd-arm64": 0.18.17 - "@esbuild/freebsd-x64": 0.18.17 - "@esbuild/linux-arm": 0.18.17 - "@esbuild/linux-arm64": 0.18.17 - "@esbuild/linux-ia32": 0.18.17 - "@esbuild/linux-loong64": 0.18.17 - "@esbuild/linux-mips64el": 0.18.17 - "@esbuild/linux-ppc64": 0.18.17 - "@esbuild/linux-riscv64": 0.18.17 - "@esbuild/linux-s390x": 0.18.17 - "@esbuild/linux-x64": 0.18.17 - "@esbuild/netbsd-x64": 0.18.17 - "@esbuild/openbsd-x64": 0.18.17 - "@esbuild/sunos-x64": 0.18.17 - "@esbuild/win32-arm64": 0.18.17 - "@esbuild/win32-ia32": 0.18.17 - "@esbuild/win32-x64": 0.18.17 + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" + dependencies: + "@esbuild/android-arm": 0.18.20 + "@esbuild/android-arm64": 0.18.20 + "@esbuild/android-x64": 0.18.20 + "@esbuild/darwin-arm64": 0.18.20 + "@esbuild/darwin-x64": 0.18.20 + "@esbuild/freebsd-arm64": 0.18.20 + "@esbuild/freebsd-x64": 0.18.20 + "@esbuild/linux-arm": 0.18.20 + "@esbuild/linux-arm64": 0.18.20 + "@esbuild/linux-ia32": 0.18.20 + "@esbuild/linux-loong64": 0.18.20 + "@esbuild/linux-mips64el": 0.18.20 + "@esbuild/linux-ppc64": 0.18.20 + "@esbuild/linux-riscv64": 0.18.20 + "@esbuild/linux-s390x": 0.18.20 + "@esbuild/linux-x64": 0.18.20 + "@esbuild/netbsd-x64": 0.18.20 + "@esbuild/openbsd-x64": 0.18.20 + "@esbuild/sunos-x64": 0.18.20 + "@esbuild/win32-arm64": 0.18.20 + "@esbuild/win32-ia32": 0.18.20 + "@esbuild/win32-x64": 0.18.20 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -6578,7 +6351,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: c6e1ffa776978a45697763a07ec9b16411db3d3b3997b2c4a0165a211727fce8b63b87165a28d8ef60d3a28b98197bbbc2833e51b89888a4437e0a483dffc8ff + checksum: 5d253614e50cdb6ec22095afd0c414f15688e7278a7eb4f3720a6dd1306b0909cf431e7b9437a90d065a31b1c57be60130f63fe3e8d0083b588571f31ee6ec7b languageName: node linkType: hard @@ -6636,43 +6409,42 @@ __metadata: linkType: hard "eslint-config-prettier@npm:^8.5.0": - version: 8.9.0 - resolution: "eslint-config-prettier@npm:8.9.0" + version: 8.10.0 + resolution: "eslint-config-prettier@npm:8.10.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: a675d0dabd76b700ef2d062b5ec6a634e105a8e8c070f95281fd2ccb614527fac60b4c758132058c50f0521fd19313f1f5be45ce9ebf081f2e5f77ae6eb7d8db + checksum: 153266badd477e49b0759816246b2132f1dbdb6c7f313ca60a9af5822fd1071c2bc5684a3720d78b725452bbac04bb130878b2513aea5e72b1b792de5a69fec8 languageName: node linkType: hard -"eslint-import-resolver-node@npm:^0.3.7": - version: 0.3.7 - resolution: "eslint-import-resolver-node@npm:0.3.7" +"eslint-import-resolver-node@npm:^0.3.9": + version: 0.3.9 + resolution: "eslint-import-resolver-node@npm:0.3.9" dependencies: debug: ^3.2.7 - is-core-module: ^2.11.0 - resolve: ^1.22.1 - checksum: 3379aacf1d2c6952c1b9666c6fa5982c3023df695430b0d391c0029f6403a7775414873d90f397e98ba6245372b6c8960e16e74d9e4a3b0c0a4582f3bdbe3d6e + is-core-module: ^2.13.0 + resolve: ^1.22.4 + checksum: 439b91271236b452d478d0522a44482e8c8540bf9df9bd744062ebb89ab45727a3acd03366a6ba2bdbcde8f9f718bab7fe8db64688aca75acf37e04eafd25e22 languageName: node linkType: hard "eslint-import-resolver-typescript@npm:^3.5.5": - version: 3.5.5 - resolution: "eslint-import-resolver-typescript@npm:3.5.5" + version: 3.6.1 + resolution: "eslint-import-resolver-typescript@npm:3.6.1" dependencies: debug: ^4.3.4 enhanced-resolve: ^5.12.0 eslint-module-utils: ^2.7.4 + fast-glob: ^3.3.1 get-tsconfig: ^4.5.0 - globby: ^13.1.3 is-core-module: ^2.11.0 is-glob: ^4.0.3 - synckit: ^0.8.5 peerDependencies: eslint: "*" eslint-plugin-import: "*" - checksum: 27e6276fdff5d377c9036362ff736ac29852106e883ff589ea9092dc57d4bc2a67a82d75134221124f05045f9a7e2114a159b2c827d1f9f64d091f7afeab0f58 + checksum: 454fa0646533050fb57f13d27daf8c71f51b0bb9156d6a461290ccb8576d892209fcc6702a89553f3f5ea8e5b407395ca2e5de169a952c953685f1f7c46b4496 languageName: node linkType: hard @@ -6689,30 +6461,29 @@ __metadata: linkType: hard "eslint-plugin-import@npm:^2.27.5": - version: 2.28.0 - resolution: "eslint-plugin-import@npm:2.28.0" + version: 2.29.1 + resolution: "eslint-plugin-import@npm:2.29.1" dependencies: - array-includes: ^3.1.6 - array.prototype.findlastindex: ^1.2.2 - array.prototype.flat: ^1.3.1 - array.prototype.flatmap: ^1.3.1 + array-includes: ^3.1.7 + array.prototype.findlastindex: ^1.2.3 + array.prototype.flat: ^1.3.2 + array.prototype.flatmap: ^1.3.2 debug: ^3.2.7 doctrine: ^2.1.0 - eslint-import-resolver-node: ^0.3.7 + eslint-import-resolver-node: ^0.3.9 eslint-module-utils: ^2.8.0 - has: ^1.0.3 - is-core-module: ^2.12.1 + hasown: ^2.0.0 + is-core-module: ^2.13.1 is-glob: ^4.0.3 minimatch: ^3.1.2 - object.fromentries: ^2.0.6 - object.groupby: ^1.0.0 - object.values: ^1.1.6 - resolve: ^1.22.3 + object.fromentries: ^2.0.7 + object.groupby: ^1.0.1 + object.values: ^1.1.7 semver: ^6.3.1 - tsconfig-paths: ^3.14.2 + tsconfig-paths: ^3.15.0 peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: f9eba311b93ca1bb89311856b1f7285bd79e0181d7eb70fe115053ff77e2235fea749b30f538b78927dc65769340b5be61f4c9581d1c82bcdcccb2061f440ad1 + checksum: e65159aef808136d26d029b71c8c6e4cb5c628e65e5de77f1eb4c13a379315ae55c9c3afa847f43f4ff9df7e54515c77ffc6489c6a6f81f7dd7359267577468c languageName: node linkType: hard @@ -6777,24 +6548,25 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.2": - version: 3.4.2 - resolution: "eslint-visitor-keys@npm:3.4.2" - checksum: 9e0e7e4aaea705c097ae37c97410e5f167d4d2193be2edcb1f0760762ede3df01545e4820ae314f42dcec687745f2c6dcaf6d83575c4a2a241eb0c8517d724f2 +"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 languageName: node linkType: hard "eslint@npm:^8.21.0, eslint@npm:^8.35.0, eslint@npm:^8.37.0": - version: 8.46.0 - resolution: "eslint@npm:8.46.0" + version: 8.56.0 + resolution: "eslint@npm:8.56.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.6.1 - "@eslint/eslintrc": ^2.1.1 - "@eslint/js": ^8.46.0 - "@humanwhocodes/config-array": ^0.11.10 + "@eslint/eslintrc": ^2.1.4 + "@eslint/js": 8.56.0 + "@humanwhocodes/config-array": ^0.11.13 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 + "@ungap/structured-clone": ^1.2.0 ajv: ^6.12.4 chalk: ^4.0.0 cross-spawn: ^7.0.2 @@ -6802,7 +6574,7 @@ __metadata: doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 eslint-scope: ^7.2.2 - eslint-visitor-keys: ^3.4.2 + eslint-visitor-keys: ^3.4.3 espree: ^9.6.1 esquery: ^1.4.2 esutils: ^2.0.2 @@ -6827,7 +6599,7 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 7a7d36b1a3bbc12e08fbb5bc36fd482a7a5a1797e62e762499dd45601b9e45aaa53a129f31ce0b4444551a9639b8b681ad535f379893dd1e3ae37b31dccd82aa + checksum: 883436d1e809b4a25d9eb03d42f584b84c408dbac28b0019f6ea07b5177940bf3cca86208f749a6a1e0039b63e085ee47aca1236c30721e91f0deef5cc5a5136 languageName: node linkType: hard @@ -6913,14 +6685,14 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^4.0.7": - version: 4.0.7 - resolution: "eventemitter3@npm:4.0.7" - checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 +"eventemitter3@npm:^5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 543d6c858ab699303c3c32e0f0f47fc64d360bf73c3daf0ac0b5079710e340d6fe9f15487f94e66c629f5f82cd1a8678d692f3dbb6f6fcd1190e1b97fcad36f8 languageName: node linkType: hard -"events@npm:^3.2.0, events@npm:^3.3.0": +"events@npm:^3.2.0": version: 3.3.0 resolution: "events@npm:3.3.0" checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780 @@ -6979,17 +6751,16 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.0.0, expect@npm:^29.6.2": - version: 29.6.2 - resolution: "expect@npm:29.6.2" +"expect@npm:^29.0.0, expect@npm:^29.7.0": + version: 29.7.0 + resolution: "expect@npm:29.7.0" dependencies: - "@jest/expect-utils": ^29.6.2 - "@types/node": "*" - jest-get-type: ^29.4.3 - jest-matcher-utils: ^29.6.2 - jest-message-util: ^29.6.2 - jest-util: ^29.6.2 - checksum: 71f7b0c560e58bf6d27e0fded261d4bdb7ef81552a6bb4bd1ee09ce7a1f7dca67fbf83cf9b07a6645a88ef52e65085a0dcbe17f6c063b53ff7c2f0f3ea4ef69e + "@jest/expect-utils": ^29.7.0 + jest-get-type: ^29.6.3 + jest-matcher-utils: ^29.7.0 + jest-message-util: ^29.7.0 + jest-util: ^29.7.0 + checksum: 9257f10288e149b81254a0fda8ffe8d54a7061cd61d7515779998b012579d2b8c22354b0eb901daf0145f347403da582f75f359f4810c007182ad3fb318b5c0c languageName: node linkType: hard @@ -7031,16 +6802,16 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": - version: 3.3.1 - resolution: "fast-glob@npm:3.3.1" +"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.1": + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" dependencies: "@nodelib/fs.stat": ^2.0.2 "@nodelib/fs.walk": ^1.2.3 glob-parent: ^5.1.2 merge2: ^1.3.0 micromatch: ^4.0.4 - checksum: b6f3add6403e02cf3a798bfbb1183d0f6da2afd368f27456010c0bc1f9640aea308243d4cb2c0ab142f618276e65ecb8be1661d7c62a7b4e5ba774b9ce5432e5 + checksum: 900e4979f4dbc3313840078419245621259f349950411ca2fa445a2f9a1a6d98c3b5e7e0660c5ccd563aa61abe133a21765c6c0dec8e57da1ba71d8000b05ec1 languageName: node linkType: hard @@ -7073,11 +6844,11 @@ __metadata: linkType: hard "fastq@npm:^1.6.0": - version: 1.15.0 - resolution: "fastq@npm:1.15.0" + version: 1.16.0 + resolution: "fastq@npm:1.16.0" dependencies: reusify: ^1.0.4 - checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a + checksum: 1d40ed1f100ae625e5720484e8602b7ad07649370f1cbc3e34a6b9630a0bfed6946bab0322d8a368a1e3cde87bb9bbb8d3bc2ae01a0c1f022fac1d07c04e4feb languageName: node linkType: hard @@ -7194,19 +6965,29 @@ __metadata: linkType: hard "flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" + version: 3.2.0 + resolution: "flat-cache@npm:3.2.0" dependencies: - flatted: ^3.1.0 + flatted: ^3.2.9 + keyv: ^4.5.3 rimraf: ^3.0.2 - checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 + checksum: e7e0f59801e288b54bee5cb9681e9ee21ee28ef309f886b312c9d08415b79fc0f24ac842f84356ce80f47d6a53de62197ce0e6e148dc42d5db005992e2a756ec languageName: node linkType: hard -"flatted@npm:^3.1.0": - version: 3.2.7 - resolution: "flatted@npm:3.2.7" - checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 +"flat@npm:^5.0.2": + version: 5.0.2 + resolution: "flat@npm:5.0.2" + bin: + flat: cli.js + checksum: 12a1536ac746db74881316a181499a78ef953632ddd28050b7a3a43c62ef5462e3357c8c29d76072bb635f147f7a9a1f0c02efef6b4be28f8db62ceb3d5c7f5d + languageName: node + linkType: hard + +"flatted@npm:^3.2.9": + version: 3.2.9 + resolution: "flatted@npm:3.2.9" + checksum: f14167fbe26a9d20f6fca8d998e8f1f41df72c8e81f9f2c9d61ed2bea058248f5e1cbd05e7f88c0e5087a6a0b822a1e5e2b446e879f3cfbe0b07ba2d7f80b026 languageName: node linkType: hard @@ -7297,13 +7078,13 @@ __metadata: linkType: hard "fs-extra@npm:^11.1.1": - version: 11.1.1 - resolution: "fs-extra@npm:11.1.1" + version: 11.2.0 + resolution: "fs-extra@npm:11.2.0" dependencies: graceful-fs: ^4.2.0 jsonfile: ^6.0.1 universalify: ^2.0.0 - checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + checksum: b12e42fa40ba47104202f57b8480dd098aa931c2724565e5e70779ab87605665594e76ee5fb00545f772ab9ace167fe06d2ab009c416dc8c842c5ae6df7aa7e8 languageName: node linkType: hard @@ -7328,11 +7109,11 @@ __metadata: linkType: hard "fs-minipass@npm:^3.0.0": - version: 3.0.2 - resolution: "fs-minipass@npm:3.0.2" + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" dependencies: - minipass: ^5.0.0 - checksum: e9cc0e1f2d01c6f6f62f567aee59530aba65c6c7b2ae88c5027bc34c711ebcfcfaefd0caf254afa6adfe7d1fba16bc2537508a6235196bac7276747d078aef0a + minipass: ^7.0.3 + checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 languageName: node linkType: hard @@ -7344,28 +7125,21 @@ __metadata: linkType: hard "fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" dependencies: node-gyp: latest - checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f + checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 conditions: os=darwin languageName: node linkType: hard "fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" dependencies: node-gyp: latest - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a + conditions: os=darwin languageName: node linkType: hard @@ -7376,15 +7150,15 @@ __metadata: languageName: node linkType: hard -"function.prototype.name@npm:^1.1.5": - version: 1.1.5 - resolution: "function.prototype.name@npm:1.1.5" +"function.prototype.name@npm:^1.1.6": + version: 1.1.6 + resolution: "function.prototype.name@npm:1.1.6" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.0 - functions-have-names: ^1.2.2 - checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + functions-have-names: ^1.2.3 + checksum: 7a3f9bd98adab09a07f6e1f03da03d3f7c26abbdeaeee15223f6c04a9fb5674792bdf5e689dac19b97ac71de6aad2027ba3048a9b883aa1b3173eed6ab07f479 languageName: node linkType: hard @@ -7395,29 +7169,13 @@ __metadata: languageName: node linkType: hard -"functions-have-names@npm:^1.2.2, functions-have-names@npm:^1.2.3": +"functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 languageName: node linkType: hard -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -7452,15 +7210,15 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1": - version: 1.2.1 - resolution: "get-intrinsic@npm:1.2.1" +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2": + version: 1.2.2 + resolution: "get-intrinsic@npm:1.2.2" dependencies: - function-bind: ^1.1.1 - has: ^1.0.3 + function-bind: ^1.1.2 has-proto: ^1.0.1 has-symbols: ^1.0.3 - checksum: 5b61d88552c24b0cf6fa2d1b3bc5459d7306f699de060d76442cce49a4721f52b8c560a33ab392cf5575b7810277d54ded9d4d39a1ea61855619ebc005aa7e5f + hasown: ^2.0.0 + checksum: 447ff0724df26829908dc033b62732359596fcf66027bc131ab37984afb33842d9cd458fd6cecadfe7eac22fd8a54b349799ed334cf2726025c921c7250e7417 languageName: node linkType: hard @@ -7471,10 +7229,10 @@ __metadata: languageName: node linkType: hard -"get-iterator@npm:^2.0.0": - version: 2.0.0 - resolution: "get-iterator@npm:2.0.0" - checksum: 4ed81e7d100dd0a8dab11bf7dc7f88d8895a03057fa4a56d24190bdfe490fa4da3005d5b88fc6336429b33b423586f40dbcc40ce723f5dea55593cae0e2937de +"get-iterator@npm:^2.0.0, get-iterator@npm:^2.0.1": + version: 2.0.1 + resolution: "get-iterator@npm:2.0.1" + checksum: 353baac51f5e335c19cb734cbf0401d7c47deeac9d375e2939fed646fe52db2912d61ed2a60112050cf4687080817d159ec938803e48e03cd602edd489a116f2 languageName: node linkType: hard @@ -7519,23 +7277,23 @@ __metadata: linkType: hard "get-tsconfig@npm:^4.5.0": - version: 4.6.2 - resolution: "get-tsconfig@npm:4.6.2" + version: 4.7.2 + resolution: "get-tsconfig@npm:4.7.2" dependencies: resolve-pkg-maps: ^1.0.0 - checksum: e791e671a9b55e91efea3ca819ecd7a25beae679e31c83234bf3dd62ddd93df070c1b95ae7e29d206358ebb6408f6f79ac6d83a32a3bbd6a6d217babe23de077 + checksum: 172358903250eff0103943f816e8a4e51d29b8e5449058bdf7266714a908a48239f6884308bd3a6ff28b09f692b9533dbebfd183ab63e4e14f073cda91f1bca9 languageName: node linkType: hard "get-uri@npm:^6.0.1": - version: 6.0.1 - resolution: "get-uri@npm:6.0.1" + version: 6.0.2 + resolution: "get-uri@npm:6.0.2" dependencies: basic-ftp: ^5.0.2 - data-uri-to-buffer: ^5.0.1 + data-uri-to-buffer: ^6.0.0 debug: ^4.3.4 fs-extra: ^8.1.0 - checksum: a8aec70e1c67386fbe67f66e344ecd671a19f4cfc8e0f0e14d070563af5123d540e77fbceb6e26566f29846fac864d2862699ab134d307f85c85e7d72ce23d14 + checksum: 762de3b0e3d4e7afc966e4ce93be587d70c270590da9b4c8fbff888362656c055838d926903d1774cbfeed4d392b4d6def4b2c06d48c050580070426a3a8629b languageName: node linkType: hard @@ -7564,22 +7322,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2": - version: 10.3.3 - resolution: "glob@npm:10.3.3" - dependencies: - foreground-child: ^3.1.0 - jackspeak: ^2.0.3 - minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 - path-scurry: ^1.10.1 - bin: - glob: dist/cjs/src/bin.js - checksum: 29190d3291f422da0cb40b77a72fc8d2c51a36524e99b8bf412548b7676a6627489528b57250429612b6eec2e6fe7826d328451d3e694a9d15e575389308ec53 - languageName: node - linkType: hard - -"glob@npm:^10.3.10": +"glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.3.10 resolution: "glob@npm:10.3.10" dependencies: @@ -7616,11 +7359,11 @@ __metadata: linkType: hard "globals@npm:^13.19.0": - version: 13.20.0 - resolution: "globals@npm:13.20.0" + version: 13.24.0 + resolution: "globals@npm:13.24.0" dependencies: type-fest: ^0.20.2 - checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a + checksum: 56066ef058f6867c04ff203b8a44c15b038346a62efbc3060052a1016be9f56f4cf0b2cd45b74b22b81e521a889fc7786c73691b0549c2f3a6e825b3d394f43c languageName: node linkType: hard @@ -7647,19 +7390,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:^13.1.3": - version: 13.2.2 - resolution: "globby@npm:13.2.2" - dependencies: - dir-glob: ^3.0.1 - fast-glob: ^3.3.0 - ignore: ^5.2.4 - merge2: ^1.4.1 - slash: ^4.0.0 - checksum: f3d84ced58a901b4fcc29c846983108c426631fe47e94872868b65565495f7bee7b3defd68923bd480582771fd4bbe819217803a164a618ad76f1d22f666f41e - languageName: node - linkType: hard - "gonzales-pe@npm:^4.2.3, gonzales-pe@npm:^4.3.0": version: 4.3.0 resolution: "gonzales-pe@npm:4.3.0" @@ -7729,12 +7459,12 @@ __metadata: languageName: node linkType: hard -"has-property-descriptors@npm:^1.0.0": - version: 1.0.0 - resolution: "has-property-descriptors@npm:1.0.0" +"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.1": + version: 1.0.1 + resolution: "has-property-descriptors@npm:1.0.1" dependencies: - get-intrinsic: ^1.1.1 - checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb + get-intrinsic: ^1.2.2 + checksum: 2bcc6bf6ec6af375add4e4b4ef586e43674850a91ad4d46666d0b28ba8e1fd69e424c7677d24d60f69470ad0afaa2f3197f508b20b0bb7dd99a8ab77ffc4b7c4 languageName: node linkType: hard @@ -7761,22 +7491,6 @@ __metadata: languageName: node linkType: hard -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 - languageName: node - linkType: hard - -"has@npm:^1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" - dependencies: - function-bind: ^1.1.1 - checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 - languageName: node - linkType: hard - "hash-base@npm:^3.0.0": version: 3.1.0 resolution: "hash-base@npm:3.1.0" @@ -7901,17 +7615,6 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "http-proxy-agent@npm:5.0.0" - dependencies: - "@tootallnate/once": 2 - agent-base: 6 - debug: 4 - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 - languageName: node - linkType: hard - "http-proxy-agent@npm:^7.0.0": version: 7.0.0 resolution: "http-proxy-agent@npm:7.0.0" @@ -7922,17 +7625,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: 6 - debug: 4 - checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.2": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2": version: 7.0.2 resolution: "https-proxy-agent@npm:7.0.2" dependencies: @@ -7956,15 +7649,6 @@ __metadata: languageName: node linkType: hard -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: ^2.0.0 - checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - "hyperdyperid@npm:^1.2.0": version: 1.2.0 resolution: "hyperdyperid@npm:1.2.0" @@ -7998,9 +7682,9 @@ __metadata: linkType: hard "ignore@npm:^5.2.0, ignore@npm:^5.2.4": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef + version: 5.3.0 + resolution: "ignore@npm:5.3.0" + checksum: 2736da6621f14ced652785cb05d86301a66d70248597537176612bd0c8630893564bd5f6421f8806b09e8472e75c591ef01672ab8059c07c6eb2c09cefe04bf9 languageName: node linkType: hard @@ -8055,9 +7739,9 @@ __metadata: linkType: hard "inflation@npm:^2.0.0": - version: 2.0.0 - resolution: "inflation@npm:2.0.0" - checksum: a0494871b12275afdef9e2710ee1af1e0fc642b04613a9be69c05ef8b5e9627f3bd7d358a937fa47aa20235ee7313a4f30255048533add0ad4918beb918a586e + version: 2.1.0 + resolution: "inflation@npm:2.1.0" + checksum: 80c1b5d9ec408105a85f0623c824d668ddf0cadafd8d9716c0737990e5a712ae5f7d6bb0ff216b6648eccb9c6ac69fe06c0d8c58456d168db5bf550c89dd74ed languageName: node linkType: hard @@ -8093,31 +7777,30 @@ __metadata: linkType: hard "interface-datastore@npm:^8.2.0": - version: 8.2.3 - resolution: "interface-datastore@npm:8.2.3" + version: 8.2.10 + resolution: "interface-datastore@npm:8.2.10" dependencies: interface-store: ^5.0.0 - nanoid: ^4.0.0 - uint8arrays: ^4.0.2 - checksum: 01520fb965281f1352b93244a449d254e2fa9f9e4fb7f7f911b459354efcaa000d6ac311efda632d366281dbad41b3a61f321ce6a6241ab0f31283a81e4084cd + uint8arrays: ^5.0.0 + checksum: 16e12820b8423e457a6255377f373ea20132d7080809756b350e8914fde9abb73c4dd226cb3a9dda31bff790c181a02382bdde0482f9385ea4d2168c35ae93d8 languageName: node linkType: hard "interface-store@npm:^5.0.0": - version: 5.1.2 - resolution: "interface-store@npm:5.1.2" - checksum: 1423c5ffb5e6f9e65a86661cda90fb35d8dda433255bce9f57417650c98df83c84c4dc65741635c3efb16965b0f409f979a524f12b22803db0ab53ecfdf7b7db + version: 5.1.7 + resolution: "interface-store@npm:5.1.7" + checksum: aeddcdbfe8601f127c485ede6c6323bf2b302c713a1661036403dfd01b6b91e19a314ecf002477f108cb9c94d67781f88d386d3688f1e9c7cd1464a756ac28fa languageName: node linkType: hard "internal-slot@npm:^1.0.5": - version: 1.0.5 - resolution: "internal-slot@npm:1.0.5" + version: 1.0.6 + resolution: "internal-slot@npm:1.0.6" dependencies: - get-intrinsic: ^1.2.0 - has: ^1.0.3 + get-intrinsic: ^1.2.2 + hasown: ^2.0.0 side-channel: ^1.0.4 - checksum: 97e84046bf9e7574d0956bd98d7162313ce7057883b6db6c5c7b5e5f05688864b0978ba07610c726d15d66544ffe4b1050107d93f8a39ebc59b15d8b429b497a + checksum: 7872454888047553ce97a3fa1da7cc054a28ec5400a9c2e9f4dbe4fe7c1d041cb8e8301467614b80d4246d50377aad2fb58860b294ed74d6700cc346b6f89549 languageName: node linkType: hard @@ -8224,16 +7907,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.1.0, is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.0, is-core-module@npm:^2.12.1": - version: 2.12.1 - resolution: "is-core-module@npm:2.12.1" - dependencies: - has: ^1.0.3 - checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0": +"is-core-module@npm:^2.1.0, is-core-module@npm:^2.11.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1": version: 2.13.1 resolution: "is-core-module@npm:2.13.1" dependencies: @@ -8251,24 +7925,6 @@ __metadata: languageName: node linkType: hard -"is-docker@npm:^2.0.0": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 - languageName: node - linkType: hard - -"is-docker@npm:^3.0.0": - version: 3.0.0 - resolution: "is-docker@npm:3.0.0" - bin: - is-docker: cli.js - checksum: b698118f04feb7eaf3338922bd79cba064ea54a1c3db6ec8c0c8d8ee7613e7e5854d802d3ef646812a8a3ace81182a085dfa0a71cc68b06f3fa794b9783b3c90 - languageName: node - linkType: hard - "is-electron@npm:^2.2.0": version: 2.2.2 resolution: "is-electron@npm:2.2.2" @@ -8315,17 +7971,6 @@ __metadata: languageName: node linkType: hard -"is-inside-container@npm:^1.0.0": - version: 1.0.0 - resolution: "is-inside-container@npm:1.0.0" - dependencies: - is-docker: ^3.0.0 - bin: - is-inside-container: cli.js - checksum: c50b75a2ab66ab3e8b92b3bc534e1ea72ca25766832c0623ac22d134116a98bcf012197d1caabe1d1c4bd5f84363d4aa5c36bb4b585fbcaf57be172cd10a1a03 - languageName: node - linkType: hard - "is-interactive@npm:^1.0.0": version: 1.0.0 resolution: "is-interactive@npm:1.0.0" @@ -8341,9 +7986,9 @@ __metadata: linkType: hard "is-loopback-addr@npm:^2.0.1": - version: 2.0.1 - resolution: "is-loopback-addr@npm:2.0.1" - checksum: 77030f7a12875c124b0bb83f172c1fa29fcb14574d15a1d4ed13be71c441b9cdc393370967b2e4bf808c564072933467d48e9ea006a3fd2cb3c7437c6d913108 + version: 2.0.2 + resolution: "is-loopback-addr@npm:2.0.2" + checksum: c7818bd2815aa7aad1efd410d38f58647759e206b43fcf5b3a35db866ceff9af0b0145f1dcba472267c6e1b965883d1ebf321f3eb18c6a8c1c609c4f91092f2f languageName: node linkType: hard @@ -8354,6 +7999,13 @@ __metadata: languageName: node linkType: hard +"is-network-error@npm:^1.0.0": + version: 1.0.1 + resolution: "is-network-error@npm:1.0.1" + checksum: 165d61500c4186c62db5a3a693d6bfa14ca40fe9b471ef4cd4f27b20ef6760880faf5386dc01ca9867531631782941fedaa94521d09959edf71f046e393c7b91 + languageName: node + linkType: hard + "is-number-object@npm:^1.0.4": version: 1.0.7 resolution: "is-number-object@npm:1.0.7" @@ -8472,7 +8124,7 @@ __metadata: languageName: node linkType: hard -"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.3, is-typed-array@npm:^1.1.9": +"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.12, is-typed-array@npm:^1.1.3, is-typed-array@npm:^1.1.9": version: 1.1.12 resolution: "is-typed-array@npm:1.1.12" dependencies: @@ -8511,15 +8163,6 @@ __metadata: languageName: node linkType: hard -"is-wsl@npm:^2.2.0": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: ^2.0.0 - checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 - languageName: node - linkType: hard - "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" @@ -8541,6 +8184,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e + languageName: node + linkType: hard + "isobject@npm:^3.0.1": version: 3.0.1 resolution: "isobject@npm:3.0.1" @@ -8557,14 +8207,23 @@ __metadata: languageName: node linkType: hard +"isows@npm:1.0.3": + version: 1.0.3 + resolution: "isows@npm:1.0.3" + peerDependencies: + ws: "*" + checksum: 9cacd5cf59f67deb51e825580cd445ab1725ecb05a67c704050383fb772856f3cd5e7da8ad08f5a3bd2823680d77d099459d0c6a7037972a74d6429af61af440 + languageName: node + linkType: hard + "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": - version: 3.2.0 - resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 2367407a8d13982d8f7a859a35e7f8dd5d8f75aae4bb5484ede3a9ea1b426dc245aff28b976a2af48ee759fdd9be374ce2bd2669b644f31e76c5f46a2e29a831 languageName: node linkType: hard -"istanbul-lib-instrument@npm:^5.0.4, istanbul-lib-instrument@npm:^5.1.0": +"istanbul-lib-instrument@npm:^5.0.4": version: 5.2.1 resolution: "istanbul-lib-instrument@npm:5.2.1" dependencies: @@ -8577,6 +8236,19 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-instrument@npm:^6.0.0": + version: 6.0.1 + resolution: "istanbul-lib-instrument@npm:6.0.1" + dependencies: + "@babel/core": ^7.12.3 + "@babel/parser": ^7.14.7 + "@istanbuljs/schema": ^0.1.2 + istanbul-lib-coverage: ^3.2.0 + semver: ^7.5.4 + checksum: fb23472e739cfc9b027cefcd7d551d5e7ca7ff2817ae5150fab99fe42786a7f7b56a29a2aa8309c37092e18297b8003f9c274f50ca4360949094d17fbac81472 + languageName: node + linkType: hard + "istanbul-lib-report@npm:^3.0.0": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" @@ -8610,69 +8282,63 @@ __metadata: linkType: hard "it-all@npm:^3.0.0, it-all@npm:^3.0.1, it-all@npm:^3.0.2": - version: 3.0.2 - resolution: "it-all@npm:3.0.2" - checksum: 37ce90f8ee6a579aa5dd710899912f21d0b2083dad8686d8ca648b2d0c2ffdb4856770e3d004c9e9e4d0a17a9c57221ec501ada98571690ac508021e6227cdab + version: 3.0.4 + resolution: "it-all@npm:3.0.4" + checksum: fb7259660b6555ae268ffde6f0245026e9d4e8afccf9c43a088bb0ff0483aaca95954b6074c1c96d46a57b572bce35fa1bb8542934ce9aee477e1dba46293891 languageName: node linkType: hard "it-batched-bytes@npm:^2.0.2": - version: 2.0.3 - resolution: "it-batched-bytes@npm:2.0.3" + version: 2.0.5 + resolution: "it-batched-bytes@npm:2.0.5" dependencies: p-defer: ^4.0.0 uint8arraylist: ^2.4.1 - checksum: a5bd5c1f2969f1b93dbaa1fbcfe756dee270ffd262485ac1175066a235059b39c09dc9da14f93281bf6ac33381d81483d755ccfc386869ea37441555d98ba30c + checksum: c127881de01aae0d1625b2179ba66f7a084466adef0d5b20ab7129040651545e4aacbff01cf372e5118a2836685463732fa52714a16b16856657f8e05861b899 languageName: node linkType: hard "it-byte-stream@npm:^1.0.0": - version: 1.0.1 - resolution: "it-byte-stream@npm:1.0.1" + version: 1.0.7 + resolution: "it-byte-stream@npm:1.0.7" dependencies: - it-pushable: ^3.2.0 it-stream-types: ^2.0.1 + p-defer: ^4.0.0 + race-signal: ^1.0.1 uint8arraylist: ^2.4.1 - checksum: 5ebd79cc48a925937337ba8b9f2ced330f13692e4800c4053f099f190d1d62def8f3071f44fb5f78fd90113e58c9a9612d1e6dd3f2ce153d5c8a87e964bc9a5c + checksum: 9cd63aa3ab2e7ebe1a3cac545f546d9362577901922b7a75803e36caacb0ef46b0cf4bc5334a0acdc548ba976849065527b9467a3c048af64233e70891537aad languageName: node linkType: hard -"it-drain@npm:^3.0.1": - version: 3.0.2 - resolution: "it-drain@npm:3.0.2" - checksum: 4ad8d8a829c2f35116f07c94bf80a82381b00ee2d431d3d0556c4848013d79fe16df0d71ebf39fc51bc5b75cef296d9a5d4c8101ef1828e1ef31b67087d2e414 - languageName: node - linkType: hard - -"it-drain@npm:^3.0.2": - version: 3.0.3 - resolution: "it-drain@npm:3.0.3" - checksum: 5f918245b6b3de4c0371cad30bdaa2f85f6786305673e325c9c5fe0358f9ec93e1b42ab46790688b0b4cbda71e450f60f3f57fbb8f627a6e96b3ff0d9d35ec2c +"it-drain@npm:^3.0.1, it-drain@npm:^3.0.2": + version: 3.0.5 + resolution: "it-drain@npm:3.0.5" + checksum: 6ab86dc487737a0a87556fab52dadd00f376881b633bd00b8c461f1e8eace47c426e8065700946eb066072e33fc7df7f0e9fa12426bd1d8cac914d52c8f44f43 languageName: node linkType: hard "it-filter@npm:^3.0.0, it-filter@npm:^3.0.1": - version: 3.0.2 - resolution: "it-filter@npm:3.0.2" + version: 3.0.4 + resolution: "it-filter@npm:3.0.4" dependencies: it-peekable: ^3.0.0 - checksum: 6eea68bcd7ee75ac52dc477149a8e822da8d7626631256179601294412f22635929ee5c0b1566413c721d078ef4bfb8c94b0e2f0d093259909582c6d1d31f1f7 + checksum: 8d57903bd99fa1b18ff2c3d0fb7ba0d041a229a33b77ff5ff86ca591e5e0ed0a61b14e937c250754ff1085d8e1c4f88996a4feff76bfc3f73e5fe54726c74dd9 languageName: node linkType: hard "it-first@npm:^3.0.1": - version: 3.0.2 - resolution: "it-first@npm:3.0.2" - checksum: cb0131bed94e13e13cc02b67fb864c0995dc8deaf8e79a3b4685165f48b331f439caf21d6576e18027308ac03556e9108b517b18c34c0e11ede8a742806dccd8 + version: 3.0.4 + resolution: "it-first@npm:3.0.4" + checksum: 428cf4b7baaf04dcb0c157cbd6332c2bab9708eeae6df752533d8fd8e21f7c321bfa8a57d35982115f57760baf526a9bf210b7d982d793e8340e22db2aa68fc6 languageName: node linkType: hard "it-foreach@npm:^2.0.3": - version: 2.0.4 - resolution: "it-foreach@npm:2.0.4" + version: 2.0.6 + resolution: "it-foreach@npm:2.0.6" dependencies: it-peekable: ^3.0.0 - checksum: 7133068fb282ac74af2b7482466a72198e1c52393e09276c96e3c40ef5c8cb3f3b76f56a4a7b6dd2d40a7c20c1679bc75192abf6c90579aa803bb4ed5665930d + checksum: 95f66b141ced66ca4429711a5d4f36b605005e5607d5e17c2a0357f10ed1b6750e3d49683e029190c1d4ff7a89378fbf9d17b26ded31ddd55741b2a1ddc3d3f2 languageName: node linkType: hard @@ -8690,62 +8356,53 @@ __metadata: linkType: hard "it-length-prefixed-stream@npm:^1.0.0": - version: 1.0.2 - resolution: "it-length-prefixed-stream@npm:1.0.2" + version: 1.1.6 + resolution: "it-length-prefixed-stream@npm:1.1.6" dependencies: it-byte-stream: ^1.0.0 - it-length-prefixed: ^9.0.1 it-stream-types: ^2.0.1 uint8-varint: ^2.0.1 uint8arraylist: ^2.4.1 - checksum: 5fcb04352601bc43df96475d1d2c6b9bf40c87a68bc0dece26d8a5280df83f383aa468f154640a28112af9c1f85f24972837cfe538a3fe117da7dc68ac4b57db + checksum: 9bba9b781934eb85f68187f4c9128c158a856d0e7d3770e13201cee84829d9d482fb60bcf5eb9ca3ed85f3671a1a27df123e3869c8461cac6929a3a2f349b792 languageName: node linkType: hard "it-length-prefixed@npm:^9.0.1": - version: 9.0.1 - resolution: "it-length-prefixed@npm:9.0.1" + version: 9.0.4 + resolution: "it-length-prefixed@npm:9.0.4" dependencies: err-code: ^3.0.1 + it-reader: ^6.0.1 it-stream-types: ^2.0.1 - uint8-varint: ^1.0.1 + uint8-varint: ^2.0.1 uint8arraylist: ^2.0.0 - uint8arrays: ^4.0.2 - checksum: a431aedef3450287c9c93cbc4017aebfaf2443cae43abbbd65384a9981f58373ed6cbb505819e60e5e7ac414eefd9f3e9aa1b10cca3726d92c3f0d4671c25b40 + uint8arrays: ^5.0.1 + checksum: 18e7c4a96299c14ec654b2c41784d4e9889d9239ba858acd0a97b6ea0261b504b306c0850b1c28dd9e8678de03ff95f1e81ba03aed6ebf92f6d01b6e9cee3bab languageName: node linkType: hard "it-length@npm:^3.0.1": - version: 3.0.2 - resolution: "it-length@npm:3.0.2" - checksum: 688565353598557dc003324fc497896f5d24795f83011d03cc3625ced09207d9e66eda69e055080d1cd3c534673f65c76e5a5c48553b53e66b58a05995b49e81 - languageName: node - linkType: hard - -"it-map@npm:^3.0.1": - version: 3.0.3 - resolution: "it-map@npm:3.0.3" - dependencies: - it-peekable: ^3.0.0 - checksum: bf48828a40c19d98b49f42730fa3d2821b52056dd755dcdd9b4a1c1077fe8fcd79bf8ae810429e4a82d6cac5b2439e5f3aae8a3c7353c9b5c51ce14d038d9858 + version: 3.0.4 + resolution: "it-length@npm:3.0.4" + checksum: 881208cbcad1e3a396b27b35d73acbac9c27eb8b9fa43b1ed1bb4ca1aba489040981e0ea2b3db6fae90d2d9a1e4c610013abef4030ecd80eca64689f07df8dc9 languageName: node linkType: hard -"it-map@npm:^3.0.3": - version: 3.0.4 - resolution: "it-map@npm:3.0.4" +"it-map@npm:^3.0.1, it-map@npm:^3.0.3": + version: 3.0.5 + resolution: "it-map@npm:3.0.5" dependencies: it-peekable: ^3.0.0 - checksum: a5c0cc6ab36b2c2d2aa17189295891ec3b71244e251f99ff79fb5231891de97b79a9851f55f4e30b1cbc06ed1a13e25b1e4c4e4ea326199c86e382acc76de090 + checksum: bdaa2f1662325457a4eba487dfb04ca8aee0b1d91356b285bf6133aaeda67fba5b7d5c6644838ea8a025e4bd0e8a46910dd7b203f75940ed7ce0d8f3d159bbf3 languageName: node linkType: hard -"it-merge@npm:^3.0.0": - version: 3.0.1 - resolution: "it-merge@npm:3.0.1" +"it-merge@npm:^3.0.0, it-merge@npm:^3.0.1": + version: 3.0.3 + resolution: "it-merge@npm:3.0.3" dependencies: - it-pushable: ^3.1.0 - checksum: 8401b0394868cd02ccd988687a641b2a250668de1a818d7a867650621fb77e6dcd4b041972f738293ab65880b0a3a16b45d94c8b7b42d6b434430c817eee7565 + it-pushable: ^3.2.0 + checksum: 031c72302b35db8769c07646c561980c8d97097ce96aa869ebd0cf7b506ea075299b497a177a04bd5eb26398379b3e0b8f4c59a9a1ad0b1e7068d1a921cabf7b languageName: node linkType: hard @@ -8760,18 +8417,18 @@ __metadata: linkType: hard "it-parallel@npm:^3.0.0": - version: 3.0.3 - resolution: "it-parallel@npm:3.0.3" + version: 3.0.6 + resolution: "it-parallel@npm:3.0.6" dependencies: p-defer: ^4.0.0 - checksum: 2326fe2d15134d59dede916b8b72a83092f79b356537921ede24f0b0d95616f2916d8bf1ebd1af6db5326303af2ac654c64dc144df64b8f48b57a95d47c1be5f + checksum: ca9cc7faea9dee197dd5e683743542da21369c5a3d6991278b0221493d0e801abd7d750ed2860a97e6eeffae6b7c8af9fdd3e61285895317599d8608ccd7576d languageName: node linkType: hard "it-peekable@npm:^3.0.0": - version: 3.0.1 - resolution: "it-peekable@npm:3.0.1" - checksum: e327caf50bc205672b4133040e4c580cb39f6a8691565f420941ac5b7877ad1ca47c53ecf1ea62e4716abe36786b1cf07f2aea663eda6779fbf0d7a7cb0fbfdc + version: 3.0.3 + resolution: "it-peekable@npm:3.0.3" + checksum: 9603045130673b26a572cb2a9bfb7cbf9907fd759aa9dbfb1113b38c07c7b750b75a8dbec317b0cde6e47b6f3be2fddd9785fc7e38f1147ea3ded7eabd590c7a languageName: node linkType: hard @@ -8787,23 +8444,23 @@ __metadata: linkType: hard "it-protobuf-stream@npm:^1.0.0": - version: 1.0.2 - resolution: "it-protobuf-stream@npm:1.0.2" + version: 1.1.2 + resolution: "it-protobuf-stream@npm:1.1.2" dependencies: it-length-prefixed-stream: ^1.0.0 it-stream-types: ^2.0.1 protons-runtime: ^5.0.0 uint8arraylist: ^2.4.1 - checksum: a5d724c213f0e9e4f4f42145c43cf0bfe0036dc8f1cae094efd959710046aae399e77a2dd2e6c270a37103ae630386666676dddd6c8cf2138803402eba64dc1a + checksum: d10601aa530ee53da994377b4704e4f28a45ff26a4da1d64c1beccfcbdc1802da5cf480b692ff692a6557bd2dd0823c4e6992fc525122ab5da8d0ba67f003198 languageName: node linkType: hard -"it-pushable@npm:^3.0.0, it-pushable@npm:^3.1.0, it-pushable@npm:^3.1.2, it-pushable@npm:^3.1.3, it-pushable@npm:^3.2.0": - version: 3.2.1 - resolution: "it-pushable@npm:3.2.1" +"it-pushable@npm:^3.0.0, it-pushable@npm:^3.1.0, it-pushable@npm:^3.1.2, it-pushable@npm:^3.1.3, it-pushable@npm:^3.2.0, it-pushable@npm:^3.2.1, it-pushable@npm:^3.2.3": + version: 3.2.3 + resolution: "it-pushable@npm:3.2.3" dependencies: p-defer: ^4.0.0 - checksum: a23eaac8d1ec86785d0f3e71c67f1544cb1b99aff88c70d3043f3b87a9966c154ca387de76739f91dd744cd7815b40d20e9711a54079cc7ddaf36be54fd10c41 + checksum: 8b1d1ceb2a42b31b55119f9721b1f4568c498627470bac18479e6f8db3791fe1185653480cd1c319462bae3d64091bd9ca9e6e90e217e38a5ab7f078559ccca4 languageName: node linkType: hard @@ -8818,11 +8475,11 @@ __metadata: linkType: hard "it-sort@npm:^3.0.1": - version: 3.0.2 - resolution: "it-sort@npm:3.0.2" + version: 3.0.4 + resolution: "it-sort@npm:3.0.4" dependencies: it-all: ^3.0.0 - checksum: d45bb64413d949e1c7c459ad1b4418f14460959d5b73c830368ac18722277c8dcbc606740343ca87441c7c136838b7335a16f9174f0dd8ef03cdc80f8bcfdfbb + checksum: de4f1832c6d12914d51109ca3f8ccebba60fdb050d0af2b3d9b8bcd14cb3d320ba1a01e3ef59de2d3691886c0a903e1c4e46ad354796159d4b0d3d7013bc180c languageName: node linkType: hard @@ -8834,22 +8491,9 @@ __metadata: linkType: hard "it-take@npm:^3.0.1": - version: 3.0.2 - resolution: "it-take@npm:3.0.2" - checksum: 50a5449efa0832cd55878b7492f536b558861181786c7a95fb59d93c761646bc4bbc9dd46fd28a5b574b7349fa4caf028bbf66e3a86630473cc5907b811952a3 - languageName: node - linkType: hard - -"jackspeak@npm:^2.0.3": - version: 2.2.2 - resolution: "jackspeak@npm:2.2.2" - dependencies: - "@isaacs/cliui": ^8.0.2 - "@pkgjs/parseargs": ^0.11.0 - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 7b1468dd910afc00642db87448f24b062346570b8b47531409aa9012bcb95fdf7ec2b1c48edbb8b57a938c08391f8cc01b5034fc335aa3a2e74dbcc0ee5c555a + version: 3.0.4 + resolution: "it-take@npm:3.0.4" + checksum: 69dedde350817cba8de80e0432c9b81c35ff2b91f9c80582e657e382ec8c38af003f575353ae22605c963c28605a48cb994c7dba93fedac732db35ee86d7e516 languageName: node linkType: hard @@ -8873,59 +8517,59 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-changed-files@npm:29.5.0" +"jest-changed-files@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-changed-files@npm:29.7.0" dependencies: execa: ^5.0.0 + jest-util: ^29.7.0 p-limit: ^3.1.0 - checksum: a67a7cb3c11f8f92bd1b7c79e84f724cbd11a9ad51f3cdadafe3ce7ee3c79ee50dbea128f920f5fddc807e9e4e83f5462143094391feedd959a77dd20ab96cf3 + checksum: 963e203893c396c5dfc75e00a49426688efea7361b0f0e040035809cecd2d46b3c01c02be2d9e8d38b1138357d2de7719ea5b5be21f66c10f2e9685a5a73bb99 languageName: node linkType: hard -"jest-circus@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-circus@npm:29.6.2" +"jest-circus@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-circus@npm:29.7.0" dependencies: - "@jest/environment": ^29.6.2 - "@jest/expect": ^29.6.2 - "@jest/test-result": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/environment": ^29.7.0 + "@jest/expect": ^29.7.0 + "@jest/test-result": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" chalk: ^4.0.0 co: ^4.6.0 dedent: ^1.0.0 is-generator-fn: ^2.0.0 - jest-each: ^29.6.2 - jest-matcher-utils: ^29.6.2 - jest-message-util: ^29.6.2 - jest-runtime: ^29.6.2 - jest-snapshot: ^29.6.2 - jest-util: ^29.6.2 + jest-each: ^29.7.0 + jest-matcher-utils: ^29.7.0 + jest-message-util: ^29.7.0 + jest-runtime: ^29.7.0 + jest-snapshot: ^29.7.0 + jest-util: ^29.7.0 p-limit: ^3.1.0 - pretty-format: ^29.6.2 + pretty-format: ^29.7.0 pure-rand: ^6.0.0 slash: ^3.0.0 stack-utils: ^2.0.3 - checksum: 4f5a96a68c3c808c3d5a9279a2f39a2937386e2cebba5096971f267d79562ce2133a13bc05356a39f8f1ba68fcfe1eb39c4572b3fb0f91affbd932950e89c1e3 + checksum: 349437148924a5a109c9b8aad6d393a9591b4dac1918fc97d81b7fc515bc905af9918495055071404af1fab4e48e4b04ac3593477b1d5dcf48c4e71b527c70a7 languageName: node linkType: hard -"jest-cli@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-cli@npm:29.6.2" +"jest-cli@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-cli@npm:29.7.0" dependencies: - "@jest/core": ^29.6.2 - "@jest/test-result": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/core": ^29.7.0 + "@jest/test-result": ^29.7.0 + "@jest/types": ^29.6.3 chalk: ^4.0.0 + create-jest: ^29.7.0 exit: ^0.1.2 - graceful-fs: ^4.2.9 import-local: ^3.0.2 - jest-config: ^29.6.2 - jest-util: ^29.6.2 - jest-validate: ^29.6.2 - prompts: ^2.0.1 + jest-config: ^29.7.0 + jest-util: ^29.7.0 + jest-validate: ^29.7.0 yargs: ^17.3.1 peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -8934,34 +8578,34 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: 0b7b09ae4bd327caf1981eac5a14679ddda3c5c836c9f8ea0ecfe1e5e10e9a39a5ed783fa38d25383604c4d3405595e74b391d955e99aea7e51acb41a59ea108 + checksum: 664901277a3f5007ea4870632ed6e7889db9da35b2434e7cb488443e6bf5513889b344b7fddf15112135495b9875892b156faeb2d7391ddb9e2a849dcb7b6c36 languageName: node linkType: hard -"jest-config@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-config@npm:29.6.2" +"jest-config@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-config@npm:29.7.0" dependencies: "@babel/core": ^7.11.6 - "@jest/test-sequencer": ^29.6.2 - "@jest/types": ^29.6.1 - babel-jest: ^29.6.2 + "@jest/test-sequencer": ^29.7.0 + "@jest/types": ^29.6.3 + babel-jest: ^29.7.0 chalk: ^4.0.0 ci-info: ^3.2.0 deepmerge: ^4.2.2 glob: ^7.1.3 graceful-fs: ^4.2.9 - jest-circus: ^29.6.2 - jest-environment-node: ^29.6.2 - jest-get-type: ^29.4.3 - jest-regex-util: ^29.4.3 - jest-resolve: ^29.6.2 - jest-runner: ^29.6.2 - jest-util: ^29.6.2 - jest-validate: ^29.6.2 + jest-circus: ^29.7.0 + jest-environment-node: ^29.7.0 + jest-get-type: ^29.6.3 + jest-regex-util: ^29.6.3 + jest-resolve: ^29.7.0 + jest-runner: ^29.7.0 + jest-util: ^29.7.0 + jest-validate: ^29.7.0 micromatch: ^4.0.4 parse-json: ^5.2.0 - pretty-format: ^29.6.2 + pretty-format: ^29.7.0 slash: ^3.0.0 strip-json-comments: ^3.1.1 peerDependencies: @@ -8972,140 +8616,128 @@ __metadata: optional: true ts-node: optional: true - checksum: 3bd104a3ac2dd9d34986238142437606354169766dcf88359a7a12ac106d0dc17dcc6b627e4f20db97a58bac5b0502b5436c9cc4722b3629b2a114bba6da9128 + checksum: 4cabf8f894c180cac80b7df1038912a3fc88f96f2622de33832f4b3314f83e22b08fb751da570c0ab2b7988f21604bdabade95e3c0c041068ac578c085cf7dff languageName: node linkType: hard -"jest-diff@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-diff@npm:29.6.2" +"jest-diff@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-diff@npm:29.7.0" dependencies: chalk: ^4.0.0 - diff-sequences: ^29.4.3 - jest-get-type: ^29.4.3 - pretty-format: ^29.6.2 - checksum: 0effd66a0c23f8c139ebf7ca99ed30b479b86fff66f19ad4869f130aaf7ae6a24ca1533f697b7e4930cbe2ddffc85387723fcca673501c653fb77a38f538e959 + diff-sequences: ^29.6.3 + jest-get-type: ^29.6.3 + pretty-format: ^29.7.0 + checksum: 08e24a9dd43bfba1ef07a6374e5af138f53137b79ec3d5cc71a2303515335898888fa5409959172e1e05de966c9e714368d15e8994b0af7441f0721ee8e1bb77 languageName: node linkType: hard -"jest-docblock@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-docblock@npm:29.4.3" +"jest-docblock@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-docblock@npm:29.7.0" dependencies: detect-newline: ^3.0.0 - checksum: e0e9df1485bb8926e5b33478cdf84b3387d9caf3658e7dc1eaa6dc34cb93dea0d2d74797f6e940f0233a88f3dadd60957f2288eb8f95506361f85b84bf8661df + checksum: 66390c3e9451f8d96c5da62f577a1dad701180cfa9b071c5025acab2f94d7a3efc2515cfa1654ebe707213241541ce9c5530232cdc8017c91ed64eea1bd3b192 languageName: node linkType: hard -"jest-each@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-each@npm:29.6.2" +"jest-each@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-each@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 chalk: ^4.0.0 - jest-get-type: ^29.4.3 - jest-util: ^29.6.2 - pretty-format: ^29.6.2 - checksum: b64194f4ca27afc6070a42b7ecccbc68be0ded19a849f8cd8f91a2abb23fadae2d38d47559a315f4d1f576927761f3ea437a75ab6cf19206332abb8527d7c165 + jest-get-type: ^29.6.3 + jest-util: ^29.7.0 + pretty-format: ^29.7.0 + checksum: e88f99f0184000fc8813f2a0aa79e29deeb63700a3b9b7928b8a418d7d93cd24933608591dbbdea732b473eb2021c72991b5cc51a17966842841c6e28e6f691c languageName: node linkType: hard -"jest-environment-node@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-environment-node@npm:29.6.2" +"jest-environment-node@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-environment-node@npm:29.7.0" dependencies: - "@jest/environment": ^29.6.2 - "@jest/fake-timers": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/environment": ^29.7.0 + "@jest/fake-timers": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" - jest-mock: ^29.6.2 - jest-util: ^29.6.2 - checksum: 0b754ac2d3bdb7ce5d6fc28595b9d1c64176f20506b6f773b18b0280ab0b396ed7d927c8519779d3c560fa2b13236ee7077092ccb19a13bea23d40dd30f06450 + jest-mock: ^29.7.0 + jest-util: ^29.7.0 + checksum: 501a9966292cbe0ca3f40057a37587cb6def25e1e0c5e39ac6c650fe78d3c70a2428304341d084ac0cced5041483acef41c477abac47e9a290d5545fd2f15646 languageName: node linkType: hard -"jest-get-type@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-get-type@npm:29.4.3" - checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce +"jest-get-type@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-get-type@npm:29.6.3" + checksum: 88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 languageName: node linkType: hard -"jest-haste-map@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-haste-map@npm:29.6.2" +"jest-haste-map@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-haste-map@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@types/graceful-fs": ^4.1.3 "@types/node": "*" anymatch: ^3.0.3 fb-watchman: ^2.0.0 fsevents: ^2.3.2 graceful-fs: ^4.2.9 - jest-regex-util: ^29.4.3 - jest-util: ^29.6.2 - jest-worker: ^29.6.2 + jest-regex-util: ^29.6.3 + jest-util: ^29.7.0 + jest-worker: ^29.7.0 micromatch: ^4.0.4 walker: ^1.0.8 dependenciesMeta: fsevents: optional: true - checksum: 726233972030eb2e5bce6c9468e497310436b455c88b40e744bd053e20a6f3ff19aec340edcbd89537c629ed5cf8916506bc895d690cc39a0862c74dcd95b7b8 + checksum: c2c8f2d3e792a963940fbdfa563ce14ef9e14d4d86da645b96d3cd346b8d35c5ce0b992ee08593939b5f718cf0a1f5a90011a056548a1dbf58397d4356786f01 languageName: node linkType: hard -"jest-leak-detector@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-leak-detector@npm:29.6.2" +"jest-leak-detector@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-leak-detector@npm:29.7.0" dependencies: - jest-get-type: ^29.4.3 - pretty-format: ^29.6.2 - checksum: e00152acdba8aa8f9334775b77375947508051c34646fbeb702275da2b6ac6145f8cad6d5893112e76484d00fa8c0b4fd71b78ab0b4ef34950f5b6a84f37ae67 + jest-get-type: ^29.6.3 + pretty-format: ^29.7.0 + checksum: e3950e3ddd71e1d0c22924c51a300a1c2db6cf69ec1e51f95ccf424bcc070f78664813bef7aed4b16b96dfbdeea53fe358f8aeaaea84346ae15c3735758f1605 languageName: node linkType: hard -"jest-matcher-utils@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-matcher-utils@npm:29.6.2" +"jest-matcher-utils@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-matcher-utils@npm:29.7.0" dependencies: chalk: ^4.0.0 - jest-diff: ^29.6.2 - jest-get-type: ^29.4.3 - pretty-format: ^29.6.2 - checksum: 3e1b65dd30d05f75fe56dc45fbe4135aec2ff96a3d1e21afbf6a66f3a45a7e29cd0fd37cf80b9564e0381d6205833f77ccaf766c6f7e1aad6b7924d117be504e + jest-diff: ^29.7.0 + jest-get-type: ^29.6.3 + pretty-format: ^29.7.0 + checksum: d7259e5f995d915e8a37a8fd494cb7d6af24cd2a287b200f831717ba0d015190375f9f5dc35393b8ba2aae9b2ebd60984635269c7f8cff7d85b077543b7744cd languageName: node linkType: hard -"jest-message-util@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-message-util@npm:29.6.2" +"jest-message-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-message-util@npm:29.7.0" dependencies: "@babel/code-frame": ^7.12.13 - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@types/stack-utils": ^2.0.0 chalk: ^4.0.0 graceful-fs: ^4.2.9 micromatch: ^4.0.4 - pretty-format: ^29.6.2 + pretty-format: ^29.7.0 slash: ^3.0.0 stack-utils: ^2.0.3 - checksum: e8e3c8d2301e2ca4038ed6df8cbba7fedc6949d1ede4c0e3f1f44f53afb56d77eb35983fa460140d0eadeab99a5f3ae04b703fe77cd7b316b40b361228b5aa1a + checksum: a9d025b1c6726a2ff17d54cc694de088b0489456c69106be6b615db7a51b7beb66788bea7a59991a019d924fbf20f67d085a445aedb9a4d6760363f4d7d09930 languageName: node linkType: hard -"jest-mock-extended@npm:^3.0.3, jest-mock-extended@npm:^3.0.4": - version: 3.0.4 - resolution: "jest-mock-extended@npm:3.0.4" - dependencies: - ts-essentials: ^7.0.3 - peerDependencies: - jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 - typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 - checksum: f861253c63508b30d971fbbbc1bf2911ff4406cd260d0e23483a1d4514898b18ba5efbd43fbdf6d94996dc09b20eb1aad1b46aeaea9c99244ba12dc99814fd3f - languageName: node - linkType: hard - -"jest-mock-extended@npm:^3.0.5": +"jest-mock-extended@npm:^3.0.3, jest-mock-extended@npm:^3.0.4, jest-mock-extended@npm:^3.0.5": version: 3.0.5 resolution: "jest-mock-extended@npm:3.0.5" dependencies: @@ -9117,14 +8749,14 @@ __metadata: languageName: node linkType: hard -"jest-mock@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-mock@npm:29.6.2" +"jest-mock@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-mock@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@types/node": "*" - jest-util: ^29.6.2 - checksum: 0bacb5d58441462c0e531ec4d2f7377eecbe21f664d8a460e72f94ba61d22635028931678e7a0f1c3e3f5894973db8e409432f7db4c01283456c8fdbd85f5b3b + jest-util: ^29.7.0 + checksum: 81ba9b68689a60be1482212878973700347cb72833c5e5af09895882b9eb5c4e02843a1bbdf23f94c52d42708bab53a30c45a3482952c9eec173d1eaac5b86c5 languageName: node linkType: hard @@ -9140,168 +8772,168 @@ __metadata: languageName: node linkType: hard -"jest-regex-util@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-regex-util@npm:29.4.3" - checksum: 96fc7fc28cd4dd73a63c13a526202c4bd8b351d4e5b68b1a2a2c88da3308c2a16e26feaa593083eb0bac38cca1aa9dd05025412e7de013ba963fb8e66af22b8a +"jest-regex-util@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-regex-util@npm:29.6.3" + checksum: 0518beeb9bf1228261695e54f0feaad3606df26a19764bc19541e0fc6e2a3737191904607fb72f3f2ce85d9c16b28df79b7b1ec9443aa08c3ef0e9efda6f8f2a languageName: node linkType: hard -"jest-resolve-dependencies@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-resolve-dependencies@npm:29.6.2" +"jest-resolve-dependencies@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-resolve-dependencies@npm:29.7.0" dependencies: - jest-regex-util: ^29.4.3 - jest-snapshot: ^29.6.2 - checksum: d40ee11af2c9d2ef0dbbcf9a5b7dda37c2b86cf4e5de1705795919fd8927907569115c502116ab56de0dca576d5faa31ec9b636240333b6830a568a63004da17 + jest-regex-util: ^29.6.3 + jest-snapshot: ^29.7.0 + checksum: aeb75d8150aaae60ca2bb345a0d198f23496494677cd6aefa26fc005faf354061f073982175daaf32b4b9d86b26ca928586344516e3e6969aa614cb13b883984 languageName: node linkType: hard -"jest-resolve@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-resolve@npm:29.6.2" +"jest-resolve@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-resolve@npm:29.7.0" dependencies: chalk: ^4.0.0 graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.2 + jest-haste-map: ^29.7.0 jest-pnp-resolver: ^1.2.2 - jest-util: ^29.6.2 - jest-validate: ^29.6.2 + jest-util: ^29.7.0 + jest-validate: ^29.7.0 resolve: ^1.20.0 resolve.exports: ^2.0.0 slash: ^3.0.0 - checksum: 01721957e61821a576b2ded043eeab8b392166e0e6d8d680f75657737e2ea7481ff29c2716b866ccd12e743f3a8da465504b1028e78b6a3c68b9561303de7ec8 + checksum: 0ca218e10731aa17920526ec39deaec59ab9b966237905ffc4545444481112cd422f01581230eceb7e82d86f44a543d520a71391ec66e1b4ef1a578bd5c73487 languageName: node linkType: hard -"jest-runner@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-runner@npm:29.6.2" +"jest-runner@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-runner@npm:29.7.0" dependencies: - "@jest/console": ^29.6.2 - "@jest/environment": ^29.6.2 - "@jest/test-result": ^29.6.2 - "@jest/transform": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/console": ^29.7.0 + "@jest/environment": ^29.7.0 + "@jest/test-result": ^29.7.0 + "@jest/transform": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" chalk: ^4.0.0 emittery: ^0.13.1 graceful-fs: ^4.2.9 - jest-docblock: ^29.4.3 - jest-environment-node: ^29.6.2 - jest-haste-map: ^29.6.2 - jest-leak-detector: ^29.6.2 - jest-message-util: ^29.6.2 - jest-resolve: ^29.6.2 - jest-runtime: ^29.6.2 - jest-util: ^29.6.2 - jest-watcher: ^29.6.2 - jest-worker: ^29.6.2 + jest-docblock: ^29.7.0 + jest-environment-node: ^29.7.0 + jest-haste-map: ^29.7.0 + jest-leak-detector: ^29.7.0 + jest-message-util: ^29.7.0 + jest-resolve: ^29.7.0 + jest-runtime: ^29.7.0 + jest-util: ^29.7.0 + jest-watcher: ^29.7.0 + jest-worker: ^29.7.0 p-limit: ^3.1.0 source-map-support: 0.5.13 - checksum: 46bd506a08ddf79628a509aed4105ab74c0b03727a3e24c90bbc2915531860b3da99f7ace2fd9603194440553cffac9cfb1a3b7d0ce03d5fc9c5f2d5ffbb3d3f + checksum: f0405778ea64812bf9b5c50b598850d94ccf95d7ba21f090c64827b41decd680ee19fcbb494007cdd7f5d0d8906bfc9eceddd8fa583e753e736ecd462d4682fb languageName: node linkType: hard -"jest-runtime@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-runtime@npm:29.6.2" +"jest-runtime@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-runtime@npm:29.7.0" dependencies: - "@jest/environment": ^29.6.2 - "@jest/fake-timers": ^29.6.2 - "@jest/globals": ^29.6.2 - "@jest/source-map": ^29.6.0 - "@jest/test-result": ^29.6.2 - "@jest/transform": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/environment": ^29.7.0 + "@jest/fake-timers": ^29.7.0 + "@jest/globals": ^29.7.0 + "@jest/source-map": ^29.6.3 + "@jest/test-result": ^29.7.0 + "@jest/transform": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" chalk: ^4.0.0 cjs-module-lexer: ^1.0.0 collect-v8-coverage: ^1.0.0 glob: ^7.1.3 graceful-fs: ^4.2.9 - jest-haste-map: ^29.6.2 - jest-message-util: ^29.6.2 - jest-mock: ^29.6.2 - jest-regex-util: ^29.4.3 - jest-resolve: ^29.6.2 - jest-snapshot: ^29.6.2 - jest-util: ^29.6.2 + jest-haste-map: ^29.7.0 + jest-message-util: ^29.7.0 + jest-mock: ^29.7.0 + jest-regex-util: ^29.6.3 + jest-resolve: ^29.7.0 + jest-snapshot: ^29.7.0 + jest-util: ^29.7.0 slash: ^3.0.0 strip-bom: ^4.0.0 - checksum: 8e7e4486b23b01a9c407313681bed0def39680c2ae21cf01347f111983252ec3a024c56493c5411fed53633f02863eed0816099110cbe04b3889aa5babf1042d + checksum: d19f113d013e80691e07047f68e1e3448ef024ff2c6b586ce4f90cd7d4c62a2cd1d460110491019719f3c59bfebe16f0e201ed005ef9f80e2cf798c374eed54e languageName: node linkType: hard -"jest-snapshot@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-snapshot@npm:29.6.2" +"jest-snapshot@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-snapshot@npm:29.7.0" dependencies: "@babel/core": ^7.11.6 "@babel/generator": ^7.7.2 "@babel/plugin-syntax-jsx": ^7.7.2 "@babel/plugin-syntax-typescript": ^7.7.2 "@babel/types": ^7.3.3 - "@jest/expect-utils": ^29.6.2 - "@jest/transform": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/expect-utils": ^29.7.0 + "@jest/transform": ^29.7.0 + "@jest/types": ^29.6.3 babel-preset-current-node-syntax: ^1.0.0 chalk: ^4.0.0 - expect: ^29.6.2 + expect: ^29.7.0 graceful-fs: ^4.2.9 - jest-diff: ^29.6.2 - jest-get-type: ^29.4.3 - jest-matcher-utils: ^29.6.2 - jest-message-util: ^29.6.2 - jest-util: ^29.6.2 + jest-diff: ^29.7.0 + jest-get-type: ^29.6.3 + jest-matcher-utils: ^29.7.0 + jest-message-util: ^29.7.0 + jest-util: ^29.7.0 natural-compare: ^1.4.0 - pretty-format: ^29.6.2 + pretty-format: ^29.7.0 semver: ^7.5.3 - checksum: c1c70a9dbce7fca62ed73ac38234b4ee643e8b667acf71b4417ab67776c1188bb08b8ad450e56a2889ad182903ffd416386fa8082a477724ccf8d8c29a4c6906 + checksum: 86821c3ad0b6899521ce75ee1ae7b01b17e6dfeff9166f2cf17f012e0c5d8c798f30f9e4f8f7f5bed01ea7b55a6bc159f5eda778311162cbfa48785447c237ad languageName: node linkType: hard -"jest-util@npm:^29.0.0, jest-util@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-util@npm:29.6.2" +"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-util@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 "@types/node": "*" chalk: ^4.0.0 ci-info: ^3.2.0 graceful-fs: ^4.2.9 picomatch: ^2.2.3 - checksum: 8aedc0c80083d0cabd6c6c4f04dea1cbcac609fd7bc3b1fc05a3999291bd6e63dd52b0c806f9378d5cae28eff5a6191709a4987861001293f8d03e53984adca4 + checksum: 042ab4980f4ccd4d50226e01e5c7376a8556b472442ca6091a8f102488c0f22e6e8b89ea874111d2328a2080083bf3225c86f3788c52af0bd0345a00eb57a3ca languageName: node linkType: hard -"jest-validate@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-validate@npm:29.6.2" +"jest-validate@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-validate@npm:29.7.0" dependencies: - "@jest/types": ^29.6.1 + "@jest/types": ^29.6.3 camelcase: ^6.2.0 chalk: ^4.0.0 - jest-get-type: ^29.4.3 + jest-get-type: ^29.6.3 leven: ^3.1.0 - pretty-format: ^29.6.2 - checksum: 32648d002189c0ad8a958eace7c6b7d05ea1dc440a1b91e0f22dc1aef489899446ec80b2d527fd13713862d89dfb4606e24a3bf8a10c4ddac3c911e93b7f0374 + pretty-format: ^29.7.0 + checksum: 191fcdc980f8a0de4dbdd879fa276435d00eb157a48683af7b3b1b98b0f7d9de7ffe12689b617779097ff1ed77601b9f7126b0871bba4f776e222c40f62e9dae languageName: node linkType: hard -"jest-watcher@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-watcher@npm:29.6.2" +"jest-watcher@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-watcher@npm:29.7.0" dependencies: - "@jest/test-result": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/test-result": ^29.7.0 + "@jest/types": ^29.6.3 "@types/node": "*" ansi-escapes: ^4.2.1 chalk: ^4.0.0 emittery: ^0.13.1 - jest-util: ^29.6.2 + jest-util: ^29.7.0 string-length: ^4.0.1 - checksum: 14624190fc8b5fbae466a2ec81458a88c15716d99f042bb4674d53e9623d305cb2905bc1dffeda05fd1a10a05c2a83efe5ac41942477e2b15eaebb08d0aaab32 + checksum: 67e6e7fe695416deff96b93a14a561a6db69389a0667e9489f24485bb85e5b54e12f3b2ba511ec0b777eca1e727235b073e3ebcdd473d68888650489f88df92f languageName: node linkType: hard @@ -9316,26 +8948,26 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-worker@npm:29.6.2" +"jest-worker@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-worker@npm:29.7.0" dependencies: "@types/node": "*" - jest-util: ^29.6.2 + jest-util: ^29.7.0 merge-stream: ^2.0.0 supports-color: ^8.0.0 - checksum: 11035564534bf181ead80b25be138c2d42372bd5626151a3e705200d47a74fd9da3ca79f8a7b15806cdc325ad73c3d21d23acceeed99d50941589ff02915ed38 + checksum: 30fff60af49675273644d408b650fc2eb4b5dcafc5a0a455f238322a8f9d8a98d847baca9d51ff197b6747f54c7901daa2287799230b856a0f48287d131f8c13 languageName: node linkType: hard "jest@npm:^29.5.0": - version: 29.6.2 - resolution: "jest@npm:29.6.2" + version: 29.7.0 + resolution: "jest@npm:29.7.0" dependencies: - "@jest/core": ^29.6.2 - "@jest/types": ^29.6.1 + "@jest/core": ^29.7.0 + "@jest/types": ^29.6.3 import-local: ^3.0.2 - jest-cli: ^29.6.2 + jest-cli: ^29.7.0 peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -9343,7 +8975,7 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: dd63facd4e6aefc35d2c42acd7e4c9fb0d8fe4705df4b3ccedd953605424d7aa89c88af8cf4c9951752709cac081d29c35b264e1794643d5688ea724ccc9a485 + checksum: 17ca8d67504a7dbb1998cf3c3077ec9031ba3eb512da8d71cb91bcabb2b8995c4e4b292b740cb9bf1cbff5ce3e110b3f7c777b0cefb6f41ab05445f248d0ee0b languageName: node linkType: hard @@ -9400,9 +9032,16 @@ __metadata: languageName: node linkType: hard +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 + languageName: node + linkType: hard + "json-joy@npm:^9.2.0": - version: 9.6.0 - resolution: "json-joy@npm:9.6.0" + version: 9.9.1 + resolution: "json-joy@npm:9.9.1" dependencies: arg: ^5.0.2 hyperdyperid: ^1.2.0 @@ -9419,7 +9058,7 @@ __metadata: json-pointer: bin/json-pointer.js json-pointer-test: bin/json-pointer-test.js json-unpack: bin/json-unpack.js - checksum: 517b1b466b1b477bd53ecf23693758e785cebba5bf32dbb04059164b067330246efd35f11df13e8a04fb85ec4c330f806e2752736189a12f1a4ff1a1e423ec27 + checksum: d165398682f00019796225faf365cd8d060f3e086af39bb5081c30907b7e52eaf13697d1c0f6ee2b010fe255ae1fd776e05ad7d6ee5fb549e98fe982f560884b languageName: node linkType: hard @@ -9455,7 +9094,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.2.2, json5@npm:^2.2.3": +"json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -9465,9 +9104,9 @@ __metadata: linkType: hard "jsonc-parser@npm:^3.2.0": - version: 3.2.0 - resolution: "jsonc-parser@npm:3.2.0" - checksum: 946dd9a5f326b745aa326d48a7257e3f4a4b62c5e98ec8e49fa2bdd8d96cef7e6febf1399f5c7016114fd1f68a1c62c6138826d5d90bc650448e3cf0951c53c7 + version: 3.2.1 + resolution: "jsonc-parser@npm:3.2.1" + checksum: 656d9027b91de98d8ab91b3aa0d0a4cab7dc798a6830845ca664f3e76c82d46b973675bbe9b500fae1de37fd3e81aceacbaa2a57884bf2f8f29192150d2d1ef7 languageName: node linkType: hard @@ -9517,6 +9156,15 @@ __metadata: languageName: node linkType: hard +"keyv@npm:^4.5.3": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: 3.0.1 + checksum: 74a24395b1c34bd44ad5cb2b49140d087553e170625240b86755a6604cd65aa16efdbdeae5cdb17ba1284a0fbb25ad06263755dbc71b8d8b06f74232ce3cdd72 + languageName: node + linkType: hard + "kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -9586,14 +9234,15 @@ __metadata: linkType: hard "koa-router@npm:^12.0.0": - version: 12.0.0 - resolution: "koa-router@npm:12.0.0" + version: 12.0.1 + resolution: "koa-router@npm:12.0.1" dependencies: + debug: ^4.3.4 http-errors: ^2.0.0 koa-compose: ^4.1.0 methods: ^1.1.2 path-to-regexp: ^6.2.1 - checksum: 29b02fd96972c037e805f6ce2626c971f4fd9cba04005bfedc080ab425d31b4b1cfe2ebc000b26e4a45e68215a3a3ed557f836ba486ea0d2f1e7e78fc95f8dca + checksum: 62852af6c47dba9327c993594367b8bcd995fd49972d2539eae9afa231571680f75ebe0f439bf886256cdfaf791900c2d11fe31b894d9ba8c60d1c727c03b9ed languageName: node linkType: hard @@ -9619,14 +9268,14 @@ __metadata: linkType: hard "koa@npm:^2.14.2": - version: 2.14.2 - resolution: "koa@npm:2.14.2" + version: 2.15.0 + resolution: "koa@npm:2.15.0" dependencies: accepts: ^1.3.5 cache-content-type: ^1.0.0 content-disposition: ~0.5.2 content-type: ^1.0.4 - cookies: ~0.8.0 + cookies: ~0.9.0 debug: ^4.3.2 delegates: ^1.0.0 depd: ^2.0.0 @@ -9645,7 +9294,7 @@ __metadata: statuses: ^1.5.0 type-is: ^1.6.16 vary: ^1.1.2 - checksum: 17fe3b8f5e0b4759004a942cc6ba2a9507299943a697dff9766b85f41f45caed4077ca2645ac9ad254d3359fffedfc4c9ebdd7a70493e5df8cdfac159a8ee835 + checksum: a97741f89f328f25ae94d82d0ee608377d89e086c73f2d868023e6050dea682ef93e0a5c80097f3aaad28121853aea50a7fb3c0c12ecc45798da2fd1255f580b languageName: node linkType: hard @@ -9733,26 +9382,25 @@ __metadata: linkType: hard "libp2p@npm:^0.46.6": - version: 0.46.6 - resolution: "libp2p@npm:0.46.6" + version: 0.46.21 + resolution: "libp2p@npm:0.46.21" dependencies: "@achingbrain/nat-port-mapper": ^1.0.9 - "@libp2p/crypto": ^2.0.3 - "@libp2p/interface": ^0.1.2 - "@libp2p/interface-internal": ^0.1.4 - "@libp2p/keychain": ^3.0.3 - "@libp2p/logger": ^3.0.2 - "@libp2p/multistream-select": ^4.0.2 - "@libp2p/peer-collections": ^4.0.3 - "@libp2p/peer-id": ^3.0.2 - "@libp2p/peer-id-factory": ^3.0.3 - "@libp2p/peer-record": ^6.0.3 - "@libp2p/peer-store": ^9.0.3 - "@libp2p/utils": ^4.0.2 + "@libp2p/crypto": ^2.0.8 + "@libp2p/interface": ^0.1.6 + "@libp2p/interface-internal": ^0.1.9 + "@libp2p/keychain": ^3.0.8 + "@libp2p/logger": ^3.1.0 + "@libp2p/multistream-select": ^4.0.6 + "@libp2p/peer-collections": ^4.0.8 + "@libp2p/peer-id": ^3.0.6 + "@libp2p/peer-id-factory": ^3.0.8 + "@libp2p/peer-record": ^6.0.9 + "@libp2p/peer-store": ^9.0.9 + "@libp2p/utils": ^4.0.7 "@multiformats/mafmt": ^12.1.2 "@multiformats/multiaddr": ^12.1.5 "@multiformats/multiaddr-matcher": ^1.0.0 - abortable-iterator: ^5.0.1 any-signal: ^4.1.1 datastore-core: ^9.0.1 delay: ^6.0.0 @@ -9774,15 +9422,15 @@ __metadata: multiformats: ^12.0.1 p-defer: ^4.0.0 p-queue: ^7.3.4 - p-retry: ^5.0.0 + p-retry: ^6.0.0 private-ip: ^3.0.0 protons-runtime: ^5.0.0 - rate-limiter-flexible: ^2.3.11 + rate-limiter-flexible: ^3.0.0 uint8arraylist: ^2.4.3 uint8arrays: ^4.0.6 wherearewe: ^2.0.1 xsalsa20: ^1.1.0 - checksum: c23d6621f1ed7d5c96de440fb08bfc807a8fc38c44e54ed6422f9414414dae0c7e87675f9416eacd5b143a2ff91fba26e6001bdde670f80696c4e73574fc228e + checksum: 6f69e89e8f4ac28ee1b365db878379d28865982bf6d4cec9524d9445975b5eab4fa5dca581e704ce1438b196258e88856cf6778048b59a75ae09ca1b9417fbb8 languageName: node linkType: hard @@ -9802,16 +9450,16 @@ __metadata: languageName: node linkType: hard -"lmdb@npm:^2.9.1": - version: 2.9.1 - resolution: "lmdb@npm:2.9.1" +"lmdb@npm:^2.9.2": + version: 2.9.2 + resolution: "lmdb@npm:2.9.2" dependencies: - "@lmdb/lmdb-darwin-arm64": 2.9.1 - "@lmdb/lmdb-darwin-x64": 2.9.1 - "@lmdb/lmdb-linux-arm": 2.9.1 - "@lmdb/lmdb-linux-arm64": 2.9.1 - "@lmdb/lmdb-linux-x64": 2.9.1 - "@lmdb/lmdb-win32-x64": 2.9.1 + "@lmdb/lmdb-darwin-arm64": 2.9.2 + "@lmdb/lmdb-darwin-x64": 2.9.2 + "@lmdb/lmdb-linux-arm": 2.9.2 + "@lmdb/lmdb-linux-arm64": 2.9.2 + "@lmdb/lmdb-linux-x64": 2.9.2 + "@lmdb/lmdb-win32-x64": 2.9.2 msgpackr: ^1.9.9 node-addon-api: ^6.1.0 node-gyp: latest @@ -9833,7 +9481,7 @@ __metadata: optional: true bin: download-lmdb-prebuilds: bin/download-prebuilds.js - checksum: 1f0a8754cc019586c8e34bd45e4ee1df99f6f5732e8dc04f951cf631895a179dfd913123773206935a580cfe80bce117800a3ccf0a2cc8187821badfdaa71cd4 + checksum: b2471c4d2c36f15a27233ae1eece86fcbb40613574ec54245cf697b16b1b35c70c72e4092dc739407df145f14b7c1b6b56c4281a439c314e79a5338df8b2b63b languageName: node linkType: hard @@ -9990,33 +9638,23 @@ __metadata: linkType: hard "logform@npm:^2.3.2, logform@npm:^2.4.0": - version: 2.5.1 - resolution: "logform@npm:2.5.1" + version: 2.6.0 + resolution: "logform@npm:2.6.0" dependencies: - "@colors/colors": 1.5.0 + "@colors/colors": 1.6.0 "@types/triple-beam": ^1.3.2 fecha: ^4.2.0 ms: ^2.1.1 safe-stable-stringify: ^2.3.1 triple-beam: ^1.3.0 - checksum: 08fdf03be5bb69af33bac214eb4f6a0c83ad3821a30de498925fccb61e993e5a4a87470aab356ca2110c11e4643685bed5597ca5f46dd1cd11437c44a0e0e3c2 - languageName: node - linkType: hard - -"long@npm:^5.0.0": - version: 5.2.3 - resolution: "long@npm:5.2.3" - checksum: 885ede7c3de4facccbd2cacc6168bae3a02c3e836159ea4252c87b6e34d40af819824b2d4edce330bfb5c4d6e8ce3ec5864bdcf9473fa1f53a4f8225860e5897 + checksum: b9ea74bb75e55379ad0eb3e4d65ae6e8d02bc45b431c218162878bf663997ab9258a73104c2b30e09dd2db288bb83c8bf8748e46689d75f5e7e34cf69378d6df languageName: node linkType: hard -"longbits@npm:^1.1.0": - version: 1.1.0 - resolution: "longbits@npm:1.1.0" - dependencies: - byte-access: ^1.0.1 - uint8arraylist: ^2.0.0 - checksum: 7f8ec8ddef64b160da22c31875fa549b40a4cff626c948c423dc2cb73c0d85a5c6a13ce3a611b5229fcf65dd6ffb4fcd1d5eaef61458570194172ad485112521 +"lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.2.0 + resolution: "lru-cache@npm:10.2.0" + checksum: eee7ddda4a7475deac51ac81d7dd78709095c6fa46e8350dc2d22462559a1faa3b81ed931d5464b13d48cbd7e08b46100b6f768c76833912bc444b99c37e25db languageName: node linkType: hard @@ -10038,20 +9676,13 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.14.1, lru-cache@npm:^7.7.1": +"lru-cache@npm:^7.14.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 languageName: node linkType: hard -"lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.0 - resolution: "lru-cache@npm:10.0.0" - checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 - languageName: node - linkType: hard - "ltgt@npm:^2.2.0": version: 2.2.1 resolution: "ltgt@npm:2.2.1" @@ -10119,26 +9750,22 @@ __metadata: languageName: node linkType: hard -"make-fetch-happen@npm:^11.0.3": - version: 11.1.1 - resolution: "make-fetch-happen@npm:11.1.1" +"make-fetch-happen@npm:^13.0.0": + version: 13.0.0 + resolution: "make-fetch-happen@npm:13.0.0" dependencies: - agentkeepalive: ^4.2.1 - cacache: ^17.0.0 + "@npmcli/agent": ^2.0.0 + cacache: ^18.0.0 http-cache-semantics: ^4.1.1 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^5.0.0 + minipass: ^7.0.2 minipass-fetch: ^3.0.0 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 negotiator: ^0.6.3 promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 ssri: ^10.0.0 - checksum: 7268bf274a0f6dcf0343829489a4506603ff34bd0649c12058753900b0eb29191dce5dba12680719a5d0a983d3e57810f594a12f3c18494e93a1fbc6348a4540 + checksum: 7c7a6d381ce919dd83af398b66459a10e2fe8f4504f340d1d090d3fa3d1b0c93750220e1d898114c64467223504bd258612ba83efbc16f31b075cd56de24b4af languageName: node linkType: hard @@ -10355,6 +9982,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:9.0.3, minimatch@npm:^9.0.0, minimatch@npm:^9.0.1": + version: 9.0.3 + resolution: "minimatch@npm:9.0.3" + dependencies: + brace-expansion: ^2.0.1 + checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 + languageName: node + linkType: hard + "minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -10364,15 +10000,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.0, minimatch@npm:^9.0.1": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: ^2.0.1 - checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 - languageName: node - linkType: hard - "minimist-options@npm:4.1.0": version: 4.1.0 resolution: "minimist-options@npm:4.1.0" @@ -10391,27 +10018,27 @@ __metadata: languageName: node linkType: hard -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" dependencies: - minipass: ^3.0.0 - checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 + minipass: ^7.0.3 + checksum: b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 languageName: node linkType: hard "minipass-fetch@npm:^3.0.0": - version: 3.0.3 - resolution: "minipass-fetch@npm:3.0.3" + version: 3.0.4 + resolution: "minipass-fetch@npm:3.0.4" dependencies: encoding: ^0.1.13 - minipass: ^5.0.0 + minipass: ^7.0.3 minipass-sized: ^1.0.3 minizlib: ^2.1.2 dependenciesMeta: encoding: optional: true - checksum: af5ab2552a16fcf505d35fd7ffb84b57f4a0eeb269e6e1d9a2a75824dda48b36e527083250b7cca4a4def21d9544e2ade441e4730e233c0bc2133f6abda31e18 + checksum: af7aad15d5c128ab1ebe52e043bdf7d62c3c6f0cecb9285b40d7b395e1375b45dcdfd40e63e93d26a0e8249c9efd5c325c65575aceee192883970ff8cb11364a languageName: node linkType: hard @@ -10458,10 +10085,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": - version: 7.0.2 - resolution: "minipass@npm:7.0.2" - checksum: 46776de732eb7cef2c7404a15fb28c41f5c54a22be50d47b03c605bf21f5c18d61a173c0a20b49a97e7a65f78d887245066410642551e45fffe04e9ac9e325bc +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3": + version: 7.0.4 + resolution: "minipass@npm:7.0.4" + checksum: 87585e258b9488caf2e7acea242fd7856bbe9a2c84a7807643513a338d66f368c7d518200ad7b70a508664d408aa000517647b2930c259a8b1f9f0984f344a21 languageName: node linkType: hard @@ -10538,21 +10165,20 @@ __metadata: linkType: hard "moment@npm:^2.29.1": - version: 2.29.4 - resolution: "moment@npm:2.29.4" - checksum: 0ec3f9c2bcba38dc2451b1daed5daded747f17610b92427bebe1d08d48d8b7bdd8d9197500b072d14e326dd0ccf3e326b9e3d07c5895d3d49e39b6803b76e80e + version: 2.30.1 + resolution: "moment@npm:2.30.1" + checksum: 859236bab1e88c3e5802afcf797fc801acdbd0ee509d34ea3df6eea21eb6bcc2abd4ae4e4e64aa7c986aa6cba563c6e62806218e6412a765010712e5fa121ba6 languageName: node linkType: hard "mortice@npm:^3.0.1": - version: 3.0.1 - resolution: "mortice@npm:3.0.1" + version: 3.0.4 + resolution: "mortice@npm:3.0.4" dependencies: - nanoid: ^4.0.0 observable-webworkers: ^2.0.1 - p-queue: ^7.2.0 + p-queue: ^8.0.1 p-timeout: ^6.0.0 - checksum: a6b23c98bdea9a18f25d0431424f0c9df54e6af5f2ebe9d5752b50bccc1fa19e2559007d813f7fc14171a9253ebc60c8702f0cda51a57c8fd0ae420abde83761 + checksum: 64d63b6d724636e94f59a8f72208561d621f601707df17e8c1ea5e236bc3f208eae98609586898458851228733908028d61b1bf5a2b6db58bd2aa9c1f7e8166b languageName: node linkType: hard @@ -10563,7 +10189,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.0.0, ms@npm:^2.1.1": +"ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -10602,14 +10228,14 @@ __metadata: linkType: hard "msgpackr@npm:^1.9.9": - version: 1.9.9 - resolution: "msgpackr@npm:1.9.9" + version: 1.10.1 + resolution: "msgpackr@npm:1.10.1" dependencies: msgpackr-extract: ^3.0.2 dependenciesMeta: msgpackr-extract: optional: true - checksum: b63182d99f479d79f0d082fd2688ce7cf699b1aee71e20f28591c30b48743bb57868fdd72656759a892891072d186d864702c756434520709e8fe7e0d350a119 + checksum: e422d18b01051598b23701eebeb4b9e2c686b9c7826b20f564724837ba2b5cd4af74c91a549eaeaf8186645cc95e8196274a4a19442aa3286ac611b98069c194 languageName: node linkType: hard @@ -10621,27 +10247,25 @@ __metadata: linkType: hard "multiformats@npm:^12.0.1": - version: 12.0.1 - resolution: "multiformats@npm:12.0.1" - checksum: 227f5a0bb835e998d105028ffaa4cec944b6461c7b7f3ddc4f3aca22f6917ad59643302898c67af167a6f9d7abddcab094e501488664e2b9437f0b6a9b2ab68d + version: 12.1.3 + resolution: "multiformats@npm:12.1.3" + checksum: 1060488612f8e6729c600f47a8741b91aa6e7b807ce165eca3c8cf07ab7465d2d9b212415a9c18886938b9e35b30ea7b9ae19b5ab5122589c65063440643e6bb languageName: node linkType: hard -"nanoid@npm:^3.3.6": - version: 3.3.6 - resolution: "nanoid@npm:3.3.6" - bin: - nanoid: bin/nanoid.cjs - checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 +"multiformats@npm:^13.0.0": + version: 13.0.1 + resolution: "multiformats@npm:13.0.1" + checksum: 63e5d6ee2c2a1d1e8fbd4b8c76fa41cf3d8204ceed1d57bc44cb30ff3d06b880ad58c3de52ae6d4397a662a6f1e3285dae74ee5d445fd1597516e1baec96d22a languageName: node linkType: hard -"nanoid@npm:^4.0.0": - version: 4.0.2 - resolution: "nanoid@npm:4.0.2" +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" bin: - nanoid: bin/nanoid.js - checksum: 747c399cea4664dd0be1d0ec498ffd1ef8f1f5221676fc8b577e3f46f66d9afcddb9595d63d19a2e78d0bc6cc33984f65e66bf1682c850b9e26288883d96b53f + nanoid: bin/nanoid.cjs + checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 languageName: node linkType: hard @@ -10652,22 +10276,6 @@ __metadata: languageName: node linkType: hard -"native-fetch@npm:^4.0.2": - version: 4.0.2 - resolution: "native-fetch@npm:4.0.2" - peerDependencies: - undici: "*" - checksum: 11e6d075aa03d40665a5fc438c56b535622fb4ee98eb2b035277c5ba47733cb4c7bc3ddb45e5ab8154869b509fc18ca1c0188ab271139ae89db14f9f552fc064 - languageName: node - linkType: hard - -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 - languageName: node - linkType: hard - "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -10720,8 +10328,8 @@ __metadata: linkType: hard "node-fetch@npm:^2.6.12": - version: 2.6.12 - resolution: "node-fetch@npm:2.6.12" + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" dependencies: whatwg-url: ^5.0.0 peerDependencies: @@ -10729,7 +10337,7 @@ __metadata: peerDependenciesMeta: encoding: optional: true - checksum: 3bc1655203d47ee8e313c0d96664b9673a3d4dd8002740318e9d27d14ef306693a4b2ef8d6525775056fd912a19e23f3ac0d7111ad8925877b7567b29a625592 + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 languageName: node linkType: hard @@ -10776,34 +10384,33 @@ __metadata: linkType: hard "node-gyp-build@npm:^4.3.0": - version: 4.6.0 - resolution: "node-gyp-build@npm:4.6.0" + version: 4.8.0 + resolution: "node-gyp-build@npm:4.8.0" bin: node-gyp-build: bin.js node-gyp-build-optional: optional.js node-gyp-build-test: build-test.js - checksum: 25d78c5ef1f8c24291f4a370c47ba52fcea14f39272041a90a7894cd50d766f7c8cb8fb06c0f42bf6f69b204b49d9be3c8fc344aac09714d5bdb95965499eb15 + checksum: b82a56f866034b559dd3ed1ad04f55b04ae381b22ec2affe74b488d1582473ca6e7f85fccf52da085812d3de2b0bf23109e752a57709ac7b9963951c710fea40 languageName: node linkType: hard "node-gyp@npm:latest": - version: 9.4.0 - resolution: "node-gyp@npm:9.4.0" + version: 10.0.1 + resolution: "node-gyp@npm:10.0.1" dependencies: env-paths: ^2.2.0 exponential-backoff: ^3.1.1 - glob: ^7.1.4 + glob: ^10.3.10 graceful-fs: ^4.2.6 - make-fetch-happen: ^11.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 + make-fetch-happen: ^13.0.0 + nopt: ^7.0.0 + proc-log: ^3.0.0 semver: ^7.3.5 tar: ^6.1.2 - which: ^2.0.2 + which: ^4.0.0 bin: node-gyp: bin/node-gyp.js - checksum: 78b404e2e0639d64e145845f7f5a3cb20c0520cdaf6dda2f6e025e9b644077202ea7de1232396ba5bde3fee84cdc79604feebe6ba3ec84d464c85d407bb5da99 + checksum: 60a74e66d364903ce02049966303a57f898521d139860ac82744a5fdd9f7b7b3b61f75f284f3bfe6e6add3b8f1871ce305a1d41f775c7482de837b50c792223f languageName: node linkType: hard @@ -10814,10 +10421,10 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.13": - version: 2.0.13 - resolution: "node-releases@npm:2.0.13" - checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 59443a2f77acac854c42d321bf1b43dea0aef55cd544c6a686e9816a697300458d4e82239e2d794ea05f7bbbc8a94500332e2d3ac3f11f52e4b16cbe638b3c41 languageName: node linkType: hard @@ -10839,14 +10446,14 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" +"nopt@npm:^7.0.0": + version: 7.2.0 + resolution: "nopt@npm:7.2.0" dependencies: - abbrev: ^1.0.0 + abbrev: ^2.0.0 bin: nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + checksum: a9c0f57fb8cb9cc82ae47192ca2b7ef00e199b9480eed202482c962d61b59a7fbe7541920b2a5839a97b42ee39e288c0aed770e38057a608d7f579389dfde410 languageName: node linkType: hard @@ -10879,23 +10486,11 @@ __metadata: linkType: hard "npm-run-path@npm:^5.1.0": - version: 5.1.0 - resolution: "npm-run-path@npm:5.1.0" + version: 5.2.0 + resolution: "npm-run-path@npm:5.2.0" dependencies: path-key: ^4.0.0 - checksum: dc184eb5ec239d6a2b990b43236845332ef12f4e0beaa9701de724aa797fe40b6bbd0157fb7639d24d3ab13f5d5cf22d223a19c6300846b8126f335f788bee66 - languageName: node - linkType: hard - -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a + checksum: c5325e016014e715689c4014f7e0be16cc4cbf529f32a1723e511bc4689b5f823b704d2bca61ac152ce2bda65e0205dc8b3ba0ec0f5e4c3e162d302f6f5b9efb languageName: node linkType: hard @@ -10906,10 +10501,10 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db +"object-inspect@npm:^1.13.1, object-inspect@npm:^1.9.0": + version: 1.13.1 + resolution: "object-inspect@npm:1.13.1" + checksum: 7d9fa9221de3311dcb5c7c307ee5dc011cdd31dc43624b7c184b3840514e118e05ef0002be5388304c416c0eb592feb46e983db12577fc47e47d5752fbbfb61f languageName: node linkType: hard @@ -10921,48 +10516,48 @@ __metadata: linkType: hard "object.assign@npm:^4.1.4": - version: 4.1.4 - resolution: "object.assign@npm:4.1.4" + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 + call-bind: ^1.0.5 + define-properties: ^1.2.1 has-symbols: ^1.0.3 object-keys: ^1.1.1 - checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 + checksum: f9aeac0541661370a1fc86e6a8065eb1668d3e771f7dbb33ee54578201336c057b21ee61207a186dd42db0c62201d91aac703d20d12a79fc79c353eed44d4e25 languageName: node linkType: hard -"object.fromentries@npm:^2.0.6": - version: 2.0.6 - resolution: "object.fromentries@npm:2.0.6" +"object.fromentries@npm:^2.0.7": + version: 2.0.7 + resolution: "object.fromentries@npm:2.0.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 453c6d694180c0c30df451b60eaf27a5b9bca3fb43c37908fd2b78af895803dc631242bcf05582173afa40d8d0e9c96e16e8874b39471aa53f3ac1f98a085d85 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 7341ce246e248b39a431b87a9ddd331ff52a454deb79afebc95609f94b1f8238966cf21f52188f2a353f0fdf83294f32f1ebf1f7826aae915ebad21fd0678065 languageName: node linkType: hard -"object.groupby@npm:^1.0.0": - version: 1.0.0 - resolution: "object.groupby@npm:1.0.0" +"object.groupby@npm:^1.0.1": + version: 1.0.1 + resolution: "object.groupby@npm:1.0.1" dependencies: call-bind: ^1.0.2 define-properties: ^1.2.0 - es-abstract: ^1.21.2 + es-abstract: ^1.22.1 get-intrinsic: ^1.2.1 - checksum: 64b00b287d57580111c958e7ff375c9b61811fa356f2cf0d35372d43cab61965701f00fac66c19fd8f49c4dfa28744bee6822379c69a73648ad03e09fcdeae70 + checksum: d7959d6eaaba358b1608066fc67ac97f23ce6f573dc8fc661f68c52be165266fcb02937076aedb0e42722fdda0bdc0bbf74778196ac04868178888e9fd3b78b5 languageName: node linkType: hard -"object.values@npm:^1.1.6": - version: 1.1.6 - resolution: "object.values@npm:1.1.6" +"object.values@npm:^1.1.7": + version: 1.1.7 + resolution: "object.values@npm:1.1.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: f3e4ae4f21eb1cc7cebb6ce036d4c67b36e1c750428d7b7623c56a0db90edced63d08af8a316d81dfb7c41a3a5fa81b05b7cc9426e98d7da986b1682460f0777 languageName: node linkType: hard @@ -11025,18 +10620,6 @@ __metadata: languageName: node linkType: hard -"open@npm:^9.1.0": - version: 9.1.0 - resolution: "open@npm:9.1.0" - dependencies: - default-browser: ^4.0.0 - define-lazy-prop: ^3.0.0 - is-inside-container: ^1.0.0 - is-wsl: ^2.2.0 - checksum: 3993c0f61d51fed8ac290e99c9c3cf45d3b6cfb3e2aa2b74cafd312c3486c22fd81df16ac8f3ab91dd8a4e3e729a16fc2480cfc406c4833416cf908acf1ae7c9 - languageName: node - linkType: hard - "optionator@npm:^0.9.3": version: 0.9.3 resolution: "optionator@npm:0.9.3" @@ -11069,9 +10652,9 @@ __metadata: linkType: hard "ordered-binary@npm:^1.4.1": - version: 1.4.1 - resolution: "ordered-binary@npm:1.4.1" - checksum: 274940b4ef983562e11371c84415c265432a4e1337ab85f8e7669eeab6afee8f655c6c12ecee1cd121aaf399c32f5c781b0d50e460bd42da004eba16dcc66574 + version: 1.5.1 + resolution: "ordered-binary@npm:1.5.1" + checksum: ec4d3a6bd7f8c84afec9def1e599e7d460a45d11f94d07b16fdf62db4d2bc16405d79ef0277c2fdf86332fd2539761278981787d2ecf52376ade8b678104a0e6 languageName: node linkType: hard @@ -11136,23 +10719,34 @@ __metadata: languageName: node linkType: hard -"p-queue@npm:^7.2.0, p-queue@npm:^7.3.4": - version: 7.3.4 - resolution: "p-queue@npm:7.3.4" +"p-queue@npm:^7.3.4": + version: 7.4.1 + resolution: "p-queue@npm:7.4.1" dependencies: - eventemitter3: ^4.0.7 + eventemitter3: ^5.0.1 p-timeout: ^5.0.2 - checksum: a21b8a4dd75f64a4988e4468cc344d1b45132506ddd2c771932d3de446d108ee68713b629e0d3f0809c227bc10eafc613edde6ae741d9f60db89b6031e40921c + checksum: 1c6888aa994d399262a9fbdd49c7066f8359732397f7a42ecf03f22875a1d65899797b46413f97e44acc18dddafbcc101eb135c284714c931dbbc83c3967f450 languageName: node linkType: hard -"p-retry@npm:^5.0.0": - version: 5.1.2 - resolution: "p-retry@npm:5.1.2" +"p-queue@npm:^8.0.1": + version: 8.0.1 + resolution: "p-queue@npm:8.0.1" + dependencies: + eventemitter3: ^5.0.1 + p-timeout: ^6.1.2 + checksum: 84a27a5b1faf2dcc96b8c0e423c34b5984b241acc07353d3cc6d8d3d1dadefb250b4ec84ce278cb1c946466999c6bf2a36ff718a75810bad8e11c7ca47ce80f5 + languageName: node + linkType: hard + +"p-retry@npm:^6.0.0": + version: 6.2.0 + resolution: "p-retry@npm:6.2.0" dependencies: - "@types/retry": 0.12.1 + "@types/retry": 0.12.2 + is-network-error: ^1.0.0 retry: ^0.13.1 - checksum: f063c08b1adc3cf7c01de01eb2dbda841970229f9f229c5167ebf4e2080d8a38b1f4e6eccefac74bca97cfaf4436d0a0eeb0b551175b26bc8b3116195f61bba8 + checksum: 6003573c559ee812329c9c3ede7ba12a783fdc8dd70602116646e850c920b4597dc502fe001c3f9526fca4e93275045db7a27341c458e51db179c1374a01ac44 languageName: node linkType: hard @@ -11227,7 +10821,7 @@ __metadata: languageName: node linkType: hard -"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.5": +"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.6": version: 5.1.6 resolution: "parse-asn1@npm:5.1.6" dependencies: @@ -11422,25 +11016,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.1.7, postcss@npm:^8.4.23": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" - dependencies: - nanoid: ^3.3.6 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea - languageName: node - linkType: hard - -"postcss@npm:^8.4.26": - version: 8.4.27 - resolution: "postcss@npm:8.4.27" +"postcss@npm:^8.1.7, postcss@npm:^8.4.23, postcss@npm:^8.4.27": + version: 8.4.33 + resolution: "postcss@npm:8.4.33" dependencies: - nanoid: ^3.3.6 + nanoid: ^3.3.7 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 1cdd0c298849df6cd65f7e646a3ba36870a37b65f55fd59d1a165539c263e9b4872a402bf4ed1ca1bc31f58b68b2835545e33ea1a23b161a1f8aa6d5ded81e78 + checksum: 6f98b2af4b76632a3de20c4f47bf0e984a1ce1a531cf11adcb0b1d63a6cbda0aae4165e578b66c32ca4879038e3eaad386a6be725a8fb4429c78e3c1ab858fe9 languageName: node linkType: hard @@ -11505,14 +11088,14 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.6.2": - version: 29.6.2 - resolution: "pretty-format@npm:29.6.2" +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": + version: 29.7.0 + resolution: "pretty-format@npm:29.7.0" dependencies: - "@jest/schemas": ^29.6.0 + "@jest/schemas": ^29.6.3 ansi-styles: ^5.0.0 react-is: ^18.0.0 - checksum: a0f972a44f959023c0df9cdfe9eed7540264d7f7ddf74667db8a5294444d5aa153fd47d20327df10ae86964e2ceec10e46ea06b1a5c9c12e02348b78c952c9fc + checksum: 032c1602383e71e9c0c02a01bbd25d6759d60e9c7cf21937dde8357aa753da348fcec5def5d1002c9678a8524d5fe099ad98861286550ef44de8808cc61e43b6 languageName: node linkType: hard @@ -11526,14 +11109,21 @@ __metadata: linkType: hard "private-ip@npm:^3.0.0": - version: 3.0.1 - resolution: "private-ip@npm:3.0.1" + version: 3.0.2 + resolution: "private-ip@npm:3.0.2" dependencies: "@chainsafe/is-ip": ^2.0.1 ip-regex: ^5.0.0 ipaddr.js: ^2.1.0 netmask: ^2.0.2 - checksum: 43eb0b61cc476d4adddebd3a44bc799abf57898edd6e5db8ba1cd25fb9b1211a4cf3428ba61cc961d683f979ddce5220849c33954a580c08269dafd778ac8085 + checksum: dc05f5a915827e09307ced6fcc9d8a40c6c1be7282aef2ffdfc0d6ce917735197fd5173fea92bbf16c776d46fd694070d1849ed58e785a4cbb587f9ffca0152e + languageName: node + linkType: hard + +"proc-log@npm:^3.0.0": + version: 3.0.0 + resolution: "proc-log@npm:3.0.0" + checksum: 02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02 languageName: node linkType: hard @@ -11585,35 +11175,13 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^7.0.0": - version: 7.2.4 - resolution: "protobufjs@npm:7.2.4" - dependencies: - "@protobufjs/aspromise": ^1.1.2 - "@protobufjs/base64": ^1.1.2 - "@protobufjs/codegen": ^2.0.4 - "@protobufjs/eventemitter": ^1.1.0 - "@protobufjs/fetch": ^1.1.0 - "@protobufjs/float": ^1.0.2 - "@protobufjs/inquire": ^1.1.0 - "@protobufjs/path": ^1.1.2 - "@protobufjs/pool": ^1.1.0 - "@protobufjs/utf8": ^1.1.0 - "@types/node": ">=13.7.0" - long: ^5.0.0 - checksum: a952cdf2a5e5250c16ae651b570849b6f5b20a5475c3eef63ffb290ad239aa2916adfc1cc676f7fc93c69f48113df268761c0c246f7f023118c85bdd1a170044 - languageName: node - linkType: hard - "protons-runtime@npm:^5.0.0": - version: 5.0.1 - resolution: "protons-runtime@npm:5.0.1" + version: 5.2.2 + resolution: "protons-runtime@npm:5.2.2" dependencies: - protobufjs: ^7.0.0 uint8arraylist: ^2.4.3 - peerDependencies: - uint8arraylist: ^2.3.2 - checksum: 08d14fb7ea57e6329765873bb7933189925cfd2a488419735fb2547b8075f06a34638bc3b95c24c803a6ac179b7b5cff9b0894b6adfa46c38b5b430424a77605 + uint8arrays: ^5.0.1 + checksum: b2c0c3612406eb49539e3f2be7e51bbb3333969b6c1052c8e2cf5cb3eb3aed86eb825eeecd3b5c579e02a545b658b90f046b7e06cc624a843130782bc8e22f6b languageName: node linkType: hard @@ -11676,41 +11244,43 @@ __metadata: linkType: hard "punycode@npm:^2.1.0": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2 languageName: node linkType: hard -"puppeteer-core@npm:21.3.5": - version: 21.3.5 - resolution: "puppeteer-core@npm:21.3.5" +"puppeteer-core@npm:21.9.0": + version: 21.9.0 + resolution: "puppeteer-core@npm:21.9.0" dependencies: - "@puppeteer/browsers": 1.7.1 - chromium-bidi: 0.4.28 + "@puppeteer/browsers": 1.9.1 + chromium-bidi: 0.5.4 cross-fetch: 4.0.0 debug: 4.3.4 - devtools-protocol: 0.0.1179426 - ws: 8.14.2 - checksum: c2e904e59c9d58ada08016ff893c6b574ab36848db8e0f214b6c02fef446cfa142d346384cb2bb49c39df45622caf6ef813e7cc10f613024e595aa4406fb77bc + devtools-protocol: 0.0.1232444 + ws: 8.16.0 + checksum: 7c92cc0bbbb33fc647ec7dde2902cca47732a5cba65bf95bd46f352c9275e30097ae26a42714d7b6407c83f1940bad82f42d8640e3051efb309fe47b8385ceea languageName: node linkType: hard "puppeteer@npm:^21.3.4": - version: 21.3.5 - resolution: "puppeteer@npm:21.3.5" + version: 21.9.0 + resolution: "puppeteer@npm:21.9.0" dependencies: - "@puppeteer/browsers": 1.7.1 - cosmiconfig: 8.3.6 - puppeteer-core: 21.3.5 - checksum: 0bb3f0f2dead30f4a18b94066d73e27a0ec418ba3e1b73fc882ba4b747405c91ee2592eef0137b984f26bca5e52007543ecd01d1ac843dd68b8d78489a296f69 + "@puppeteer/browsers": 1.9.1 + cosmiconfig: 9.0.0 + puppeteer-core: 21.9.0 + bin: + puppeteer: lib/esm/puppeteer/node/cli.js + checksum: 0cb28d29a183af04869022ff30632116be65f1f8ec4ba729cc36a22332aefee697909adc7c4a15ceae53fdf657c9450aa9b8d8eacab05535adf4972ef2e50038 languageName: node linkType: hard "pure-rand@npm:^6.0.0": - version: 6.0.2 - resolution: "pure-rand@npm:6.0.2" - checksum: 79de33876a4f515d759c48e98d00756bbd916b4ea260cc572d7adfa4b62cace9952e89f0241d0410214554503d25061140fe325c66f845213d2b1728ba8d413e + version: 6.0.4 + resolution: "pure-rand@npm:6.0.4" + checksum: e1c4e69f8bf7303e5252756d67c3c7551385cd34d94a1f511fe099727ccbab74c898c03a06d4c4a24a89b51858781057b83ebbfe740d984240cdc04fead36068 languageName: node linkType: hard @@ -11751,6 +11321,13 @@ __metadata: languageName: node linkType: hard +"race-signal@npm:^1.0.0, race-signal@npm:^1.0.1": + version: 1.0.2 + resolution: "race-signal@npm:1.0.2" + checksum: 01ea1f70059673cd239acbe9523eaf1649f3b02ec786b5266770d9b045018aa96e316150447f0a12e7b0f8aa02522deb23e7d3a2c3a58d37135c505f595f2e49 + languageName: node + linkType: hard + "randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" @@ -11770,10 +11347,10 @@ __metadata: languageName: node linkType: hard -"rate-limiter-flexible@npm:^2.3.11": - version: 2.4.2 - resolution: "rate-limiter-flexible@npm:2.4.2" - checksum: 039e58b664991963ba2668a83d0406a72e5822683103acbe416854deb92ed834b840ce6e0acfea35917d9b49685bd53946ae47435a9f5916c2e7550395dec9dc +"rate-limiter-flexible@npm:^3.0.0": + version: 3.0.6 + resolution: "rate-limiter-flexible@npm:3.0.6" + checksum: 65cf8edacde55b78255d5de0286b1297ec897fee128f4f18734f36a230297d75433fa599ea423f7726b61b8f8ebf108d66ee09e7155e37aa25f506015b5166a4 languageName: node linkType: hard @@ -11833,7 +11410,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0, readable-stream@npm:^3.6.2": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -11887,21 +11464,21 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.11": - version: 0.13.11 - resolution: "regenerator-runtime@npm:0.13.11" - checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38 languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.5.0": - version: 1.5.0 - resolution: "regexp.prototype.flags@npm:1.5.0" +"regexp.prototype.flags@npm:^1.5.1": + version: 1.5.1 + resolution: "regexp.prototype.flags@npm:1.5.1" dependencies: call-bind: ^1.0.2 define-properties: ^1.2.0 - functions-have-names: ^1.2.3 - checksum: c541687cdbdfff1b9a07f6e44879f82c66bbf07665f9a7544c5fd16acdb3ec8d1436caab01662d2fbcad403f3499d49ab0b77fbc7ef29ef961d98cc4bc9755b4 + set-function-name: ^2.0.0 + checksum: 869edff00288442f8d7fa4c9327f91d85f3b3acf8cbbef9ea7a220345cf23e9241b6def9263d2c1ebcf3a316b0aa52ad26a43a84aa02baca3381717b3e307f47 languageName: node linkType: hard @@ -12004,20 +11581,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.3": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 - languageName: node - linkType: hard - -"resolve@npm:^1.21.0": +"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.21.0, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -12040,20 +11604,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.3#~builtin": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" - dependencies: - is-core-module: ^2.12.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 - languageName: node - linkType: hard - -"resolve@patch:resolve@^1.21.0#~builtin": +"resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.21.0#~builtin, resolve@patch:resolve@^1.22.4#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -12128,9 +11679,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.25.2": - version: 3.27.0 - resolution: "rollup@npm:3.27.0" +"rollup@npm:^3.27.1": + version: 3.29.4 + resolution: "rollup@npm:3.29.4" dependencies: fsevents: ~2.3.2 dependenciesMeta: @@ -12138,16 +11689,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: f60c2c288d039dc14e1f6e7fd673b7fcb11928b5a781675791b37a741f63b7af110fc5d040d60d603175b6e03ff978bed83db018dd2ac542ef809fe1a5b32dae - languageName: node - linkType: hard - -"run-applescript@npm:^5.0.0": - version: 5.0.0 - resolution: "run-applescript@npm:5.0.0" - dependencies: - execa: ^5.0.0 - checksum: d00c2dbfa5b2d774de7451194b8b125f40f65fc183de7d9dcae97f57f59433586d3c39b9001e111c38bfa24c3436c99df1bb4066a2a0c90d39a8c4cd6889af77 + checksum: 8bb20a39c8d91130825159c3823eccf4dc2295c9a0a5c4ed851a5bf2167dbf24d9a29f23461a54c955e5506395e6cc188eafc8ab0e20399d7489fb33793b184e languageName: node linkType: hard @@ -12169,19 +11711,19 @@ __metadata: languageName: node linkType: hard -"safe-array-concat@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-array-concat@npm:1.0.0" +"safe-array-concat@npm:^1.0.1": + version: 1.1.0 + resolution: "safe-array-concat@npm:1.1.0" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.2.0 + call-bind: ^1.0.5 + get-intrinsic: ^1.2.2 has-symbols: ^1.0.3 isarray: ^2.0.5 - checksum: f43cb98fe3b566327d0c09284de2b15fb85ae964a89495c1b1a5d50c7c8ed484190f4e5e71aacc167e16231940079b326f2c0807aea633d47cc7322f40a6b57f + checksum: 5c71eaa999168ee7474929f1cd3aae80f486353a651a094d9968936692cf90aa065224929a6486dcda66334a27dce4250a83612f9e0fef6dced1a925d3ac7296 languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 @@ -12196,13 +11738,13 @@ __metadata: linkType: hard "safe-regex-test@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-regex-test@npm:1.0.0" + version: 1.0.2 + resolution: "safe-regex-test@npm:1.0.2" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 + call-bind: ^1.0.5 + get-intrinsic: ^1.2.2 is-regex: ^1.1.4 - checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 + checksum: 4af5ce05a2daa4f6d4bfd5a3c64fc33d6b886f6592122e93c0efad52f7147b9b605e5ffc03c269a1e3d1f8db2a23bc636628a961c9fd65bafdc09503330673fd languageName: node linkType: hard @@ -12241,9 +11783,9 @@ __metadata: linkType: hard "sax@npm:>=0.6.0": - version: 1.2.4 - resolution: "sax@npm:1.2.4" - checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe + version: 1.3.0 + resolution: "sax@npm:1.3.0" + checksum: 238ab3a9ba8c8f8aaf1c5ea9120386391f6ee0af52f1a6a40bbb6df78241dd05d782f2359d614ac6aae08c4c4125208b456548a6cf68625aa4fe178486e63ecd languageName: node linkType: hard @@ -12297,18 +11839,35 @@ __metadata: linkType: hard "serialize-javascript@npm:^6.0.1": - version: 6.0.1 - resolution: "serialize-javascript@npm:6.0.1" + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" dependencies: randombytes: ^2.1.0 - checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f + checksum: c4839c6206c1d143c0f80763997a361310305751171dd95e4b57efee69b8f6edd8960a0b7fbfc45042aadff98b206d55428aee0dc276efe54f100899c7fa8ab7 languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 +"set-function-length@npm:^1.1.1": + version: 1.2.0 + resolution: "set-function-length@npm:1.2.0" + dependencies: + define-data-property: ^1.1.1 + function-bind: ^1.1.2 + get-intrinsic: ^1.2.2 + gopd: ^1.0.1 + has-property-descriptors: ^1.0.1 + checksum: 63e34b45a2ff9abb419f52583481bf8ba597d33c0c85e56999085eb6078a0f7fbb4222051981c287feceeb358aa7789e7803cea2c82ac94c0ab37059596aff79 + languageName: node + linkType: hard + +"set-function-name@npm:^2.0.0": + version: 2.0.1 + resolution: "set-function-name@npm:2.0.1" + dependencies: + define-data-property: ^1.0.1 + functions-have-names: ^1.2.3 + has-property-descriptors: ^1.0.0 + checksum: 4975d17d90c40168eee2c7c9c59d023429f0a1690a89d75656306481ece0c3c1fb1ebcc0150ea546d1913e35fbd037bace91372c69e543e51fc5d1f31a9fa126 languageName: node linkType: hard @@ -12397,14 +11956,14 @@ __metadata: linkType: hard "shiki@npm:^0.14.1": - version: 0.14.3 - resolution: "shiki@npm:0.14.3" + version: 0.14.7 + resolution: "shiki@npm:0.14.7" dependencies: ansi-sequence-parser: ^1.1.0 jsonc-parser: ^3.2.0 vscode-oniguruma: ^1.7.0 vscode-textmate: ^8.0.0 - checksum: a4dd98e3b2a5dd8be207448f111ffb9ad2ed6c530f215714d8b61cbf91ec3edbabb09109b8ec58a26678aacd24e8161d5a9bc0c1fa1b4f64b27ceb180cbd0c89 + checksum: 2aec3b3519df977c4391df9e1825cb496e9a4d7e11395f05a0da77e4fa2f7c3d9d6e6ee94029ac699533017f2b25637ee68f6d39f05f311535c2704d0329b520 languageName: node linkType: hard @@ -12456,13 +12015,6 @@ __metadata: languageName: node linkType: hard -"slash@npm:^4.0.0": - version: 4.0.0 - resolution: "slash@npm:4.0.0" - checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d - languageName: node - linkType: hard - "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -12470,18 +12022,7 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" - dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.2": +"socks-proxy-agent@npm:^8.0.1, socks-proxy-agent@npm:^8.0.2": version: 8.0.2 resolution: "socks-proxy-agent@npm:8.0.2" dependencies: @@ -12492,7 +12033,7 @@ __metadata: languageName: node linkType: hard -"socks@npm:^2.6.2, socks@npm:^2.7.1": +"socks@npm:^2.7.1": version: 2.7.1 resolution: "socks@npm:2.7.1" dependencies: @@ -12543,6 +12084,13 @@ __metadata: languageName: node linkType: hard +"source-map@npm:^0.7.4": + version: 0.7.4 + resolution: "source-map@npm:0.7.4" + checksum: 01cc5a74b1f0e1d626a58d36ad6898ea820567e87f18dfc9d24a9843a351aaa2ec09b87422589906d6ff1deed29693e176194dc88bcae7c9a852dc74b311dbf5 + languageName: node + linkType: hard + "spawn-command@npm:0.0.2, spawn-command@npm:^0.0.2-1": version: 0.0.2 resolution: "spawn-command@npm:0.0.2" @@ -12561,9 +12109,9 @@ __metadata: linkType: hard "spdx-exceptions@npm:^2.1.0": - version: 2.3.0 - resolution: "spdx-exceptions@npm:2.3.0" - checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 + version: 2.4.0 + resolution: "spdx-exceptions@npm:2.4.0" + checksum: b1b650a8d94424473bf9629cf972c86a91c03cccc260f5c901bce0e4b92d831627fec28c9e0a1e9c34c5ebad0a12cf2eab887bec088e0a862abb9d720c2fd0a1 languageName: node linkType: hard @@ -12578,9 +12126,9 @@ __metadata: linkType: hard "spdx-license-ids@npm:^3.0.0": - version: 3.0.13 - resolution: "spdx-license-ids@npm:3.0.13" - checksum: 3469d85c65f3245a279fa11afc250c3dca96e9e847f2f79d57f466940c5bb8495da08a542646086d499b7f24a74b8d0b42f3fc0f95d50ff99af1f599f6360ad7 + version: 3.0.16 + resolution: "spdx-license-ids@npm:3.0.16" + checksum: 5cdaa85aaa24bd02f9353a2e357b4df0a4f205cb35655f3fd0a5674a4fb77081f28ffd425379214bc3be2c2b7593ce1215df6bcc75884aeee0a9811207feabe2 languageName: node linkType: hard @@ -12601,11 +12149,11 @@ __metadata: linkType: hard "ssri@npm:^10.0.0": - version: 10.0.4 - resolution: "ssri@npm:10.0.4" + version: 10.0.5 + resolution: "ssri@npm:10.0.5" dependencies: - minipass: ^5.0.0 - checksum: fb14da9f8a72b04eab163eb13a9dda11d5962cd2317f85457c4e0b575e9a6e0e3a6a87b5bf122c75cb36565830cd5f263fb457571bf6f1587eb5f95d095d6165 + minipass: ^7.0.3 + checksum: 0a31b65f21872dea1ed3f7c200d7bc1c1b91c15e419deca14f282508ba917cbb342c08a6814c7f68ca4ca4116dd1a85da2bbf39227480e50125a1ceffeecb750 languageName: node linkType: hard @@ -12676,20 +12224,13 @@ __metadata: languageName: node linkType: hard -"streamsearch@npm:^1.1.0": - version: 1.1.0 - resolution: "streamsearch@npm:1.1.0" - checksum: 1cce16cea8405d7a233d32ca5e00a00169cc0e19fbc02aa839959985f267335d435c07f96e5e0edd0eadc6d39c98d5435fb5bbbdefc62c41834eadc5622ad942 - languageName: node - linkType: hard - "streamx@npm:^2.15.0": - version: 2.15.1 - resolution: "streamx@npm:2.15.1" + version: 2.15.6 + resolution: "streamx@npm:2.15.6" dependencies: fast-fifo: ^1.1.0 queue-tick: ^1.0.1 - checksum: 6f2b4fed68caacd28efbd44d4264f5d3c2b81b0a5de14419333dac57f2075c49ae648df8d03db632a33587a6c8ab7cb9cdb4f9a2f8305be0c2cd79af35742b15 + checksum: 37a245f5cee4c33fcb8b018ccb935bad6eab423f05b0d14d018e63dbd2670bb109a69442e961a195b750c2c774f613c19476d11bd727d645eedb655d2dba234b languageName: node linkType: hard @@ -12710,7 +12251,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -12732,36 +12273,36 @@ __metadata: languageName: node linkType: hard -"string.prototype.trim@npm:^1.2.7": - version: 1.2.7 - resolution: "string.prototype.trim@npm:1.2.7" +"string.prototype.trim@npm:^1.2.8": + version: 1.2.8 + resolution: "string.prototype.trim@npm:1.2.8" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 05b7b2d6af63648e70e44c4a8d10d8cc457536df78b55b9d6230918bde75c5987f6b8604438c4c8652eb55e4fc9725d2912789eb4ec457d6995f3495af190c09 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 49eb1a862a53aba73c3fb6c2a53f5463173cb1f4512374b623bcd6b43ad49dd559a06fb5789bdec771a40fc4d2a564411c0a75d35fb27e76bbe738c211ecff07 languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimend@npm:1.0.6" +"string.prototype.trimend@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimend@npm:1.0.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 0fdc34645a639bd35179b5a08227a353b88dc089adf438f46be8a7c197fc3f22f8514c1c9be4629b3cd29c281582730a8cbbad6466c60f76b5f99cf2addb132e + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 2375516272fd1ba75992f4c4aa88a7b5f3c7a9ca308d963bcd5645adf689eba6f8a04ebab80c33e30ec0aefc6554181a3a8416015c38da0aa118e60ec896310c languageName: node linkType: hard -"string.prototype.trimstart@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimstart@npm:1.0.6" +"string.prototype.trimstart@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimstart@npm:1.0.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 89080feef416621e6ef1279588994305477a7a91648d9436490d56010a1f7adc39167cddac7ce0b9884b8cdbef086987c4dcb2960209f2af8bac0d23ceff4f41 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 13d0c2cb0d5ff9e926fa0bec559158b062eed2b68cd5be777ffba782c96b2b492944e47057274e064549b94dd27cf81f48b27a31fee8af5b574cff253e7eb613 languageName: node linkType: hard @@ -12875,9 +12416,9 @@ __metadata: languageName: node linkType: hard -"superagent@npm:^8.0.5": - version: 8.0.9 - resolution: "superagent@npm:8.0.9" +"superagent@npm:^8.1.2": + version: 8.1.2 + resolution: "superagent@npm:8.1.2" dependencies: component-emitter: ^1.3.0 cookiejar: ^2.1.4 @@ -12889,17 +12430,17 @@ __metadata: mime: 2.6.0 qs: ^6.11.0 semver: ^7.3.8 - checksum: 5d00cdc7ceb5570663da80604965750e6b1b8d7d7442b7791e285c62bcd8d578a8ead0242a2426432b59a255fb42eb3a196d636157538a1392e7b6c5f1624810 + checksum: f3601c5ccae34d5ba684a03703394b5d25931f4ae2e1e31a1de809f88a9400e997ece037f9accf148a21c408f950dc829db1e4e23576a7f9fe0efa79fd5c9d2f languageName: node linkType: hard "supertest@npm:^6.3.3": - version: 6.3.3 - resolution: "supertest@npm:6.3.3" + version: 6.3.4 + resolution: "supertest@npm:6.3.4" dependencies: methods: ^1.1.2 - superagent: ^8.0.5 - checksum: 38239e517f7ba62b7a139a79c5c48d55f8d67b5ff4b6e51d5b07732ca8bbc4a28ffa1b10916fbb403dd013a054dbf028edc5850057d9a43aecbff439d494673e + superagent: ^8.1.2 + checksum: 875c6fa7940f21e5be9bb646579cdb030d4057bf2da643e125e1f0480add1200395d2b17e10b8e54e1009efc63e047422501e9eb30e12828668498c0910f295f languageName: node linkType: hard @@ -12937,16 +12478,6 @@ __metadata: languageName: node linkType: hard -"synckit@npm:^0.8.5": - version: 0.8.5 - resolution: "synckit@npm:0.8.5" - dependencies: - "@pkgr/utils": ^2.3.1 - tslib: ^2.5.0 - checksum: 8a9560e5d8f3d94dc3cf5f7b9c83490ffa30d320093560a37b88f59483040771fd1750e76b9939abfbb1b5a23fd6dfbae77f6b338abffe7cae7329cd9b9bb86b - languageName: node - linkType: hard - "tapable@npm:^2.1.1, tapable@npm:^2.2.0": version: 2.2.1 resolution: "tapable@npm:2.2.1" @@ -12966,19 +12497,19 @@ __metadata: linkType: hard "tar-stream@npm:^3.1.5": - version: 3.1.6 - resolution: "tar-stream@npm:3.1.6" + version: 3.1.7 + resolution: "tar-stream@npm:3.1.7" dependencies: b4a: ^1.6.4 fast-fifo: ^1.2.0 streamx: ^2.15.0 - checksum: f3627f918581976e954ff03cb8d370551053796b82564f8c7ca8fac84c48e4d042026d0854fc222171a34ff9c682b72fae91be9c9b0a112d4c54f9e4f443e9c5 + checksum: 6393a6c19082b17b8dcc8e7fd349352bb29b4b8bfe1075912b91b01743ba6bb4298f5ff0b499a3bbaf82121830e96a1a59d4f21a43c0df339e54b01789cb8cc6 languageName: node linkType: hard "tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.15 - resolution: "tar@npm:6.1.15" + version: 6.2.0 + resolution: "tar@npm:6.2.0" dependencies: chownr: ^2.0.0 fs-minipass: ^2.0.0 @@ -12986,19 +12517,19 @@ __metadata: minizlib: ^2.1.1 mkdirp: ^1.0.3 yallist: ^4.0.0 - checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 + checksum: db4d9fe74a2082c3a5016630092c54c8375ff3b280186938cfd104f2e089c4fd9bad58688ef6be9cf186a889671bf355c7cda38f09bbf60604b281715ca57f5c languageName: node linkType: hard -"terser-webpack-plugin@npm:^5.3.7": - version: 5.3.9 - resolution: "terser-webpack-plugin@npm:5.3.9" +"terser-webpack-plugin@npm:^5.3.10": + version: 5.3.10 + resolution: "terser-webpack-plugin@npm:5.3.10" dependencies: - "@jridgewell/trace-mapping": ^0.3.17 + "@jridgewell/trace-mapping": ^0.3.20 jest-worker: ^27.4.5 schema-utils: ^3.1.1 serialize-javascript: ^6.0.1 - terser: ^5.16.8 + terser: ^5.26.0 peerDependencies: webpack: ^5.1.0 peerDependenciesMeta: @@ -13008,13 +12539,13 @@ __metadata: optional: true uglify-js: optional: true - checksum: 41705713d6f9cb83287936b21e27c658891c78c4392159f5148b5623f0e8c48559869779619b058382a4c9758e7820ea034695e57dc7c474b4962b79f553bc5f + checksum: bd6e7596cf815f3353e2a53e79cbdec959a1b0276f5e5d4e63e9d7c3c5bb5306df567729da287d1c7b39d79093e56863c569c42c6c24cc34c76aa313bd2cbcea languageName: node linkType: hard -"terser@npm:^5.16.8": - version: 5.19.2 - resolution: "terser@npm:5.19.2" +"terser@npm:^5.26.0": + version: 5.27.0 + resolution: "terser@npm:5.27.0" dependencies: "@jridgewell/source-map": ^0.3.3 acorn: ^8.8.2 @@ -13022,7 +12553,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: e059177775b4d4f4cff219ad89293175aefbd1b081252270444dc83e42a2c5f07824eb2a85eae6e22ef6eb7ef04b21af36dd7d1dd7cfb93912310e57d416a205 + checksum: c165052cfea061e8512e9b9ba42a098c2ff6382886ae122b040fd5b6153443070cc2dcb4862269f1669c09c716763e856125a355ff984aa72be525d6fffd8729 languageName: node linkType: hard @@ -13052,11 +12583,11 @@ __metadata: linkType: hard "thingies@npm:^1.11.1": - version: 1.12.0 - resolution: "thingies@npm:1.12.0" + version: 1.16.0 + resolution: "thingies@npm:1.16.0" peerDependencies: tslib: ^2 - checksum: 04b75d264e1880676fb9f400b2c0e069abdd00de1fa006d9daee527ad6d899828169fd46bb17e7cabf2802b7dbd64053106e29e7a7aa271659f5b41b3a11657f + checksum: 9afbe70a9777fc31ac2567d06c9f64511585437298948330c39c076c6bd54bae6a700dee4cf4074486ef26c83f51031241ef4f4309c386555fb016a93be8aa06 languageName: node linkType: hard @@ -13067,13 +12598,6 @@ __metadata: languageName: node linkType: hard -"titleize@npm:^3.0.0": - version: 3.0.0 - resolution: "titleize@npm:3.0.0" - checksum: 71fbbeabbfb36ccd840559f67f21e356e1d03da2915b32d2ae1a60ddcc13a124be2739f696d2feb884983441d159a18649e8d956648d591bdad35c430a6b6d28 - languageName: node - linkType: hard - "tmpl@npm:1.0.5": version: 1.0.5 resolution: "tmpl@npm:1.0.5" @@ -13144,11 +12668,11 @@ __metadata: linkType: hard "ts-api-utils@npm:^1.0.1": - version: 1.0.1 - resolution: "ts-api-utils@npm:1.0.1" + version: 1.0.3 + resolution: "ts-api-utils@npm:1.0.3" peerDependencies: typescript: ">=4.2.0" - checksum: 78794fc7270d295b36c1ac613465b5dc7e7226907a533125b30f177efef9dd630d4e503b00be31b44335eb2ebf9e136ebe97353f8fc5d383885d5fead9d54c09 + checksum: 441cc4489d65fd515ae6b0f4eb8690057add6f3b6a63a36073753547fb6ce0c9ea0e0530220a0b282b0eec535f52c4dfc315d35f8a4c9a91c0def0707a714ca6 languageName: node linkType: hard @@ -13235,23 +12759,24 @@ __metadata: linkType: hard "ts-loader@npm:^9.4.4": - version: 9.4.4 - resolution: "ts-loader@npm:9.4.4" + version: 9.5.1 + resolution: "ts-loader@npm:9.5.1" dependencies: chalk: ^4.1.0 enhanced-resolve: ^5.0.0 micromatch: ^4.0.0 semver: ^7.3.4 + source-map: ^0.7.4 peerDependencies: typescript: "*" webpack: ^5.0.0 - checksum: 8e5e6b839b0edfa40d2156c880d88ccab58226894ea5978221bc48c7db3215e2e856bfd0093f148e925a2befc42d6c94cafa9a994a7da274541efaa916012b63 + checksum: 7cf396e656d905388ea2a9b5e82f16d3c955fda8d3df2fbf219f4bee16ff50a3c995c44ae3e584634e9443f056cec70bb3151add3917ffb4588ecd7394bac0ec languageName: node linkType: hard "ts-node@npm:^10.9.1": - version: 10.9.1 - resolution: "ts-node@npm:10.9.1" + version: 10.9.2 + resolution: "ts-node@npm:10.9.2" dependencies: "@cspotcode/source-map-support": ^0.8.0 "@tsconfig/node10": ^1.0.7 @@ -13283,7 +12808,7 @@ __metadata: ts-node-script: dist/bin-script.js ts-node-transpile-only: dist/bin-transpile.js ts-script: dist/bin-script-deprecated.js - checksum: 090adff1302ab20bd3486e6b4799e90f97726ed39e02b39e566f8ab674fd5bd5f727f43615debbfc580d33c6d9d1c6b1b3ce7d8e3cca3e20530a145ffa232c35 + checksum: fde256c9073969e234526e2cfead42591b9a2aec5222bac154b0de2fa9e4ceb30efcd717ee8bc785a56f3a119bdd5aa27b333d9dbec94ed254bd26f8944c67ac languageName: node linkType: hard @@ -13303,15 +12828,15 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.10.1, tsconfig-paths@npm:^3.14.2": - version: 3.14.2 - resolution: "tsconfig-paths@npm:3.14.2" +"tsconfig-paths@npm:^3.10.1, tsconfig-paths@npm:^3.15.0": + version: 3.15.0 + resolution: "tsconfig-paths@npm:3.15.0" dependencies: "@types/json5": ^0.0.29 json5: ^1.0.2 minimist: ^1.2.6 strip-bom: ^3.0.0 - checksum: a6162eaa1aed680537f93621b82399c7856afd10ec299867b13a0675e981acac4e0ec00896860480efc59fc10fd0b16fdc928c0b885865b52be62cadac692447 + checksum: 59f35407a390d9482b320451f52a411a256a130ff0e7543d18c6f20afab29ac19fbe55c360a93d6476213cc335a4d76ce90f67df54c4e9037f7d240920832201 languageName: node linkType: hard @@ -13329,20 +12854,13 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1": +"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0": - version: 2.6.1 - resolution: "tslib@npm:2.6.1" - checksum: b0d176d176487905b66ae4d5856647df50e37beea7571c53b8d10ba9222c074b81f1410fb91da13debaf2cbc970663609068bdebafa844ea9d69b146527c38fe - languageName: node - linkType: hard - "tsscmp@npm:1.0.6": version: 1.0.6 resolution: "tsscmp@npm:1.0.6" @@ -13513,12 +13031,12 @@ __metadata: linkType: hard "typescript@npm:^5.0.4": - version: 5.1.6 - resolution: "typescript@npm:5.1.6" + version: 5.3.3 + resolution: "typescript@npm:5.3.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: b2f2c35096035fe1f5facd1e38922ccb8558996331405eb00a5111cc948b2e733163cc22fab5db46992aba7dd520fff637f2c1df4996ff0e134e77d3249a7350 + checksum: 2007ccb6e51bbbf6fde0a78099efe04dc1c3dfbdff04ca3b6a8bc717991862b39fd6126c0c3ebf2d2d98ac5e960bcaa873826bb2bb241f14277034148f41f6a2 languageName: node linkType: hard @@ -13543,61 +13061,49 @@ __metadata: linkType: hard "typescript@patch:typescript@^5.0.4#~builtin": - version: 5.1.6 - resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071" + version: 5.3.3 + resolution: "typescript@patch:typescript@npm%3A5.3.3#~builtin::version=5.3.3&hash=f3b441" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: f53bfe97f7c8b2b6d23cf572750d4e7d1e0c5fff1c36d859d0ec84556a827b8785077bc27676bf7e71fae538e517c3ecc0f37e7f593be913d884805d931bc8be - languageName: node - linkType: hard - -"uint8-varint@npm:^1.0.1, uint8-varint@npm:^1.0.2": - version: 1.0.6 - resolution: "uint8-varint@npm:1.0.6" - dependencies: - byte-access: ^1.0.0 - longbits: ^1.1.0 - uint8arraylist: ^2.0.0 - uint8arrays: ^4.0.2 - checksum: 9d97312b9d032cc20976c3d9ea9e7548bc761a5f4483156e349d5dcd9ffed7c71f597dc564591cbe93816ee39d258751dee2efa6b43859d3662c83ad1cf6cd1a + checksum: f61375590b3162599f0f0d5b8737877ac0a7bc52761dbb585d67e7b8753a3a4c42d9a554c4cc929f591ffcf3a2b0602f65ae3ce74714fd5652623a816862b610 languageName: node linkType: hard "uint8-varint@npm:^2.0.0, uint8-varint@npm:^2.0.1": - version: 2.0.1 - resolution: "uint8-varint@npm:2.0.1" + version: 2.0.3 + resolution: "uint8-varint@npm:2.0.3" dependencies: uint8arraylist: ^2.0.0 - uint8arrays: ^4.0.2 - checksum: b03431e7fb87224726524b6dcc4ac0ff2c61c122134be0b16394c04bac4a3b59328800f302e3d3df7715bdb676b2e1fd0a17332cf6dbdb148cbb9f81332cedef + uint8arrays: ^5.0.0 + checksum: 8c20b02f803ade88d3aad0c01368e8bfebedca3cb43f2d74347f32b92a219ab734b8df4bb0dee5540261de984896ef4ffb3c58e83b200d4b1d01a7e3f7757dee languageName: node linkType: hard -"uint8arraylist@npm:^2.0.0, uint8arraylist@npm:^2.4.1, uint8arraylist@npm:^2.4.3": - version: 2.4.3 - resolution: "uint8arraylist@npm:2.4.3" +"uint8arraylist@npm:^2.0.0, uint8arraylist@npm:^2.4.1, uint8arraylist@npm:^2.4.3, uint8arraylist@npm:^2.4.7": + version: 2.4.8 + resolution: "uint8arraylist@npm:2.4.8" dependencies: - uint8arrays: ^4.0.2 - checksum: 95225fe2b8f6a4d8919b6c8e3dcff32ced35a08a53efaef757a50bc0082fb5b91f09e7e46f0d1c234243899930f7cb02ef9eb44b97ce03e2381d416de15e16c9 + uint8arrays: ^5.0.1 + checksum: 8259124cf5c7acd29edeed346489d898f3eb12f129dadedb1c263ad8d637e1a2f689968934a94c16804e39f6e8765178507be6d7b3c3c6b67147ad7546d34186 languageName: node linkType: hard -"uint8arrays@npm:^4.0.2": - version: 4.0.4 - resolution: "uint8arrays@npm:4.0.4" +"uint8arrays@npm:^4.0.4, uint8arrays@npm:^4.0.6": + version: 4.0.10 + resolution: "uint8arrays@npm:4.0.10" dependencies: - multiformats: ^11.0.0 - checksum: 49b2f53cf41aecd18b4623eea71d4e32fbcc572341cc687bb3e6e3372122b022079b2f0beca7c21648b1bd8a019ee596c71861043babc677e5c74773071e5d55 + multiformats: ^12.0.1 + checksum: 784677a00f67d18d3aaaf441422b4055576e1ab76dbf276e474b86c91ddb95945ac1cc95a97979ab1f3b3c9a0ebeea74dd803ec6056adbd1ee6ef2f231f00f97 languageName: node linkType: hard -"uint8arrays@npm:^4.0.4, uint8arrays@npm:^4.0.6": - version: 4.0.6 - resolution: "uint8arrays@npm:4.0.6" +"uint8arrays@npm:^5.0.0, uint8arrays@npm:^5.0.1": + version: 5.0.1 + resolution: "uint8arrays@npm:5.0.1" dependencies: - multiformats: ^12.0.1 - checksum: 0d55d74fe8d791ee24396bf6175ffe8ff73aae763cfaca5bf774e43315ee57bc69cc3af854de5e7b20bc7e6b7bde731f73a478bc43c295ea8115bff8a49621e0 + multiformats: ^13.0.0 + checksum: 29b27d41e1b5fe2b3de0ce502556e9ac7caabf53c0a40f27d3654c4cb08f06913b14b7722325a1a4287664d15938abf48dd987340d966ca61c2daa40030b5f82 languageName: node linkType: hard @@ -13623,12 +13129,10 @@ __metadata: languageName: node linkType: hard -"undici@npm:^5.12.0": - version: 5.22.1 - resolution: "undici@npm:5.22.1" - dependencies: - busboy: ^1.6.0 - checksum: 048a3365f622be44fb319316cedfaa241c59cf7f3368ae7667a12323447e1822e8cc3d00f6956c852d1478a6fde1cbbe753f49e05f2fdaed229693e716ebaf35 +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 3192ef6f3fd5df652f2dc1cd782b49d6ff14dc98e5dced492aa8a8c65425227da5da6aafe22523c67f035a272c599bb89cfe803c1db6311e44bed3042fc25487 languageName: node linkType: hard @@ -13665,9 +13169,9 @@ __metadata: linkType: hard "universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 languageName: node linkType: hard @@ -13678,13 +13182,6 @@ __metadata: languageName: node linkType: hard -"untildify@npm:^4.0.0": - version: 4.0.0 - resolution: "untildify@npm:4.0.0" - checksum: 39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9 - languageName: node - linkType: hard - "unzipit@npm:^1.4.3": version: 1.4.3 resolution: "unzipit@npm:1.4.3" @@ -13701,9 +13198,9 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.11": - version: 1.0.11 - resolution: "update-browserslist-db@npm:1.0.11" +"update-browserslist-db@npm:^1.0.13": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" dependencies: escalade: ^3.1.1 picocolors: ^1.0.0 @@ -13711,7 +13208,7 @@ __metadata: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 + checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 languageName: node linkType: hard @@ -13773,13 +13270,13 @@ __metadata: linkType: hard "v8-to-istanbul@npm:^9.0.1": - version: 9.1.0 - resolution: "v8-to-istanbul@npm:9.1.0" + version: 9.2.0 + resolution: "v8-to-istanbul@npm:9.2.0" dependencies: "@jridgewell/trace-mapping": ^0.3.12 "@types/istanbul-lib-coverage": ^2.0.1 - convert-source-map: ^1.6.0 - checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 + convert-source-map: ^2.0.0 + checksum: 31ef98c6a31b1dab6be024cf914f235408cd4c0dc56a5c744a5eea1a9e019ba279e1b6f90d695b78c3186feed391ed492380ccf095009e2eb91f3d058f0b4491 languageName: node linkType: hard @@ -13793,13 +13290,6 @@ __metadata: languageName: node linkType: hard -"varint@npm:^6.0.0": - version: 6.0.0 - resolution: "varint@npm:6.0.0" - checksum: 7684113c9d497c01e40396e50169c502eb2176203219b96e1c5ac965a3e15b4892bd22b7e48d87148e10fffe638130516b6dbeedd0efde2b2d0395aa1772eea7 - languageName: node - linkType: hard - "vary@npm:^1.1.2": version: 1.1.2 resolution: "vary@npm:1.1.2" @@ -13830,35 +13320,34 @@ __metadata: linkType: hard "viem@npm:^1.2.5": - version: 1.5.0 - resolution: "viem@npm:1.5.0" + version: 1.21.4 + resolution: "viem@npm:1.21.4" dependencies: - "@adraffy/ens-normalize": 1.9.0 - "@noble/curves": 1.0.0 - "@noble/hashes": 1.3.0 - "@scure/bip32": 1.3.0 - "@scure/bip39": 1.2.0 - "@wagmi/chains": 1.6.0 - abitype: 0.9.3 - isomorphic-ws: 5.0.0 - ws: 8.12.0 + "@adraffy/ens-normalize": 1.10.0 + "@noble/curves": 1.2.0 + "@noble/hashes": 1.3.2 + "@scure/bip32": 1.3.2 + "@scure/bip39": 1.2.1 + abitype: 0.9.8 + isows: 1.0.3 + ws: 8.13.0 peerDependencies: typescript: ">=5.0.4" peerDependenciesMeta: typescript: optional: true - checksum: 28ff9e64a3076b339182a3bab5dc442222400da4c66d258bf35e961f9a2e555ba2b0f3b30bdb87f63142682530c25f0807113580fbf888f840930f39df4bd8e3 + checksum: c351fdea2d53d2d781ac73c964348b3b9fc5dd46f9eb53903e867705fc9e30a893cb9f2c8d7a00acdcdeca27d14eeebf976eed9f948c28c47018dc9211369117 languageName: node linkType: hard "vite@npm:^4.2.3": - version: 4.4.8 - resolution: "vite@npm:4.4.8" + version: 4.5.2 + resolution: "vite@npm:4.5.2" dependencies: esbuild: ^0.18.10 fsevents: ~2.3.2 - postcss: ^8.4.26 - rollup: ^3.25.2 + postcss: ^8.4.27 + rollup: ^3.27.1 peerDependencies: "@types/node": ">= 14" less: "*" @@ -13887,7 +13376,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: e8ffe688f8a7396b1357778f00cb06d1f3dadad200823c47a1955cf52774a0cbff5ac4d6a8f8d09e26c1d4e588e5815956f9eba02ae301e77a36c3d181a1bc86 + checksum: 9d1f84f703c2660aced34deee7f309278ed368880f66e9570ac115c793d91f7fffb80ab19c602b3c8bc1341fe23437d86a3fcca2a9ef82f7ef0cdac5a40d0c86 languageName: node linkType: hard @@ -13948,9 +13437,9 @@ __metadata: linkType: hard "web-streams-polyfill@npm:^3.0.3": - version: 3.2.1 - resolution: "web-streams-polyfill@npm:3.2.1" - checksum: b119c78574b6d65935e35098c2afdcd752b84268e18746606af149e3c424e15621b6f1ff0b42b2676dc012fc4f0d313f964b41a4b5031e525faa03997457da02 + version: 3.3.2 + resolution: "web-streams-polyfill@npm:3.3.2" + checksum: 0292f4113c1bda40d8e8ecebee39eb14cc2e2e560a65a6867980e394537a2645130e2c73f5ef6e641fd3697d2f71720ccf659aebaf69a9d5a773f653a0fdf39d languageName: node linkType: hard @@ -13994,12 +13483,13 @@ __metadata: linkType: hard "webpack-merge@npm:^5.7.3": - version: 5.9.0 - resolution: "webpack-merge@npm:5.9.0" + version: 5.10.0 + resolution: "webpack-merge@npm:5.10.0" dependencies: clone-deep: ^4.0.1 + flat: ^5.0.2 wildcard: ^2.0.0 - checksum: 64fe2c23aacc5f19684452a0e84ec02c46b990423aee6fcc5c18d7d471155bd14e9a6adb02bd3656eb3e0ac2532c8e97d69412ad14c97eeafe32fa6d10050872 + checksum: 1fe8bf5309add7298e1ac72fb3f2090e1dfa80c48c7e79fa48aa60b5961332c7d0d61efa8851acb805e6b91a4584537a347bc106e05e9aec87fa4f7088c62f2f languageName: node linkType: hard @@ -14011,17 +13501,17 @@ __metadata: linkType: hard "webpack@npm:^5.88.2": - version: 5.88.2 - resolution: "webpack@npm:5.88.2" + version: 5.90.0 + resolution: "webpack@npm:5.90.0" dependencies: "@types/eslint-scope": ^3.7.3 - "@types/estree": ^1.0.0 + "@types/estree": ^1.0.5 "@webassemblyjs/ast": ^1.11.5 "@webassemblyjs/wasm-edit": ^1.11.5 "@webassemblyjs/wasm-parser": ^1.11.5 acorn: ^8.7.1 acorn-import-assertions: ^1.9.0 - browserslist: ^4.14.5 + browserslist: ^4.21.10 chrome-trace-event: ^1.0.2 enhanced-resolve: ^5.15.0 es-module-lexer: ^1.2.1 @@ -14035,7 +13525,7 @@ __metadata: neo-async: ^2.6.2 schema-utils: ^3.2.0 tapable: ^2.1.1 - terser-webpack-plugin: ^5.3.7 + terser-webpack-plugin: ^5.3.10 watchpack: ^2.4.0 webpack-sources: ^3.2.3 peerDependenciesMeta: @@ -14043,7 +13533,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 79476a782da31a21f6dd38fbbd06b68da93baf6a62f0d08ca99222367f3b8668f5a1f2086b7bb78e23172e31fa6df6fa7ab09b25e827866c4fc4dc2b30443ce2 + checksum: 178a0e7e9e5b26264a19dd5fe554a3508a8afafc9cce972bfd4452b5128d0db1b37832f5e615be1cff1934f24da0de967929f199be2b3fe283ca1951f98ea3fe languageName: node linkType: hard @@ -14079,20 +13569,20 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.10, which-typed-array@npm:^1.1.11, which-typed-array@npm:^1.1.2": - version: 1.1.11 - resolution: "which-typed-array@npm:1.1.11" +"which-typed-array@npm:^1.1.11, which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.2": + version: 1.1.13 + resolution: "which-typed-array@npm:1.1.13" dependencies: available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 + call-bind: ^1.0.4 for-each: ^0.3.3 gopd: ^1.0.1 has-tostringtag: ^1.0.0 - checksum: 711ffc8ef891ca6597b19539075ec3e08bb9b4c2ca1f78887e3c07a977ab91ac1421940505a197758fb5939aa9524976d0a5bbcac34d07ed6faa75cedbb17206 + checksum: 3828a0d5d72c800e369d447e54c7620742a4cc0c9baf1b5e8c17e9b6ff90d8d861a3a6dd4800f1953dbf80e5e5cec954a289e5b4a223e3bee4aeb1f8c5f33309 languageName: node linkType: hard -"which@npm:^2.0.1, which@npm:^2.0.2": +"which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" dependencies: @@ -14103,12 +13593,14 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 languageName: node linkType: hard @@ -14134,21 +13626,21 @@ __metadata: linkType: hard "winston-transport@npm:^4.4.0, winston-transport@npm:^4.5.0": - version: 4.5.0 - resolution: "winston-transport@npm:4.5.0" + version: 4.6.0 + resolution: "winston-transport@npm:4.6.0" dependencies: logform: ^2.3.2 readable-stream: ^3.6.0 triple-beam: ^1.3.0 - checksum: a56e5678a80b88a73e77ed998fc6e19d0db19c989a356b137ec236782f2bf58ae4511b11c29163f99391fa4dc12102c7bc5738dcb6543f28877fa2819adc3ee9 + checksum: 19f06ebdbb57cb14cdd48a23145d418d3bbe538851053303f84f04a8a849bb530b78b1495a175059c1299f92945dc61d5421c4914fee32d9a41bc397d84f26d7 languageName: node linkType: hard "winston@npm:^3.10.0": - version: 3.10.0 - resolution: "winston@npm:3.10.0" + version: 3.11.0 + resolution: "winston@npm:3.11.0" dependencies: - "@colors/colors": 1.5.0 + "@colors/colors": ^1.6.0 "@dabh/diagnostics": ^2.0.2 async: ^3.2.3 is-stream: ^2.0.0 @@ -14159,7 +13651,7 @@ __metadata: stack-trace: 0.0.x triple-beam: ^1.3.0 winston-transport: ^4.5.0 - checksum: 47df0361220d12b46d1b3c98a1c380a3718321739d527a182ce7984fc20715e5b0b55db0bcd3fd076d1b1d3261903b890b053851cfd4bc028bda7951fa8ca2e0 + checksum: ca4454070f7a71b19f53c8c1765c59a013dab220edb49161b2e81917751d3e9edc3382430e4fb050feda04fb8463290ecab7cbc9240ec8d3d3b32a121849bbb0 languageName: node linkType: hard @@ -14217,9 +13709,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.14.2": - version: 8.14.2 - resolution: "ws@npm:8.14.2" +"ws@npm:8.13.0": + version: 8.13.0 + resolution: "ws@npm:8.13.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -14228,13 +13720,13 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b + checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c languageName: node linkType: hard -"ws@npm:^8.13.0": - version: 8.13.0 - resolution: "ws@npm:8.13.0" +"ws@npm:8.16.0, ws@npm:^8.13.0": + version: 8.16.0 + resolution: "ws@npm:8.16.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -14243,21 +13735,11 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c - languageName: node - linkType: hard - -"xml2js@npm:^0.5.0": - version: 0.5.0 - resolution: "xml2js@npm:0.5.0" - dependencies: - sax: ">=0.6.0" - xmlbuilder: ~11.0.0 - checksum: 1aa71d62e5bc2d89138e3929b9ea46459157727759cbc62ef99484b778641c0cd21fb637696c052d901a22f82d092a3e740a16b4ce218e81ac59b933535124ea + checksum: feb3eecd2bae82fa8a8beef800290ce437d8b8063bdc69712725f21aef77c49cb2ff45c6e5e7fce622248f9c7abaee506bae0a9064067ffd6935460c7357321b languageName: node linkType: hard -"xml2js@npm:^0.6.0": +"xml2js@npm:^0.6.0, xml2js@npm:^0.6.2": version: 0.6.2 resolution: "xml2js@npm:0.6.2" dependencies: @@ -14303,9 +13785,9 @@ __metadata: linkType: hard "yaml@npm:^2.1.3": - version: 2.3.1 - resolution: "yaml@npm:2.3.1" - checksum: 2c7bc9a7cd4c9f40d3b0b0a98e370781b68b8b7c4515720869aced2b00d92f5da1762b4ffa947f9e795d6cd6b19f410bd4d15fdd38aca7bd96df59bd9486fb54 + version: 2.3.4 + resolution: "yaml@npm:2.3.4" + checksum: e6d1dae1c6383bcc8ba11796eef3b8c02d5082911c6723efeeb5ba50fc8e881df18d645e64de68e421b577296000bea9c75d6d9097c2f6699da3ae0406c030d8 languageName: node linkType: hard @@ -14326,22 +13808,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:17.7.1": - version: 17.7.1 - resolution: "yargs@npm:17.7.1" - dependencies: - cliui: ^8.0.1 - escalade: ^3.1.1 - get-caller-file: ^2.0.5 - require-directory: ^2.1.1 - string-width: ^4.2.3 - y18n: ^5.0.5 - yargs-parser: ^21.1.1 - checksum: 3d8a43c336a4942bc68080768664aca85c7bd406f018bad362fd255c41c8f4e650277f42fd65d543fce99e084124ddafee7bbfc1a5c6a8fda4cec78609dcf8d4 - languageName: node - linkType: hard - -"yargs@npm:^17.3.1, yargs@npm:^17.7.2": +"yargs@npm:17.7.2, yargs@npm:^17.3.1, yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: diff --git a/yellow-paper/docs/public-vm/avm.md b/yellow-paper/docs/public-vm/avm.md index 60f06218ab6..680763fa15a 100644 --- a/yellow-paper/docs/public-vm/avm.md +++ b/yellow-paper/docs/public-vm/avm.md @@ -249,7 +249,7 @@ results.output = machineState.memory[instr.args.retOffset:instr.args.retOffset+i An exceptional halt is not explicitly triggered by an instruction but instead occurs when an exceptional condition is met. -When an exceptional halt occurs, the context is flagged as consuming all off its allocated gas and is marked as `reverted` with no output data, and then execution within the current context ends. +When an exceptional halt occurs, the context is flagged as consuming all of its allocated gas and is marked as `reverted` with no output data, and then execution within the current context ends. ``` machineState.l1GasLeft = 0 From 7a9f463d9e174b005e1b11d7aa786dbfb1ee8ab8 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 24 Jan 2024 03:12:21 +0000 Subject: [PATCH 4/9] feat: accured substate instructions --- .../src/avm/journal/journal.test.ts | 23 +++-- .../acir-simulator/src/avm/journal/journal.ts | 39 ++++---- .../src/avm/opcodes/accrued_substate.test.ts | 84 ++++++++++++++++++ .../src/avm/opcodes/accrued_substate.ts | 88 +++++++++++++++++++ 4 files changed, 203 insertions(+), 31 deletions(-) create mode 100644 yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.test.ts b/yarn-project/acir-simulator/src/avm/journal/journal.test.ts index 1d5d0d08671..58b0b3345b9 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.test.ts @@ -86,14 +86,14 @@ describe('journal', () => { describe('UTXOs', () => { it('Should maintain commitments', () => { const utxo = new Fr(1); - journal.writeCommitment(utxo); + journal.writeNoteHash(utxo); const journalUpdates = journal.flush(); - expect(journalUpdates.newCommitments).toEqual([utxo]); + expect(journalUpdates.newNoteHashes).toEqual([utxo]); }); it('Should maintain l1 messages', () => { - const utxo = new Fr(1); + const utxo = [new Fr(1)]; journal.writeL1Message(utxo); const journalUpdates = journal.flush(); @@ -123,16 +123,20 @@ describe('journal', () => { const valueT1 = new Fr(2); const commitment = new Fr(10); const commitmentT1 = new Fr(20); + const logs = [new Fr(1), new Fr(2)]; + const logsT1 = [new Fr(3), new Fr(4)]; journal.writeStorage(contractAddress, key, value); - journal.writeCommitment(commitment); - journal.writeL1Message(commitment); + journal.writeNoteHash(commitment); + journal.writeLog(logs); + journal.writeL1Message(logs); journal.writeNullifier(commitment); const journal1 = new AvmJournal(journal.hostStorage, journal); journal.writeStorage(contractAddress, key, valueT1); - journal.writeCommitment(commitmentT1); - journal.writeL1Message(commitmentT1); + journal.writeNoteHash(commitmentT1); + journal.writeLog(logsT1); + journal.writeL1Message(logsT1); journal.writeNullifier(commitmentT1); journal1.mergeWithParent(); @@ -143,8 +147,9 @@ describe('journal', () => { // Check that the UTXOs are merged const journalUpdates: JournalData = journal.flush(); - expect(journalUpdates.newCommitments).toEqual([commitment, commitmentT1]); - expect(journalUpdates.newL1Messages).toEqual([commitment, commitmentT1]); + expect(journalUpdates.newNoteHashes).toEqual([commitment, commitmentT1]); + expect(journalUpdates.newLogs).toEqual([logs, logsT1]); + expect(journalUpdates.newL1Messages).toEqual([logs, logsT1]); expect(journalUpdates.newNullifiers).toEqual([commitment, commitmentT1]); }); diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.ts b/yarn-project/acir-simulator/src/avm/journal/journal.ts index 4d5b92fec6b..da503f2b88f 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.ts @@ -7,11 +7,10 @@ import { HostStorage } from './host_storage.js'; * Data held within the journal */ export type JournalData = { - newCommitments: Fr[]; - - newL1Messages: Fr[]; - + newNoteHashes: Fr[]; newNullifiers: Fr[]; + newL1Messages: Fr[][]; + newLogs: Fr[][]; /** contract address -\> key -\> value */ storageWrites: Map>; }; @@ -34,11 +33,11 @@ export class AvmJournal { private storageReads: Map> = new Map(); // New written state - private newCommitments: Fr[] = []; + private newNoteHashes: Fr[] = []; private newNullifiers: Fr[] = []; - private newL1Message: Fr[] = []; - // New Substrate + // New Substate + private newL1Message: Fr[][] = []; private newLogs: Fr[][] = []; // contract address -> key -> value @@ -102,27 +101,22 @@ export class AvmJournal { return this.hostStorage.publicStateDb.storageRead(contractAddress, key); } - /** - - * @param commitment - - */ - public writeCommitment(commitment: Fr) { - this.newCommitments.push(commitment); + public writeNoteHash(noteHash: Fr) { + this.newNoteHashes.push(noteHash); } - /** - - * @param message - - */ - public writeL1Message(message: Fr) { + public writeL1Message(message: Fr[]) { this.newL1Message.push(message); } - /** - - * @param nullifier - - */ public writeNullifier(nullifier: Fr) { this.newNullifiers.push(nullifier); } + public writeLog(log: Fr[]) { + this.newLogs.push(log); + } + /** * Merge Journal into parent * - Utxo objects are concatenated @@ -136,7 +130,7 @@ export class AvmJournal { const incomingFlush = this.flush(); // Merge UTXOs - this.parentJournal.newCommitments = this.parentJournal.newCommitments.concat(incomingFlush.newCommitments); + this.parentJournal.newNoteHashes = this.parentJournal.newNoteHashes.concat(incomingFlush.newNoteHashes); this.parentJournal.newL1Message = this.parentJournal.newL1Message.concat(incomingFlush.newL1Messages); this.parentJournal.newNullifiers = this.parentJournal.newNullifiers.concat(incomingFlush.newNullifiers); @@ -150,9 +144,10 @@ export class AvmJournal { */ public flush(): JournalData { return { - newCommitments: this.newCommitments, - newL1Messages: this.newL1Message, + newNoteHashes: this.newNoteHashes, newNullifiers: this.newNullifiers, + newL1Messages: this.newL1Message, + newLogs: this.newLogs, storageWrites: this.storageWrites, }; } diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts new file mode 100644 index 00000000000..c12bf1e7570 --- /dev/null +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts @@ -0,0 +1,84 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { mock } from 'jest-mock-extended'; + +import { AvmMachineState } from '../avm_machine_state.js'; +import { initExecutionEnvironment } from '../fixtures/index.js'; +import { HostStorage } from '../journal/host_storage.js'; +import { AvmJournal } from '../journal/journal.js'; +import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, SendL2ToL1Message } from './accrued_substate.js'; +import { StaticCallStorageAlterError } from './storage.js'; + +describe('Accrued Substate', () => { + let journal: AvmJournal; + let machineState: AvmMachineState; + + beforeEach(async () => { + const hostStorage = mock(); + journal = new AvmJournal(hostStorage); + machineState = new AvmMachineState(initExecutionEnvironment()); + }); + + it('Should append a new note hash correctly', async () => { + const value = new Fr(69n); + machineState.writeMemory(0, value); + + await new EmitNoteHash(0).execute(machineState, journal); + + const journalState = journal.flush(); + expect(journalState.newNoteHashes).toEqual([value]); + }); + + it('Should append a new nullifier correctly', async () => { + const value = new Fr(69n); + machineState.writeMemory(0, value); + + await new EmitNullifier(0).execute(machineState, journal); + + const journalState = journal.flush(); + expect(journalState.newNullifiers).toEqual([value]); + }); + + it('Should append unencrypted logs correctly', async () => { + const startOffset = 0; + const length = 2; + + const values = [new Fr(69n), new Fr(420n)]; + machineState.writeMemoryChunk(0, values); + + await new EmitUnencryptedLog(startOffset, length).execute(machineState, journal); + + const journalState = journal.flush(); + expect(journalState.newLogs).toEqual([values]); + }); + + it('Should append l1 to l2 messages correctly', async () => { + const startOffset = 0; + const length = 2; + + const values = [new Fr(69n), new Fr(420n)]; + machineState.writeMemoryChunk(0, values); + + await new SendL2ToL1Message(startOffset, length).execute(machineState, journal); + + const journalState = journal.flush(); + expect(journalState.newLogs).toEqual([values]); + }); + + it('All substate instructions should fail within a static call', async () => { + const executionEnvironment = initExecutionEnvironment({ isStaticCall: true }); + machineState = new AvmMachineState(executionEnvironment); + + const instructions = [ + new EmitNoteHash(0), + new EmitNullifier(0), + new EmitUnencryptedLog(0, 1), + new SendL2ToL1Message(0, 1), + ]; + + for (const instruction of instructions) { + const inst = () => instruction.execute(machineState, journal); + await expect(inst()).rejects.toThrowError(StaticCallStorageAlterError); + } + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts index e69de29bb2d..71d2e41b599 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts @@ -0,0 +1,88 @@ +import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmJournal } from '../journal/journal.js'; +import { Instruction } from './instruction.js'; +import { StaticCallStorageAlterError } from './storage.js'; + +export class EmitNoteHash extends Instruction { + static type: string = 'EMITNOTEHASH'; + static numberOfOperands = 1; + + constructor(private noteHashOffset: number) { + super(); + } + + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + if (machineState.executionEnvironment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + + const noteHash = machineState.readMemory(this.noteHashOffset); + + journal.writeNoteHash(noteHash); + + this.incrementPc(machineState); + } +} + +export class EmitNullifier extends Instruction { + static type: string = 'EMITNULLIFIER'; + static numberOfOperands = 1; + + constructor(private nullifierOffset: number) { + super(); + } + + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + if (machineState.executionEnvironment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + + const nullifier = machineState.readMemory(this.nullifierOffset); + + journal.writeNullifier(nullifier); + + this.incrementPc(machineState); + } +} + +export class EmitUnencryptedLog extends Instruction { + static type: string = 'EMITUNENCRYPTEDLOG'; + static numberOfOperands = 2; + + constructor(private logOffset: number, private logSize: number) { + super(); + } + + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + if (machineState.executionEnvironment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + + const log = machineState.readMemoryChunk(this.logOffset, this.logSize); + + journal.writeLog(log); + + this.incrementPc(machineState); + } +} + +export class SendL2ToL1Message extends Instruction { + static type: string = 'EMITUNENCRYPTEDLOG'; + static numberOfOperands = 2; + + constructor(private msgOffset: number, private msgSize: number) { + super(); + } + + async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { + if (machineState.executionEnvironment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + + const msg = machineState.readMemoryChunk(this.msgOffset, this.msgSize); + + journal.writeLog(msg); + + this.incrementPc(machineState); + } +} From 0f8ce4edbd7302b738b095e3119bc44e0ca3a1c4 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 29 Jan 2024 21:50:05 +0000 Subject: [PATCH 5/9] fix: update ontop of HEAD --- .../src/avm/avm_memory_types.ts | 5 ++++ .../acir-simulator/src/avm/journal/journal.ts | 21 +++++++-------- .../src/avm/opcodes/accrued_substate.test.ts | 27 ++++++++++--------- .../src/avm/opcodes/accrued_substate.ts | 20 +++++++++++--- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts b/yarn-project/acir-simulator/src/avm/avm_memory_types.ts index 6967a58fd8f..953d6e84238 100644 --- a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/acir-simulator/src/avm/avm_memory_types.ts @@ -237,6 +237,11 @@ export class TaggedMemory { return this._mem.slice(offset, offset + size); } + public getSliceAs(offset: number, size: number): T[] { + assert(offset < TaggedMemory.MAX_MEMORY_SIZE); + return this._mem.slice(offset, offset + size) as T[]; + } + public getSliceTags(offset: number, size: number): TypeTag[] { assert(offset < TaggedMemory.MAX_MEMORY_SIZE); return this._mem.slice(offset, offset + size).map(TaggedMemory.getTag); diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.ts b/yarn-project/acir-simulator/src/avm/journal/journal.ts index da503f2b88f..cba50f2cc5d 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.ts @@ -37,7 +37,7 @@ export class AvmJournal { private newNullifiers: Fr[] = []; // New Substate - private newL1Message: Fr[][] = []; + private newL1Messages: Fr[][] = []; private newLogs: Fr[][] = []; // contract address -> key -> value @@ -106,7 +106,7 @@ export class AvmJournal { } public writeL1Message(message: Fr[]) { - this.newL1Message.push(message); + this.newL1Messages.push(message); } public writeNullifier(nullifier: Fr) { @@ -127,26 +127,25 @@ export class AvmJournal { throw new RootJournalCannotBeMerged(); } - const incomingFlush = this.flush(); - // Merge UTXOs - this.parentJournal.newNoteHashes = this.parentJournal.newNoteHashes.concat(incomingFlush.newNoteHashes); - this.parentJournal.newL1Message = this.parentJournal.newL1Message.concat(incomingFlush.newL1Messages); - this.parentJournal.newNullifiers = this.parentJournal.newNullifiers.concat(incomingFlush.newNullifiers); + this.parentJournal.newNoteHashes = this.parentJournal.newNoteHashes.concat(this.newNoteHashes); + this.parentJournal.newL1Messages = this.parentJournal.newL1Messages.concat(this.newL1Messages); + this.parentJournal.newNullifiers = this.parentJournal.newNullifiers.concat(this.newNullifiers); // Merge Public State - mergeContractMaps(this.parentJournal.storageWrites, incomingFlush.storageWrites); + mergeContractMaps(this.parentJournal.storageWrites, this.storageWrites); } - /** Access the current state of the journal + /** + * Access the current state of the journal * - * @returns a JournalData object that can be used to write to the storage + * @returns a JournalData object */ public flush(): JournalData { return { newNoteHashes: this.newNoteHashes, newNullifiers: this.newNullifiers, - newL1Messages: this.newL1Message, + newL1Messages: this.newL1Messages, newLogs: this.newLogs, storageWrites: this.storageWrites, }; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts index c12bf1e7570..4d35e334a05 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts @@ -1,5 +1,3 @@ -import { Fr } from '@aztec/foundation/fields'; - import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; @@ -8,20 +6,21 @@ import { HostStorage } from '../journal/host_storage.js'; import { AvmJournal } from '../journal/journal.js'; import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, SendL2ToL1Message } from './accrued_substate.js'; import { StaticCallStorageAlterError } from './storage.js'; +import { Field } from '../avm_memory_types.js'; describe('Accrued Substate', () => { let journal: AvmJournal; let machineState: AvmMachineState; - beforeEach(async () => { + beforeEach(() => { const hostStorage = mock(); journal = new AvmJournal(hostStorage); machineState = new AvmMachineState(initExecutionEnvironment()); }); it('Should append a new note hash correctly', async () => { - const value = new Fr(69n); - machineState.writeMemory(0, value); + const value = new Field(69n); + machineState.memory.set(0, value); await new EmitNoteHash(0).execute(machineState, journal); @@ -30,8 +29,8 @@ describe('Accrued Substate', () => { }); it('Should append a new nullifier correctly', async () => { - const value = new Fr(69n); - machineState.writeMemory(0, value); + const value = new Field(69n); + machineState.memory.set(0, value); await new EmitNullifier(0).execute(machineState, journal); @@ -41,10 +40,11 @@ describe('Accrued Substate', () => { it('Should append unencrypted logs correctly', async () => { const startOffset = 0; - const length = 2; - const values = [new Fr(69n), new Fr(420n)]; - machineState.writeMemoryChunk(0, values); + const values = [new Field(69n), new Field(420n), new Field(Field.MODULUS - 1n)]; + machineState.memory.setSlice(0, values); + + const length = values.length; await new EmitUnencryptedLog(startOffset, length).execute(machineState, journal); @@ -54,10 +54,11 @@ describe('Accrued Substate', () => { it('Should append l1 to l2 messages correctly', async () => { const startOffset = 0; - const length = 2; - const values = [new Fr(69n), new Fr(420n)]; - machineState.writeMemoryChunk(0, values); + const values = [new Field(69n), new Field(420n), new Field(Field.MODULUS - 1n)]; + machineState.memory.setSlice(0, values); + + const length = values.length; await new SendL2ToL1Message(startOffset, length).execute(machineState, journal); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts index 71d2e41b599..7423ad81ce5 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts @@ -1,7 +1,9 @@ +import { Fr } from '@aztec/foundation/fields'; import { AvmMachineState } from '../avm_machine_state.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; import { StaticCallStorageAlterError } from './storage.js'; +import { TypeTag } from '../avm_memory_types.js'; export class EmitNoteHash extends Instruction { static type: string = 'EMITNOTEHASH'; @@ -16,7 +18,8 @@ export class EmitNoteHash extends Instruction { throw new StaticCallStorageAlterError(); } - const noteHash = machineState.readMemory(this.noteHashOffset); + Instruction.checkTags(machineState, TypeTag.FIELD, this.noteHashOffset); + const noteHash = machineState.memory.getAs(this.noteHashOffset); journal.writeNoteHash(noteHash); @@ -37,7 +40,8 @@ export class EmitNullifier extends Instruction { throw new StaticCallStorageAlterError(); } - const nullifier = machineState.readMemory(this.nullifierOffset); + Instruction.checkTags(machineState, TypeTag.FIELD, this.nullifierOffset); + const nullifier = machineState.memory.getAs(this.nullifierOffset); journal.writeNullifier(nullifier); @@ -58,7 +62,11 @@ export class EmitUnencryptedLog extends Instruction { throw new StaticCallStorageAlterError(); } - const log = machineState.readMemoryChunk(this.logOffset, this.logSize); + // Check log tags are all fields + const offsets = Array.from({length: this.logSize}, (_, i) => this.logOffset + i); + Instruction.checkTags(machineState, TypeTag.FIELD, ...offsets); + + const log = machineState.memory.getSliceAs(this.logOffset, this.logSize); journal.writeLog(log); @@ -79,7 +87,11 @@ export class SendL2ToL1Message extends Instruction { throw new StaticCallStorageAlterError(); } - const msg = machineState.readMemoryChunk(this.msgOffset, this.msgSize); + // Check log tags are all fields + const offsets = Array.from({length: this.msgSize}, (_, i) => this.msgOffset + i); + Instruction.checkTags(machineState, TypeTag.FIELD, ...offsets); + + const msg = machineState.memory.getSliceAs(this.msgOffset, this.msgSize); journal.writeLog(msg); From 1e212500586fb409044088e807b27cab60bc5623 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 29 Jan 2024 21:50:32 +0000 Subject: [PATCH 6/9] fmt --- yarn-project/acir-simulator/src/avm/journal/journal.ts | 2 +- .../src/avm/opcodes/accrued_substate.test.ts | 2 +- .../acir-simulator/src/avm/opcodes/accrued_substate.ts | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.ts b/yarn-project/acir-simulator/src/avm/journal/journal.ts index cba50f2cc5d..6168ce2cdf2 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.ts +++ b/yarn-project/acir-simulator/src/avm/journal/journal.ts @@ -136,7 +136,7 @@ export class AvmJournal { mergeContractMaps(this.parentJournal.storageWrites, this.storageWrites); } - /** + /** * Access the current state of the journal * * @returns a JournalData object diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts index 4d35e334a05..b4b7ae2c8f0 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts @@ -1,12 +1,12 @@ import { mock } from 'jest-mock-extended'; import { AvmMachineState } from '../avm_machine_state.js'; +import { Field } from '../avm_memory_types.js'; import { initExecutionEnvironment } from '../fixtures/index.js'; import { HostStorage } from '../journal/host_storage.js'; import { AvmJournal } from '../journal/journal.js'; import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, SendL2ToL1Message } from './accrued_substate.js'; import { StaticCallStorageAlterError } from './storage.js'; -import { Field } from '../avm_memory_types.js'; describe('Accrued Substate', () => { let journal: AvmJournal; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts index 7423ad81ce5..b21acb8b7b2 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts @@ -1,9 +1,10 @@ import { Fr } from '@aztec/foundation/fields'; + import { AvmMachineState } from '../avm_machine_state.js'; +import { TypeTag } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; import { StaticCallStorageAlterError } from './storage.js'; -import { TypeTag } from '../avm_memory_types.js'; export class EmitNoteHash extends Instruction { static type: string = 'EMITNOTEHASH'; @@ -63,7 +64,7 @@ export class EmitUnencryptedLog extends Instruction { } // Check log tags are all fields - const offsets = Array.from({length: this.logSize}, (_, i) => this.logOffset + i); + const offsets = Array.from({ length: this.logSize }, (_, i) => this.logOffset + i); Instruction.checkTags(machineState, TypeTag.FIELD, ...offsets); const log = machineState.memory.getSliceAs(this.logOffset, this.logSize); @@ -88,7 +89,7 @@ export class SendL2ToL1Message extends Instruction { } // Check log tags are all fields - const offsets = Array.from({length: this.msgSize}, (_, i) => this.msgOffset + i); + const offsets = Array.from({ length: this.msgSize }, (_, i) => this.msgOffset + i); Instruction.checkTags(machineState, TypeTag.FIELD, ...offsets); const msg = machineState.memory.getSliceAs(this.msgOffset, this.msgSize); From 07012bc2b3a18903940e9c793ca77411d6387b22 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:03:21 +0000 Subject: [PATCH 7/9] chore: refactor tag check before cast to be tidier --- .../src/avm/opcodes/accrued_substate.ts | 6 ++--- .../src/avm/opcodes/instruction.ts | 23 +++++++++++++++---- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts index b21acb8b7b2..f6879ceed89 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts @@ -64,8 +64,7 @@ export class EmitUnencryptedLog extends Instruction { } // Check log tags are all fields - const offsets = Array.from({ length: this.logSize }, (_, i) => this.logOffset + i); - Instruction.checkTags(machineState, TypeTag.FIELD, ...offsets); + Instruction.checkTagsRange(machineState, TypeTag.FIELD, this.logOffset, this.logSize); const log = machineState.memory.getSliceAs(this.logOffset, this.logSize); @@ -89,8 +88,7 @@ export class SendL2ToL1Message extends Instruction { } // Check log tags are all fields - const offsets = Array.from({ length: this.msgSize }, (_, i) => this.msgOffset + i); - Instruction.checkTags(machineState, TypeTag.FIELD, ...offsets); + Instruction.checkTagsRange(machineState, TypeTag.FIELD, this.msgOffset, this.msgSize); const msg = machineState.memory.getSliceAs(this.msgOffset, this.msgSize); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts index cccef0861fe..434bfc257db 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts @@ -20,13 +20,26 @@ export abstract class Instruction { } static checkTags(machineState: AvmMachineState, tag: TypeTag, ...offsets: number[]) { - for (const off of offsets) { - if (machineState.memory.getTag(off) !== tag) { - const error = `Offset ${off} has tag ${TypeTag[machineState.memory.getTag(off)]}, expected ${TypeTag[tag]}`; - throw new InstructionExecutionError(error); - } + for (const offset of offsets) { + checkTag(machineState, tag, offset); } } + + static checkTagsRange(machineState: AvmMachineState, tag: TypeTag, startOffset: number, size: number) { + for (let offset = startOffset; offset < startOffset + size; offset++) { + checkTag(machineState, tag, offset); + } + } +} + +/** + * Checks that the memory at the given offset has the given tag. + */ +function checkTag(machineState: AvmMachineState, tag: TypeTag, offset: number) { + if (machineState.memory.getTag(offset) !== tag) { + const error = `Offset ${offset} has tag ${TypeTag[machineState.memory.getTag(offset)]}, expected ${TypeTag[tag]}`; + throw new InstructionExecutionError(error); + } } export class InstructionExecutionError extends Error { From dbd73078cc54ba92ea22feedccfcce00b3ff0282 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 29 Jan 2024 22:36:24 +0000 Subject: [PATCH 8/9] chore: use toFr rather than unsafe type casting --- .../acir-simulator/src/avm/avm_memory_types.ts | 5 +++++ .../src/avm/opcodes/accrued_substate.test.ts | 12 ++++++++---- .../src/avm/opcodes/accrued_substate.ts | 12 ++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts b/yarn-project/acir-simulator/src/avm/avm_memory_types.ts index 953d6e84238..8963276813b 100644 --- a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/acir-simulator/src/avm/avm_memory_types.ts @@ -16,6 +16,11 @@ export abstract class MemoryValue { // Use sparingly. public abstract toBigInt(): bigint; + + // To field + public toFr(): Fr { + return new Fr(this.toBigInt()); + } } export abstract class IntegralValue extends MemoryValue { diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts index b4b7ae2c8f0..fd24b23eda4 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts @@ -25,7 +25,8 @@ describe('Accrued Substate', () => { await new EmitNoteHash(0).execute(machineState, journal); const journalState = journal.flush(); - expect(journalState.newNoteHashes).toEqual([value]); + const expected = [value.toFr()]; + expect(journalState.newNoteHashes).toEqual(expected); }); it('Should append a new nullifier correctly', async () => { @@ -35,7 +36,8 @@ describe('Accrued Substate', () => { await new EmitNullifier(0).execute(machineState, journal); const journalState = journal.flush(); - expect(journalState.newNullifiers).toEqual([value]); + const expected = [value.toFr()]; + expect(journalState.newNullifiers).toEqual(expected); }); it('Should append unencrypted logs correctly', async () => { @@ -49,7 +51,8 @@ describe('Accrued Substate', () => { await new EmitUnencryptedLog(startOffset, length).execute(machineState, journal); const journalState = journal.flush(); - expect(journalState.newLogs).toEqual([values]); + const expected = values.map(v => v.toFr()); + expect(journalState.newLogs).toEqual([expected]); }); it('Should append l1 to l2 messages correctly', async () => { @@ -63,7 +66,8 @@ describe('Accrued Substate', () => { await new SendL2ToL1Message(startOffset, length).execute(machineState, journal); const journalState = journal.flush(); - expect(journalState.newLogs).toEqual([values]); + const expected = values.map(v => v.toFr()); + expect(journalState.newLogs).toEqual([expected]); }); it('All substate instructions should fail within a static call', async () => { diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts index f6879ceed89..160ef369430 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts @@ -1,5 +1,3 @@ -import { Fr } from '@aztec/foundation/fields'; - import { AvmMachineState } from '../avm_machine_state.js'; import { TypeTag } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/journal.js'; @@ -20,7 +18,7 @@ export class EmitNoteHash extends Instruction { } Instruction.checkTags(machineState, TypeTag.FIELD, this.noteHashOffset); - const noteHash = machineState.memory.getAs(this.noteHashOffset); + const noteHash = machineState.memory.get(this.noteHashOffset).toFr(); journal.writeNoteHash(noteHash); @@ -42,7 +40,7 @@ export class EmitNullifier extends Instruction { } Instruction.checkTags(machineState, TypeTag.FIELD, this.nullifierOffset); - const nullifier = machineState.memory.getAs(this.nullifierOffset); + const nullifier = machineState.memory.get(this.nullifierOffset).toFr(); journal.writeNullifier(nullifier); @@ -65,8 +63,7 @@ export class EmitUnencryptedLog extends Instruction { // Check log tags are all fields Instruction.checkTagsRange(machineState, TypeTag.FIELD, this.logOffset, this.logSize); - - const log = machineState.memory.getSliceAs(this.logOffset, this.logSize); + const log = machineState.memory.getSlice(this.logOffset, this.logSize).map(f => f.toFr()); journal.writeLog(log); @@ -89,8 +86,7 @@ export class SendL2ToL1Message extends Instruction { // Check log tags are all fields Instruction.checkTagsRange(machineState, TypeTag.FIELD, this.msgOffset, this.msgSize); - - const msg = machineState.memory.getSliceAs(this.msgOffset, this.msgSize); + const msg = machineState.memory.getSlice(this.msgOffset, this.msgSize).map(f => f.toFr()); journal.writeLog(msg); From 8cdc33c9ea2f78aa56d3b8ac600e14956cfb4a34 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 29 Jan 2024 23:26:22 +0000 Subject: [PATCH 9/9] remove typecheck --- .../src/avm/opcodes/accrued_substate.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts index 160ef369430..de54edaa0c7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts @@ -1,5 +1,4 @@ import { AvmMachineState } from '../avm_machine_state.js'; -import { TypeTag } from '../avm_memory_types.js'; import { AvmJournal } from '../journal/journal.js'; import { Instruction } from './instruction.js'; import { StaticCallStorageAlterError } from './storage.js'; @@ -17,9 +16,7 @@ export class EmitNoteHash extends Instruction { throw new StaticCallStorageAlterError(); } - Instruction.checkTags(machineState, TypeTag.FIELD, this.noteHashOffset); const noteHash = machineState.memory.get(this.noteHashOffset).toFr(); - journal.writeNoteHash(noteHash); this.incrementPc(machineState); @@ -39,9 +36,7 @@ export class EmitNullifier extends Instruction { throw new StaticCallStorageAlterError(); } - Instruction.checkTags(machineState, TypeTag.FIELD, this.nullifierOffset); const nullifier = machineState.memory.get(this.nullifierOffset).toFr(); - journal.writeNullifier(nullifier); this.incrementPc(machineState); @@ -61,10 +56,7 @@ export class EmitUnencryptedLog extends Instruction { throw new StaticCallStorageAlterError(); } - // Check log tags are all fields - Instruction.checkTagsRange(machineState, TypeTag.FIELD, this.logOffset, this.logSize); const log = machineState.memory.getSlice(this.logOffset, this.logSize).map(f => f.toFr()); - journal.writeLog(log); this.incrementPc(machineState); @@ -84,10 +76,7 @@ export class SendL2ToL1Message extends Instruction { throw new StaticCallStorageAlterError(); } - // Check log tags are all fields - Instruction.checkTagsRange(machineState, TypeTag.FIELD, this.msgOffset, this.msgSize); const msg = machineState.memory.getSlice(this.msgOffset, this.msgSize).map(f => f.toFr()); - journal.writeLog(msg); this.incrementPc(machineState);