Skip to content

Commit

Permalink
feat(noir): use #[aztec(private)] and #[aztec(public) attributes (#…
Browse files Browse the repository at this point in the history
…1735)

## Overview

Now that noir-lang/noir#2403 has been merged
into noir and released under the `aztec` tag. This PR now builds!

This cleans up the syntax for noir programs, making them less verbose
and easier to get started with.
For example what originally was:
```rust
    fn mint(
        inputs: PrivateContextInputs,
        amount: Field, 
        owner: Field
    ) -> distinct pub abi::PrivateCircuitPublicInputs {
        let storage = Storage::init();
        let mut context = PrivateContext::new(inputs, abi::hash_args([amount, owner]));

        // Insert new note to a set of user notes and emit the newly created encrypted note preimage via oracle call.
        let owner_balance = storage.balances.at(owner);
        send_note(&mut context, owner_balance, amount, owner);
        emit_unencrypted_log(&mut context, "Coins minted");

        // Return private circuit public inputs. All private functions need to return this as it is part of the input of the private kernel..
        context.finish()
    }
```
can instead be written as:
```rust
   #[aztec(private)]
    fn mint(
        amount: Field, 
        owner: Field
    )  {
        let storage = Storage::init();

        // Insert new note to a set of user notes and emit the newly created encrypted note preimage via oracle call.
        let owner_balance = storage.balances.at(owner);
        send_note(&mut context, owner_balance, amount, owner);
        emit_unencrypted_log(&mut context, "Coins minted");
    }
```
  • Loading branch information
Maddiaa0 authored Aug 29, 2023
1 parent e681a49 commit 89756fa
Show file tree
Hide file tree
Showing 27 changed files with 313 additions and 929 deletions.
6 changes: 3 additions & 3 deletions yarn-project/aztec.js/src/abis/ecdsa_account_contract.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions yarn-project/aztec.js/src/abis/schnorr_account_contract.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion yarn-project/noir-contracts/scripts/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ if [ -f "$error_file" ]; then
rm "$error_file"
echo "Error occurred in one or more child processes. Exiting..."
exit 1
fi
fi
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod storage;
// A contract used along with `Parent` contract to test nested calls.
contract Child {
use dep::aztec::abi;
use dep::aztec::abi::Hasher;
use dep::aztec::abi::PrivateContextInputs;
use dep::aztec::abi::PublicContextInputs;
use dep::aztec::context::{
Expand All @@ -12,86 +13,61 @@ contract Child {
use crate::storage::Storage;
use dep::aztec::oracle::logs::emit_unencrypted_log;

fn constructor(
inputs: PrivateContextInputs,
) -> distinct pub abi::PrivateCircuitPublicInputs {
// Return private circuit public inputs. All private functions need to return this as it is part of the input of the private kernel.
PrivateContext::new(inputs, 0).finish()
}
#[aztec(private)]
fn constructor() {}

// Returns a sum of the input and the chain id and version of the contract in private circuit public input's return_values.
#[aztec(private)]
fn value(
inputs: PrivateContextInputs,
input: Field,
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, abi::hash_args([input]));

) {
context.return_values.push(input + context.chain_id() + context.version());

// Return private circuit public inputs. All private functions need to return this as it is part of the input of the private kernel.
context.finish()
}

// Returns base_value + 42.
open fn pubGetValue(inputs: PublicContextInputs, base_value: Field) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([base_value]));

#[aztec(public)]
open fn pubGetValue(base_value: Field) {
let returnValue = base_value + context.chain_id() + context.version() + context.block_number() + context.timestamp();

context.return_values.push(returnValue);
context.finish()
}

// Sets `current_value` to `new_value`
open fn pubSetValue(inputs: PublicContextInputs, new_value: Field) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([new_value]));

#[aztec(public)]
open fn pubSetValue(new_value: Field) {
let storage = Storage::init();
storage.current_value.write(new_value);
let _hash = emit_unencrypted_log(new_value);
context.return_values.push(new_value);
context.finish()
}

// Increments `current_value` by `new_value`
open fn pubIncValue(inputs: PublicContextInputs, new_value: Field) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([new_value]));

