Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro committed Apr 2, 2024
1 parent fb89f86 commit 41eeb0f
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 38 deletions.
69 changes: 56 additions & 13 deletions noir-projects/aztec-nr/aztec/src/initializer.nr
Original file line number Diff line number Diff line change
@@ -1,37 +1,80 @@
use dep::protocol_types::{
hash::{silo_nullifier, pedersen_hash}, constants::GENERATOR_INDEX__CONSTRUCTOR,
abis::function_selector::FunctionSelector
address::AztecAddress, hash::{silo_nullifier, pedersen_hash},
constants::GENERATOR_INDEX__CONSTRUCTOR, abis::function_selector::FunctionSelector
};

use crate::{
context::{PrivateContext, PublicContext, ContextInterface},
context::{PrivateContext, PublicContext, AvmContext, ContextInterface},
oracle::get_contract_instance::get_contract_instance,
oracle::get_contract_instance::get_contract_instance_avm,
history::nullifier_inclusion::prove_nullifier_inclusion
};

pub fn mark_as_initialized<TContext>(context: &mut TContext) where TContext: ContextInterface {
let init_nullifier = compute_unsiloed_contract_initialization_nullifier(*context);
pub fn mark_as_initialized_public(context: &mut PublicContext) {
mark_as_initialized(context);
}

pub fn mark_as_initialized_avm(context: &mut AvmContext) {
let init_nullifier = compute_unsiloed_contract_initialization_nullifier(context.this_address());
context.push_new_nullifier(init_nullifier, 0);
}

pub fn mark_as_initialized_private(context: &mut PrivateContext) {
mark_as_initialized(context);
}

fn mark_as_initialized<TContext>(context: &mut TContext) where TContext: ContextInterface {
let init_nullifier = compute_unsiloed_contract_initialization_nullifier((*context).this_address());
ContextInterface::push_new_nullifier(context, init_nullifier, 0);
}

pub fn assert_is_initialized<TContext>(context: &mut TContext) where TContext: ContextInterface {
let init_nullifier = compute_contract_initialization_nullifier(*context);
pub fn assert_is_initialized_public(context: &mut PublicContext) {
let init_nullifier = compute_contract_initialization_nullifier(context.this_address());
prove_nullifier_inclusion(init_nullifier, *context);
}

pub fn compute_contract_initialization_nullifier<TContext>(context: TContext) -> Field where TContext: ContextInterface {
let address = context.this_address();
pub fn assert_is_initialized_avm(context: &mut AvmContext) {
// FIXME: AVM simulator does not correctly handle nullifier siloing.
// let init_nullifier = compute_contract_initialization_nullifier(context.this_address());
let init_nullifier = compute_unsiloed_contract_initialization_nullifier(context.this_address());
assert(context.nullifier_exists(init_nullifier));
}

pub fn assert_is_initialized_private(context: &mut PrivateContext) {
let init_nullifier = compute_contract_initialization_nullifier(context.this_address());
prove_nullifier_inclusion(init_nullifier, *context);
}

fn compute_contract_initialization_nullifier(address: AztecAddress) -> Field {
silo_nullifier(
address,
compute_unsiloed_contract_initialization_nullifier(context)
compute_unsiloed_contract_initialization_nullifier(address)
)
}

pub fn compute_unsiloed_contract_initialization_nullifier<TContext>(context: TContext) -> Field where TContext: ContextInterface {
context.this_address().to_field()
fn compute_unsiloed_contract_initialization_nullifier(address: AztecAddress) -> Field {
address.to_field()
}

pub fn assert_initialization_matches_address_preimage_public(context: PublicContext) {
assert_initialization_matches_address_preimage(context);
}

pub fn assert_initialization_matches_address_preimage_avm(context: AvmContext) {
let address = context.this_address();
let instance = get_contract_instance_avm(address).unwrap();
let expected_init = compute_initialization_hash(context.selector(), context.get_args_hash());
assert(instance.initialization_hash == expected_init, "Initialization hash does not match");
assert(
(instance.deployer.is_zero()) | (instance.deployer == context.msg_sender()), "Initializer address is not the contract deployer"
);
}

pub fn assert_initialization_matches_address_preimage_private(context: PrivateContext) {
assert_initialization_matches_address_preimage(context);
}

pub fn assert_initialization_matches_address_preimage<TContext>(context: TContext) where TContext: ContextInterface {
fn assert_initialization_matches_address_preimage<TContext>(context: TContext) where TContext: ContextInterface {
let address = context.this_address();
let instance = get_contract_instance(address);
let expected_init = compute_initialization_hash(context.selector(), context.get_args_hash());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,11 @@ contract AvmTest {
/************************************************************************
* Storage
************************************************************************/
// FIX: calls unsupported getNullifierMembershipWitness.
// #[aztec(public-vm)]
// #[aztec(initializer)]
// fn constructor() {
// storage.immutable.initialize(42);
// }
#[aztec(public-vm)]
#[aztec(initializer)]
fn constructor() {
storage.immutable.initialize(42);
}

unconstrained fn view_storage_immutable() -> pub Field {
storage.immutable.read()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ contract StatefulTest {
use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote}};
use dep::aztec::{
deploy::deploy_contract as aztec_deploy_contract, context::{PublicContext, Context},
oracle::get_contract_instance::get_contract_instance, initializer::assert_is_initialized
oracle::get_contract_instance::get_contract_instance, initializer::assert_is_initialized_private
};

struct Storage {
Expand Down Expand Up @@ -45,7 +45,7 @@ contract StatefulTest {

#[aztec(private)]
fn destroy_and_create(recipient: AztecAddress, amount: Field) {
assert_is_initialized(&mut context);
assert_is_initialized_private(&mut context);
let sender = context.msg_sender();

let sender_notes = storage.notes.at(sender);
Expand Down
26 changes: 13 additions & 13 deletions noir/noir-repo/aztec_macros/src/transforms/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ pub fn transform_function(

// Add initialization check
if insert_init_check {
let init_check = create_init_check();
let init_check = create_init_check(ty);
func.def.body.statements.insert(0, init_check);
}

// Add assertion for initialization arguments and sender
if is_initializer {
func.def.body.statements.insert(0, create_assert_initializer());
func.def.body.statements.insert(0, create_assert_initializer(ty));
}

// Add access to the storage struct
Expand Down Expand Up @@ -85,7 +85,7 @@ pub fn transform_function(

// Before returning mark the contract as initialized
if is_initializer {
let mark_initialized = create_mark_as_initialized();
let mark_initialized = create_mark_as_initialized(ty);
func.def.body.statements.push(mark_initialized);
}

Expand Down Expand Up @@ -159,9 +159,10 @@ fn create_inputs(ty: &str) -> Param {
/// ```noir
/// assert_is_initialized(&mut context);
/// ```
fn create_init_check() -> Statement {
fn create_init_check(ty: &str) -> Statement {
let fname = format!("assert_is_initialized_{}", ty.to_case(Case::Snake));
make_statement(StatementKind::Expression(call(
variable_path(chained_dep!("aztec", "initializer", "assert_is_initialized")),
variable_path(chained_dep!("aztec", "initializer", &fname)),
vec![mutable_reference("context")],
)))
}
Expand All @@ -172,9 +173,10 @@ fn create_init_check() -> Statement {
/// ```noir
/// mark_as_initialized(&mut context);
/// ```
fn create_mark_as_initialized() -> Statement {
fn create_mark_as_initialized(ty: &str) -> Statement {
let fname = format!("mark_as_initialized_{}", ty.to_case(Case::Snake));
make_statement(StatementKind::Expression(call(
variable_path(chained_dep!("aztec", "initializer", "mark_as_initialized")),
variable_path(chained_dep!("aztec", "initializer", &fname)),
vec![mutable_reference("context")],
)))
}
Expand Down Expand Up @@ -205,13 +207,11 @@ fn create_internal_check(fname: &str) -> Statement {
/// ```noir
/// assert_initialization_matches_address_preimage(context);
/// ```
fn create_assert_initializer() -> Statement {
fn create_assert_initializer(ty: &str) -> Statement {
let fname =
format!("assert_initialization_matches_address_preimage_{}", ty.to_case(Case::Snake));
make_statement(StatementKind::Expression(call(
variable_path(chained_dep!(
"aztec",
"initializer",
"assert_initialization_matches_address_preimage"
)),
variable_path(chained_dep!("aztec", "initializer", &fname)),
vec![variable("context")],
)))
}
Expand Down
7 changes: 3 additions & 4 deletions yarn-project/end-to-end/src/e2e_avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ describe('e2e_avm_simulator', () => {
}, 50_000);

describe('Storage', () => {
// FIX: Enable once the contract function works.
// it('Read immutable (initialized) storage (Field)', async () => {
// expect(await avmContact.methods.view_storage_immutable().view()).toEqual(42n);
// });
it('Read immutable (initialized) storage (Field)', async () => {
expect(await avmContact.methods.view_storage_immutable().view()).toEqual(42n);
});

it('Modifies storage (Field)', async () => {
await avmContact.methods.set_storage_single(20n).send().wait();
Expand Down
7 changes: 7 additions & 0 deletions yarn-project/simulator/src/avm/journal/nullifiers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { siloNullifier } from '@aztec/circuits.js/hash';
import { Fr } from '@aztec/foundation/fields';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';

import type { CommitmentsDB } from '../../index.js';

Expand All @@ -9,6 +10,8 @@ import type { CommitmentsDB } from '../../index.js';
* When a contract call completes, its cached nullifier set can be merged into its parent's.
*/
export class Nullifiers {
private log: DebugLogger = createDebugLogger('aztec:nullifiers');

/** Cached nullifiers. */
private cache: NullifierCache;
/** Parent's nullifier cache. Checked on cache-miss. */
Expand Down Expand Up @@ -41,16 +44,19 @@ export class Nullifiers {
): Promise<[/*exists=*/ boolean, /*isPending=*/ boolean, /*leafIndex=*/ Fr]> {
// First check this cache
let existsAsPending = this.cache.exists(storageAddress, nullifier);
this.log(`Checking nullifier ${nullifier} at contract ${storageAddress} in cache: ${existsAsPending}`);
// Then check parent's cache
if (!existsAsPending && this.parentCache) {
existsAsPending = this.parentCache?.exists(storageAddress, nullifier);
}
this.log(`Checking nullifier ${nullifier} at contract ${storageAddress} in parent cache: ${existsAsPending}`);
// Finally try the host's Aztec state (a trip to the database)
// If the value is found in the database, it will be associated with a leaf index!
let leafIndex: bigint | undefined = undefined;
if (!existsAsPending) {
// silo the nullifier before checking for its existence in the host
leafIndex = await this.hostNullifiers.getNullifierIndex(siloNullifier(storageAddress, nullifier));
this.log(`Checking nullifier index ${siloNullifier(storageAddress, nullifier)} in host: ${leafIndex}`);
}
const exists = existsAsPending || leafIndex !== undefined;
leafIndex = leafIndex === undefined ? BigInt(0) : leafIndex;
Expand All @@ -64,6 +70,7 @@ export class Nullifiers {
* @param nullifier - the nullifier to stage
*/
public async append(storageAddress: Fr, nullifier: Fr) {
this.log(`Staging nullifier ${nullifier} at contract ${storageAddress}`);
const [exists, ,] = await this.checkExists(storageAddress, nullifier);
if (exists) {
throw new NullifierCollisionError(
Expand Down
5 changes: 5 additions & 0 deletions yarn-project/simulator/src/avm/opcodes/storage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Fr } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';

import type { AvmContext } from '../avm_context.js';
import { Field } from '../avm_memory_types.js';
Expand All @@ -8,6 +9,8 @@ import { Addressing } from './addressing_mode.js';
import { Instruction } from './instruction.js';

abstract class BaseStorageInstruction extends Instruction {
static readonly log = createDebugLogger('aztec:avm_simulator:storage');

// Informs (de)serialization. See Instruction.deserialize.
public static readonly wireFormat: OperandType[] = [
OperandType.UINT8,
Expand Down Expand Up @@ -47,6 +50,7 @@ export class SStore extends BaseStorageInstruction {

const slot = context.machineState.memory.get(slotOffset).toFr();
const data = context.machineState.memory.getSlice(srcOffset, this.size).map(field => field.toFr());
BaseStorageInstruction.log(`Writing ${data} to slot ${slot}`);

for (const [index, value] of Object.entries(data)) {
const adjustedSlot = slot.add(new Fr(BigInt(index)));
Expand Down Expand Up @@ -82,6 +86,7 @@ export class SLoad extends BaseStorageInstruction {

context.machineState.memory.set(bOffset + i, new Field(data));
}
BaseStorageInstruction.log(`Read ${context.machineState.memory.getSlice(bOffset, size)} from slot ${slot}.`);

context.machineState.incrementPc();
}
Expand Down

0 comments on commit 41eeb0f

Please sign in to comment.