Skip to content
Open
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
2 changes: 1 addition & 1 deletion boxes/boxes/react/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class PrivateEnv {
);
}

await wallet.createSchnorrAccount(accountData.secret, accountData.salt, accountData.signingKey);
await wallet.createSchnorrInitializerlessAccount(accountData.secret, accountData.salt, accountData.signingKey);
this.wallet = wallet;
this.defaultAccountAddress = accountData.address;
}
Expand Down
12 changes: 4 additions & 8 deletions boxes/boxes/vite/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getInitialTestAccountsData } from "@aztec/accounts/testing";
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
import { AztecAddress } from '@aztec/aztec.js/addresses';
import { Wallet } from '@aztec/aztec.js/wallet';
import { EmbeddedWallet } from '@aztec/wallets/embedded';
Expand All @@ -10,22 +10,18 @@ export class PrivateEnv {
constructor() {}

async init() {
const nodeURL = process.env.AZTEC_NODE_URL ?? "http://localhost:8080";
const nodeURL = process.env.AZTEC_NODE_URL ?? 'http://localhost:8080';

const wallet = await EmbeddedWallet.create(nodeURL);

const [accountData] = await getInitialTestAccountsData();
if (!accountData) {
console.error(
"Account not found. Please connect the app to a testing environment with deployed and funded test accounts.",
'Account not found. Please connect the app to a testing environment with deployed and funded test accounts.',
);
}

await wallet.createSchnorrAccount(
accountData.secret,
accountData.salt,
accountData.signingKey,
);
await wallet.createSchnorrInitializerlessAccount(accountData.secret, accountData.salt, accountData.signingKey);
this.wallet = wallet;
this.defaultAccountAddress = accountData.address;
}
Expand Down
7 changes: 5 additions & 2 deletions docs/examples/ts/aave_bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const node = createAztecNodeClient(
await waitForNode(node);
const aztecWallet = await EmbeddedWallet.create(node, { ephemeral: true });
const [accData] = await getInitialTestAccountsData();
const account = await aztecWallet.createSchnorrAccount(
const account = await aztecWallet.createSchnorrInitializerlessAccount(
accData.secret,
accData.salt,
accData.signingKey,
Expand Down Expand Up @@ -279,7 +279,10 @@ console.log("Block proven!\n");

// Compute the membership witness using the message hash and the L2 tx hash.
// The node picks the smallest partial-proof root that covers the tx's checkpoint.
const witness = await node.getL2ToL1MembershipWitness(exitReceipt.txHash, msgLeaf);
const witness = await node.getL2ToL1MembershipWitness(
exitReceipt.txHash,
msgLeaf,
);
const epoch = witness!.epochNumber;
const numCheckpointsInEpoch = witness!.numCheckpointsInEpoch;

Expand Down
2 changes: 1 addition & 1 deletion docs/examples/ts/aztecjs_advanced/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const testAccounts = await getInitialTestAccountsData();
const [aliceAddress, bobAddress] = await Promise.all(
testAccounts.slice(0, 2).map(async (account) => {
return (
await wallet.createSchnorrAccount(
await wallet.createSchnorrInitializerlessAccount(
account.secret,
account.salt,
account.signingKey,
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/ts/aztecjs_authwit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const testAccounts = await getInitialTestAccountsData();
const [aliceAddress, bobAddress] = await Promise.all(
testAccounts.slice(0, 2).map(async (account) => {
return (
await wallet.createSchnorrAccount(
await wallet.createSchnorrInitializerlessAccount(
account.secret,
account.salt,
account.signingKey,
Expand Down
16 changes: 12 additions & 4 deletions docs/examples/ts/aztecjs_connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const testAccounts = await getInitialTestAccountsData();
const [aliceAddress, bobAddress] = await Promise.all(
testAccounts.slice(0, 2).map(async (account) => {
return (
await wallet.createSchnorrAccount(
await wallet.createSchnorrInitializerlessAccount(
account.secret,
account.salt,
account.signingKey,
Expand Down Expand Up @@ -158,7 +158,10 @@ import { FeeJuicePaymentMethodWithClaim } from "@aztec/aztec.js/fee";

// claim is from the bridgeTokensPublic step above
// Create a payment method that claims the bridged Fee Juice and uses it to pay
const bridgePaymentMethod = new FeeJuicePaymentMethodWithClaim(feeJuiceAccount.address, claim);
const bridgePaymentMethod = new FeeJuicePaymentMethodWithClaim(
feeJuiceAccount.address,
claim,
);

// Use it to pay for any transaction; here we deploy the account in one step
const deployMethodBridged = await feeJuiceAccount.getDeployMethod();
Expand All @@ -175,5 +178,10 @@ const metadata = await wallet.getContractMetadata(newAccount.address);
console.log("Account deployed:", metadata.initializationStatus);
// docs:end:verify_account_deployment

const feeJuiceMetadata = await wallet.getContractMetadata(feeJuiceAccount.address);
console.log("Fee Juice account deployed:", feeJuiceMetadata.initializationStatus);
const feeJuiceMetadata = await wallet.getContractMetadata(
feeJuiceAccount.address,
);
console.log(
"Fee Juice account deployed:",
feeJuiceMetadata.initializationStatus,
);
4 changes: 2 additions & 2 deletions docs/examples/ts/aztecjs_getting_started/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const nodeUrl = process.env.AZTEC_NODE_URL ?? "http://localhost:8080";
const wallet = await EmbeddedWallet.create(nodeUrl, { ephemeral: true });

const [alice, bob] = await getInitialTestAccountsData();
await wallet.createSchnorrAccount(alice.secret, alice.salt);
await wallet.createSchnorrAccount(bob.secret, bob.salt);
await wallet.createSchnorrInitializerlessAccount(alice.secret, alice.salt);
await wallet.createSchnorrInitializerlessAccount(bob.secret, bob.salt);
// docs:end:setup

// docs:start:deploy
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/ts/aztecjs_kernelless_simulation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const testAccounts = await getInitialTestAccountsData();
const [aliceAddress, bobAddress] = await Promise.all(
testAccounts.slice(0, 2).map(async (account) => {
return (
await wallet.createSchnorrAccount(
await wallet.createSchnorrInitializerlessAccount(
account.secret,
account.salt,
account.signingKey,
Expand Down
16 changes: 13 additions & 3 deletions docs/examples/ts/aztecjs_testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ let token: TokenContract;

// beforeAll equivalent - setup
async function setup() {
const node = createAztecNodeClient(process.env.AZTEC_NODE_URL ?? "http://localhost:8080");
const node = createAztecNodeClient(
process.env.AZTEC_NODE_URL ?? "http://localhost:8080",
);
await waitForNode(node);
wallet = await EmbeddedWallet.create(node, { ephemeral: true });
const testAccounts = await getInitialTestAccountsData();
[aliceAddress, bobAddress] = await Promise.all(
testAccounts.slice(0, 2).map(async (account) => {
return (await wallet.createSchnorrAccount(account.secret, account.salt, account.signingKey)).address;
return (
await wallet.createSchnorrInitializerlessAccount(
account.secret,
account.salt,
account.signingKey,
)
).address;
}),
);

Expand Down Expand Up @@ -61,7 +69,9 @@ async function testTransferTokens() {
.send({ from: aliceAddress });

// Transfer to bob using public transfer
await token.methods.transfer_in_public(aliceAddress, bobAddress, 100n, 0n).send({ from: aliceAddress });
await token.methods
.transfer_in_public(aliceAddress, bobAddress, 100n, 0n)
.send({ from: aliceAddress });

const { result: aliceBalance } = await token.methods
.balance_of_public(aliceAddress)
Expand Down
13 changes: 7 additions & 6 deletions docs/examples/ts/bob_token_contract/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,19 @@ async function main() {

const [giggleWalletData, aliceWalletData, bobClinicWalletData] =
await getInitialTestAccountsData();
const giggleAccountManager = await wallet.createSchnorrAccount(
const giggleAccountManager = await wallet.createSchnorrInitializerlessAccount(
giggleWalletData.secret,
giggleWalletData.salt,
);
const aliceAccountManager = await wallet.createSchnorrAccount(
const aliceAccountManager = await wallet.createSchnorrInitializerlessAccount(
aliceWalletData.secret,
aliceWalletData.salt,
);
const bobClinicAccountManager = await wallet.createSchnorrAccount(
bobClinicWalletData.secret,
bobClinicWalletData.salt,
);
const bobClinicAccountManager =
await wallet.createSchnorrInitializerlessAccount(
bobClinicWalletData.secret,
bobClinicWalletData.salt,
);

const giggleAddress = giggleAccountManager.address;
const aliceAddress = aliceAccountManager.address;
Expand Down
12 changes: 9 additions & 3 deletions docs/examples/ts/example_swap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const node = createAztecNodeClient(nodeUrl);
await waitForNode(node);
const wallet = await EmbeddedWallet.create(node, { ephemeral: true });
const [accData] = await getInitialTestAccountsData();
const account = await wallet.createSchnorrAccount(
const account = await wallet.createSchnorrInitializerlessAccount(
accData.secret,
accData.salt,
accData.signingKey,
Expand Down Expand Up @@ -445,7 +445,10 @@ const exitMsgLeaf = computeL2ToL1MessageHash({

// docs:start:consume_l1_messages_witnesses
// The node picks the smallest partial-proof root that covers each tx's checkpoint.
const exitWitness = await node.getL2ToL1MembershipWitness(swapReceipt.txHash, exitMsgLeaf);
const exitWitness = await node.getL2ToL1MembershipWitness(
swapReceipt.txHash,
exitMsgLeaf,
);
const exitSiblingPath = exitWitness!.siblingPath
.toBufferArray()
.map((buf: Buffer) => `0x${buf.toString("hex")}` as `0x${string}`);
Expand Down Expand Up @@ -495,7 +498,10 @@ const swapMsgLeaf = computeL2ToL1MessageHash({
chainId: new Fr(foundry.id),
});

const swapWitness = await node.getL2ToL1MembershipWitness(swapReceipt.txHash, swapMsgLeaf);
const swapWitness = await node.getL2ToL1MembershipWitness(
swapReceipt.txHash,
swapMsgLeaf,
);
const swapSiblingPath = swapWitness!.siblingPath
.toBufferArray()
.map((buf: Buffer) => `0x${buf.toString("hex")}` as `0x${string}`);
Expand Down
7 changes: 5 additions & 2 deletions docs/examples/ts/token_bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ console.log("Setting up L2...\n");
const node = createAztecNodeClient("http://localhost:8080");
const aztecWallet = await EmbeddedWallet.create(node);
const [accData] = await getInitialTestAccountsData();
const account = await aztecWallet.createSchnorrAccount(
const account = await aztecWallet.createSchnorrInitializerlessAccount(
accData.secret,
accData.salt,
);
Expand Down Expand Up @@ -304,7 +304,10 @@ console.log("Block proven!\n");

// Compute the membership witness using the message hash and the L2 tx hash.
// The node picks the smallest partial-proof root that covers the tx's checkpoint.
const witness = await node.getL2ToL1MembershipWitness(exitReceipt.txHash, msgLeaf);
const witness = await node.getL2ToL1MembershipWitness(
exitReceipt.txHash,
msgLeaf,
);
const epoch = witness!.epochNumber;
const numCheckpointsInEpoch = witness!.numCheckpointsInEpoch;
console.log(` Epoch for block ${exitReceipt.blockNumber}: ${epoch}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,45 @@ unconstrained fn no_sync(
#[aztec(AztecConfig::new().custom_sync_state(crate::no_sync))]
pub contract SchnorrInitializerlessAccount {
use aztec::{
authwit::{account::AccountActions, entrypoint::app::AppPayload},
authwit::{
account::AccountActions,
auth::{compute_authwit_message_hash, compute_authwit_nullifier},
entrypoint::app::AppPayload,
},
context::PrivateContext,
macros::functions::{allow_phase_change, external, view},
oracle::{auth_witness::get_auth_witness, capsules::{load, store}, get_contract_instance::get_contract_instance},
protocol::{hash::{poseidon2_hash, poseidon2_hash_bytes}, traits::{Deserialize, Serialize}},
oracle::{
auth_witness::get_auth_witness,
capsules::{load, store},
get_contract_instance::get_contract_instance,
get_nullifier_membership_witness::get_low_nullifier_membership_witness,
},
protocol::{
address::AztecAddress,
hash::{compute_siloed_nullifier, poseidon2_hash, poseidon2_hash_bytes},
traits::{Deserialize, Serialize},
},
};

#[derive(Eq, Serialize, Deserialize)]
pub struct PublicKey {
pub x: Field,
pub y: Field,
}
use std::embedded_curve_ops::EmbeddedCurvePoint;

global PUB_KEY_SLOT: Field = comptime { poseidon2_hash_bytes("INITIALIZERLESS_ACCOUNT_PUB_KEY".as_bytes()) };

#[external("utility")]
unconstrained fn constructor(public_key: PublicKey) {
let serialized_pub_key = public_key.serialize();
let expected = poseidon2_hash(public_key.serialize());
unconstrained fn constructor(signing_pub_key_x: Field, signing_pub_key_y: Field) {
let expected = poseidon2_hash([signing_pub_key_x, signing_pub_key_y]);
let instance = get_contract_instance(self.address);
assert_eq(
expected,
instance.immutables_hash,
"Public key hash does not match the immutables hash, refusing to store",
);

store(self.address, PUB_KEY_SLOT, serialized_pub_key, self.address);
store(
self.address,
PUB_KEY_SLOT,
[signing_pub_key_x, signing_pub_key_y],
self.address,
);
}

#[external("private")]
Expand All @@ -68,7 +80,7 @@ pub contract SchnorrInitializerlessAccount {
fn is_valid_impl(context: &mut PrivateContext, outer_hash: Field) -> bool {
// Safety: The public key inside the capsule is checked to match the immutables_hash of this instance
let public_key = unsafe { load(context.this_address(), PUB_KEY_SLOT, context.this_address()) }
.map(|data| PublicKey::deserialize(data))
.map(|data| EmbeddedCurvePoint::deserialize(data))
.unwrap_or_else(|| panic(
"Public key was not stored in the Private eXecution Environment. Please call `constructor` first",
));
Expand All @@ -86,8 +98,46 @@ pub contract SchnorrInitializerlessAccount {
std::embedded_curve_ops::EmbeddedCurveScalar::new(limbs[2], limbs[3]),
);

schnorr::verify_signature(public_key, signature, outer_hash)
}

/// @notice Helper function to check validity of private authwitnesses
/// @param consumer The address of the consumer of the message
/// @param message_hash The message hash of the message to check the validity
/// @return True if the message_hash can be consumed, false otherwise
#[external("utility")]
unconstrained fn lookup_validity(consumer: AztecAddress, inner_hash: Field) -> bool {
// Safety: The public key inside the capsule is checked to match the immutables_hash of this instance
let public_key = load(self.address, PUB_KEY_SLOT, self.address)
.map(|data| EmbeddedCurvePoint::deserialize(data))
.unwrap_or_else(|| panic(
"Public key was not stored in the Private eXecution Environment. Please call `constructor` first",
));

let message_hash = compute_authwit_message_hash(
consumer,
self.context.chain_id(),
self.context.version(),
inner_hash,
);

let limbs: [Field; 4] = get_auth_witness(message_hash);
let signature = (
std::embedded_curve_ops::EmbeddedCurveScalar::new(limbs[0], limbs[1]),
std::embedded_curve_ops::EmbeddedCurveScalar::new(limbs[2], limbs[3]),
);
let pub_key = std::embedded_curve_ops::EmbeddedCurvePoint { x: public_key.x, y: public_key.y };
let valid_in_private = schnorr::verify_signature(pub_key, signature, message_hash);

// Compute the nullifier and check if it is spent
// This will BLINDLY TRUST the oracle, but the oracle is us, and
// it is not as part of execution of the contract, so we are good.
let nullifier = compute_authwit_nullifier(self.address, inner_hash);
let siloed_nullifier = compute_siloed_nullifier(consumer, nullifier);
let (low_leaf_preimage, _witness) =
get_low_nullifier_membership_witness(self.context.block_header(), siloed_nullifier);
let is_spent = low_leaf_preimage.nullifier == siloed_nullifier;

schnorr::verify_signature(pub_key, signature, outer_hash)
!is_spent & valid_in_private
}
}
9 changes: 9 additions & 0 deletions yarn-project/accounts/src/defaults/account_contract.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Account, type AccountContract, type AuthWitnessProvider, BaseAccount } from '@aztec/aztec.js/account';
import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account';
import type { Fr } from '@aztec/foundation/curves/bn254';
import type { ContractArtifact } from '@aztec/stdlib/abi';
import type { CompleteAddress } from '@aztec/stdlib/contract';

Expand All @@ -22,6 +23,14 @@ export abstract class DefaultAccountContract implements AccountContract {

constructor() {}

/**
* Accounts without immutables (the default) contribute to their address via an on-chain
* initializer instead. Account contracts that commit immutables into their address override this.
*/
getImmutablesHash(): Promise<Fr | undefined> {
return Promise.resolve(undefined);
}

getAccount(completeAddress: CompleteAddress): Account {
const authWitnessProvider = this.getAuthWitnessProvider(completeAddress);
return new BaseAccount(
Expand Down
Loading
Loading