#[aztec(public)]
open fn pubIncValue(new_value: Field) {
let storage = Storage::init();
let old_value = storage.current_value.read();
storage.current_value.write(old_value + new_value);
let _hash = emit_unencrypted_log(new_value);
context.return_values.push(new_value);
context.finish()
}

open fn setValueTwiceWithNestedFirst(
inputs: PublicContextInputs,
) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([]));

#[aztec(public)]
open fn setValueTwiceWithNestedFirst() {
let pubSetValueSelector = 0x5b0f91b0;
let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]);

let storage = Storage::init();
storage.current_value.write(20);
let _hash = emit_unencrypted_log(20);

context.finish()
}

open fn setValueTwiceWithNestedLast(
inputs: PublicContextInputs,
) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([]));

#[aztec(public)]
open fn setValueTwiceWithNestedLast() {
let storage = Storage::init();
storage.current_value.write(20);
let _hash = emit_unencrypted_log(20);

let pubSetValueSelector = 0x5b0f91b0;
let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]);

context.finish()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
mod storage;

contract EasyPrivateToken {
use dep::aztec::abi::Hasher;
use dep::value_note::{
balance_utils,
value_note::{
Expand All @@ -25,62 +26,41 @@ contract EasyPrivateToken {
/**
* Initialise the contract's initial state variables.
*/
#[aztec(private)]
fn constructor(
/*********************************/
inputs: PrivateContextInputs,
/*********************************/
initial_supply: u120,
owner: Field,
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, abi::hash_args([initial_supply as Field, owner]));
) {
let storage = Storage::init();
let balances = storage.balances;

balances.at(owner).add(&mut context, initial_supply, owner);

// Return private circuit public inputs. All private functions need to return this as it is part of the input of the private kernel.
context.finish()
}

// Mints `amount` of tokens to `owner`.
#[aztec(private)]
fn mint(
//*********************************/
// Should eventually be hidden:
inputs: PrivateContextInputs,
//*********************************/
amount: u120,
owner: Field,
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, abi::hash_args([amount as Field, owner]));
) {
let storage = Storage::init();
let balances = storage.balances;

balances.at(owner).add(&mut context, amount, owner);

// Return private circuit public inputs. All private functions need to return this as it is part of the input of the private kernel..
context.finish()
}

// Transfers `amount` of tokens from `sender` to a `recipient`.
#[aztec(private)]
fn transfer(
//*********************************/
// Should eventually be hidden:
inputs: PrivateContextInputs,
//*********************************/
amount: u120,
sender: Field,
recipient: Field,
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, abi::hash_args([amount as Field, sender, recipient]));
) {
let storage = Storage::init();
let balances = storage.balances;

balances.at(sender).sub(&mut context, amount, sender);

balances.at(recipient).add(&mut context, amount, recipient);

// Return private circuit public inputs. All private functions need to return this as it is part of the input of the private kernel..
context.finish()
}

// Helper function to get the balance of a user ("unconstrained" is a Noir alternative of Solidity's "view" function).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ contract EcdsaAccount {
use dep::aztec::abi;
use dep::aztec::abi::PrivateContextInputs;
use dep::aztec::abi::CallContext;
use dep::aztec::abi::Hasher;
use dep::aztec::context::PrivateContext;
use dep::aztec::log::emit_encrypted_log;
use dep::aztec::oracle::get_public_key::get_public_key;
Expand All @@ -29,19 +30,11 @@ contract EcdsaAccount {
use crate::ecdsa_public_key_note::ECDSA_PUBLIC_KEY_NOTE_LEN;

// All calls made by this account will be routed through this entrypoint
#[aztec(private)]
fn entrypoint(
inputs: pub PrivateContextInputs,
payload: pub EntrypointPayload, // contains a set of arguments, selectors, targets and a nonce
signature: pub [u8;64],
) -> distinct pub abi::PrivateCircuitPublicInputs {

// Initialise context
// ENTRYPOINT_PAYLOAD_SIZE(13) + 64
let mut args: BoundedVec<Field, 77> = BoundedVec::new(0);
args.push_array(payload.serialize());
for byte in signature { args.push(byte as Field); }
let mut context = PrivateContext::new(inputs, abi::hash_args(args.storage));

) {
// Load public key from storage
let storage = Storage::init();
let public_key = storage.public_key.get_note(&mut context);
Expand All @@ -61,23 +54,16 @@ contract EcdsaAccount {
assert(verification == true);

payload.execute_calls(&mut context);

context.finish()
}

// Creates a new account out of an ECDSA public key to use for signature verification
#[aztec(private)]
fn constructor(
inputs: pub PrivateContextInputs,
signing_pub_key_x: pub [u8;32],
signing_pub_key_y: pub [u8;32],
) -> distinct pub abi::PrivateCircuitPublicInputs {
) {
let storage = Storage::init();

let mut args: BoundedVec<Field, 64> = BoundedVec::new(0);
for byte in signing_pub_key_x { args.push(byte as Field); }
for byte in signing_pub_key_y { args.push(byte as Field); }
let mut context = PrivateContext::new(inputs, abi::hash_args(args.storage));

let this = context.this_address();
let mut pub_key_note = EcdsaPublicKeyNote::new(signing_pub_key_x, signing_pub_key_y, this);
storage.public_key.initialise(&mut context, &mut pub_key_note);
Expand All @@ -89,8 +75,6 @@ contract EcdsaAccount {
get_public_key(this),
pub_key_note.serialise(),
);

context.finish()
}

// Computes note hash and nullifier.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod private_token_contract_interface;
contract Escrow {
use dep::std;
use dep::aztec::abi;
use dep::aztec::abi::Hasher;
use dep::aztec::abi::PrivateContextInputs;
use dep::aztec::abi::CallContext;
use dep::aztec::private_call_stack_item::PrivateCallStackItem;
Expand All @@ -30,11 +31,10 @@ contract Escrow {
use crate::private_token_contract_interface::PrivateTokenContractInterface;

// Creates a new instance
#[aztec(private)]
fn constructor(
inputs: pub PrivateContextInputs,
owner: pub Field
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, abi::hash_args([owner]));
) {
let this = context.this_address();

let storage = Storage::init();
Expand All @@ -47,18 +47,15 @@ contract Escrow {
get_public_key(this),
note.serialise(),
);

context.finish()
}

// Withdraws balance. Requires that msg.sender is registered as an owner.
#[aztec(private)]
fn withdraw(
inputs: pub PrivateContextInputs,
token: pub Field,
amount: pub Field,
recipient: pub Field,
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, abi::hash_args([token, amount, recipient]));
) {
let this = context.this_address();
let sender = context.msg_sender();
let storage = Storage::init();
Expand All @@ -71,10 +68,7 @@ contract Escrow {
assert(note.address == sender);
assert(note.owner == this);

// TODO: Can we dynamically get this selector?
let _callStackItem = PrivateTokenContractInterface::at(token).transfer(&mut context, amount, recipient);

context.finish()
}

unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, preimage: [Field; ADDRESS_NOTE_LEN]) -> [Field; 4] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod storage;

contract ExamplePublicStateIncrement {
use dep::aztec::abi;
use dep::aztec::abi::Hasher;
use dep::aztec::abi::PrivateContextInputs;
use dep::aztec::abi::PublicContextInputs;
use dep::aztec::context::{
Expand All @@ -18,41 +19,28 @@ contract ExamplePublicStateIncrement {
};

// call initialise_a();
#[aztec(private)]
fn constructor(
inputs: PrivateContextInputs,
) -> distinct pub abi::PrivateCircuitPublicInputs {
let mut context = PrivateContext::new(inputs, 0);

) {
let initialise_a_function_selector: Field = 1234;
let _return_values = context.call_public_function_no_args(context.this_address(), initialise_a_function_selector);

context.finish()
}

// a = 100;
open internal fn initialise_a(
inputs: PublicContextInputs,
) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([]));

#[aztec(public)]
open internal fn initialise_a() {
let storage = Storage::init();
storage.a.write(100);

context.finish()
}

// a += b;
#[aztec(public)]
open fn increment_a(
inputs: PublicContextInputs,
b: Field,
) -> pub abi::PublicCircuitPublicInputs {
let mut context = PublicContext::new(inputs, abi::hash_args([b]));

) {
let storage = Storage::init();
let mut a = storage.a.read();
a += b;
storage.a.write(a);

context.finish()
}
}
Loading

0 comments on commit 89756fa

Please sign in to comment.