Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion noir-projects/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ members = [
"contracts/account/ecdsa_r_account_contract",
"contracts/account/schnorr_account_contract",
"contracts/account/schnorr_hardcoded_account_contract",
"contracts/account/simulated_account_contract",
"contracts/account/simulated_schnorr_account_contract",
"contracts/account/simulated_ecdsa_account_contract",
"contracts/app/amm_contract",
"contracts/app/app_subscription_contract",
"contracts/app/auth_contract",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "simulated_account_contract"
name = "simulated_ecdsa_account_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use aztec::macros::aztec;

// Stub account contract for ECDSA accounts (both secp256k1 and secp256r1) used during simulation.
// Matches the constructor signature of EcdsaKAccount / EcdsaRAccount so that deployment
// simulations using this stub as an override do not fail on selector lookup.
// See simulated_account_contract for the base stub without a constructor.
#[aztec]
pub contract SimulatedEcdsaAccount {
use aztec::{
authwit::{account::AccountActions, auth::IS_VALID_SELECTOR, entrypoint::app::AppPayload},
context::PrivateContext,
macros::functions::{allow_phase_change, external, view},
messages::encoding::MESSAGE_CIPHERTEXT_LEN,
oracle::{notes::set_sender_for_tags, random::random},
};

// Stub constructor matching the EcdsaKAccount / EcdsaRAccount constructor signature.
// Does NOT use #[initializer] so that the macro does not inject
// assert_initialization_matches_address_preimage_private, which would fail during kernelless
// simulation because the stub instance has a different initialization hash than the real account.
// Emits the same shape of side effects as the real constructor (one nullifier for
// SinglePrivateImmutable initialization, one note hash for the key note, and one private
// log tied to that note hash) so that gas estimation produces accurate results.
#[external("private")]
fn constructor(_signing_pub_key_x: [u8; 32], _signing_pub_key_y: [u8; 32]) {
// Safety: Random seeds are only used to produce dummy side effects that match the shape of
// the real EcdsaKAccount / EcdsaRAccount constructor. The values are never constrained or
// used for any security purpose.
let seed = unsafe { random() };

// Emit the initialization nullifier for the signing_public_key SinglePrivateImmutable.
self.context.push_nullifier(seed);

// Emit the note hash for the signing key note.
self.context.push_note_hash(seed + 1);

// Emit a private log tied to the note hash, matching the length of a real note delivery
// log (MESSAGE_CIPHERTEXT_LEN fields). The signing key note is a SinglePrivateImmutable
// and is therefore never nullified, so in practice the log will never be squashed. We
// pass the note hash counter anyway for correctness.
let dummy_log: [Field; MESSAGE_CIPHERTEXT_LEN] = [seed + 2; MESSAGE_CIPHERTEXT_LEN];
self.context.emit_raw_note_log_unsafe(
seed + 3,
dummy_log,
MESSAGE_CIPHERTEXT_LEN,
self.context.side_effect_counter,
);
}

// @dev: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts
#[external("private")]
#[allow_phase_change]
fn entrypoint(app_payload: AppPayload, fee_payment_method: u8, cancellable: bool) {
// Safety: The sender for tags is only used to compute unconstrained shared secrets for
// emitting logs. It is not used in any constrained logic, so it is safe to set here.
unsafe { set_sender_for_tags(self.address) };

let actions = AccountActions::init(self.context, is_valid_impl);
actions.entrypoint(app_payload, fee_payment_method, cancellable);
}

#[external("private")]
#[view]
fn verify_private_authwit(inner_hash: Field) -> Field {
IS_VALID_SELECTOR
}

#[contract_library_method]
fn is_valid_impl(_context: &mut PrivateContext, _outer_hash: Field) -> bool {
true
}

#[external("utility")]
unconstrained fn sync_state() {
assert(
false,
"BUG ALERT: sync_state on a simulated account contract should never be triggered.",
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "simulated_schnorr_account_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"

[dependencies]
aztec = { path = "../../../../aztec-nr/aztec" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use aztec::macros::aztec;

// Stub account contract for Schnorr accounts used during simulation.
// Matches the constructor signature of SchnorrAccount so that deployment
// simulations using this stub as an override do not fail on selector lookup.
// See simulated_account_contract for the base stub without a constructor.
#[aztec]
pub contract SimulatedSchnorrAccount {
use aztec::{
authwit::{account::AccountActions, auth::IS_VALID_SELECTOR, entrypoint::app::AppPayload},
context::PrivateContext,
macros::functions::{allow_phase_change, external, view},
messages::encoding::MESSAGE_CIPHERTEXT_LEN,
oracle::{notes::set_sender_for_tags, random::random},
};

// Stub constructor matching the SchnorrAccount constructor signature.
// Does NOT use #[initializer] so that the macro does not inject
// assert_initialization_matches_address_preimage_private, which would fail during kernelless
// simulation because the stub instance has a different initialization hash than the real account.
// Emits the same shape of side effects as the real constructor (one nullifier for
// SinglePrivateImmutable initialization, one note hash for the key note, and one private
// log tied to that note hash) so that gas estimation produces accurate results.
#[external("private")]
fn constructor(_signing_pub_key_x: Field, _signing_pub_key_y: Field) {
// Safety: Random seeds are only used to produce dummy side effects that match the shape of
// the real SchnorrAccount constructor. The values are never constrained or used for any
// security purpose.
let seed = unsafe { random() };

// Emit the initialization nullifier for the signing_public_key SinglePrivateImmutable.
self.context.push_nullifier(seed);

// Emit the note hash for the signing key note.
self.context.push_note_hash(seed + 1);

// Emit a private log tied to the note hash, matching the length of a real note delivery
// log (MESSAGE_CIPHERTEXT_LEN fields). The signing key note is a SinglePrivateImmutable
// and is therefore never nullified, so in practice the log will never be squashed. We
// pass the note hash counter anyway for correctness.
let dummy_log: [Field; MESSAGE_CIPHERTEXT_LEN] = [seed + 2; MESSAGE_CIPHERTEXT_LEN];
self.context.emit_raw_note_log_unsafe(
seed + 3,
dummy_log,
MESSAGE_CIPHERTEXT_LEN,
self.context.side_effect_counter,
);
}

// @dev: If you globally change the entrypoint signature don't forget to update account_entrypoint.ts
#[external("private")]
#[allow_phase_change]
fn entrypoint(app_payload: AppPayload, fee_payment_method: u8, cancellable: bool) {
// Safety: The sender for tags is only used to compute unconstrained shared secrets for
// emitting logs. It is not used in any constrained logic, so it is safe to set here.
unsafe { set_sender_for_tags(self.address) };

let actions = AccountActions::init(self.context, is_valid_impl);
actions.entrypoint(app_payload, fee_payment_method, cancellable);
}

#[external("private")]
#[view]
fn verify_private_authwit(inner_hash: Field) -> Field {
IS_VALID_SELECTOR
}

#[contract_library_method]
fn is_valid_impl(_context: &mut PrivateContext, _outer_hash: Field) -> bool {
true
}

#[external("utility")]
unconstrained fn sync_state() {
assert(
false,
"BUG ALERT: sync_state on a simulated account contract should never be triggered.",
);
}
}
6 changes: 4 additions & 2 deletions yarn-project/accounts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
"./ecdsa/lazy": "./dest/ecdsa/lazy.js",
"./schnorr": "./dest/schnorr/index.js",
"./schnorr/lazy": "./dest/schnorr/lazy.js",
"./stub": "./dest/stub/index.js",
"./stub/lazy": "./dest/stub/lazy.js",
"./stub/schnorr": "./dest/stub/schnorr/index.js",
"./stub/schnorr/lazy": "./dest/stub/schnorr/lazy.js",
"./stub/ecdsa": "./dest/stub/ecdsa/index.js",
"./stub/ecdsa/lazy": "./dest/stub/ecdsa/lazy.js",
"./testing": "./dest/testing/index.js",
"./testing/lazy": "./dest/testing/lazy.js",
"./copy-cat": "./dest/copy_cat/index.js",
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/accounts/scripts/copy-contracts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -euo pipefail
mkdir -p ./artifacts

contracts=(schnorr_account_contract-SchnorrAccount ecdsa_k_account_contract-EcdsaKAccount ecdsa_r_account_contract-EcdsaRAccount simulated_account_contract-SimulatedAccount )
contracts=(schnorr_account_contract-SchnorrAccount ecdsa_k_account_contract-EcdsaKAccount ecdsa_r_account_contract-EcdsaRAccount simulated_schnorr_account_contract-SimulatedSchnorrAccount simulated_ecdsa_account_contract-SimulatedEcdsaAccount )

decl=$(cat <<EOF
import { type NoirCompiledContract } from '@aztec/stdlib/noir';
Expand Down
28 changes: 28 additions & 0 deletions yarn-project/accounts/src/stub/ecdsa/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { BaseAccount } from '@aztec/aztec.js/account';
import type { CompleteAddress } from '@aztec/aztec.js/addresses';
import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account';
import { loadContractArtifact } from '@aztec/stdlib/abi';
import type { NoirCompiledContract } from '@aztec/stdlib/noir';

import SimulatedEcdsaAccountJson from '../../../artifacts/SimulatedEcdsaAccount.json' with { type: 'json' };
import { StubBaseAccountContract } from '../account_contract.js';

export const StubEcdsaAccountContractArtifact = loadContractArtifact(SimulatedEcdsaAccountJson as NoirCompiledContract);

/** Stub account contract for ECDSA accounts (secp256k1 and secp256r1). Eagerly loads the contract artifact. */
export class StubEcdsaAccountContract extends StubBaseAccountContract {
override getContractArtifact() {
return Promise.resolve(StubEcdsaAccountContractArtifact);
}
}

/** Creates an ECDSA stub account that impersonates the one with the provided address. */
export function createStubEcdsaAccount(originalAddress: CompleteAddress) {
const accountContract = new StubEcdsaAccountContract();
const authWitnessProvider = accountContract.getAuthWitnessProvider(originalAddress);
return new BaseAccount(
new DefaultAccountEntrypoint(originalAddress.address, authWitnessProvider),
authWitnessProvider,
originalAddress,
);
}
34 changes: 34 additions & 0 deletions yarn-project/accounts/src/stub/ecdsa/lazy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { BaseAccount } from '@aztec/aztec.js/account';
import type { CompleteAddress } from '@aztec/aztec.js/addresses';
import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account';
import { loadContractArtifact } from '@aztec/stdlib/abi';

import { StubBaseAccountContract } from '../account_contract.js';

/**
* Lazily loads the ECDSA stub contract artifact (browser-compatible).
*/
export async function getStubEcdsaAccountContractArtifact() {
// Cannot assert this import as it's incompatible with bundlers like vite
// https://github.com/vitejs/vite/issues/19095#issuecomment-2566074352
const { default: json } = await import('../../../artifacts/SimulatedEcdsaAccount.json');
return loadContractArtifact(json);
}

/** Stub account contract for ECDSA accounts (secp256k1 and secp256r1). Lazily loads the contract artifact. */
export class StubEcdsaAccountContract extends StubBaseAccountContract {
override getContractArtifact() {
return getStubEcdsaAccountContractArtifact();
}
}

/** Creates an ECDSA stub account that impersonates the one with the provided address. */
export function createStubEcdsaAccount(originalAddress: CompleteAddress) {
const accountContract = new StubEcdsaAccountContract();
const authWitnessProvider = accountContract.getAuthWitnessProvider(originalAddress);
return new BaseAccount(
new DefaultAccountEntrypoint(originalAddress.address, authWitnessProvider),
authWitnessProvider,
originalAddress,
);
}
40 changes: 0 additions & 40 deletions yarn-project/accounts/src/stub/index.ts

This file was deleted.

Loading
Loading